From 1c49ac35b831c0b6f2bf46620d613d0efb5a3f3a Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Tue, 8 Aug 2023 10:11:29 +0200 Subject: [PATCH] feat: Improve permission request --- .../AudioRecorder/molecules/StartRecording.kt | 9 +- .../alibi/ui/components/atoms/MessageBox.kt | 2 +- .../components/atoms/PermissionRequester.kt | 123 +++++++++++++++--- .../alibi/ui/utils/PermissionHelper.kt | 30 ++--- app/src/main/res/values/strings.xml | 3 +- 5 files changed, 121 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt index 106c9d7..c8ee01e 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt @@ -69,13 +69,8 @@ fun StartRecording( ) { Spacer(modifier = Modifier.weight(1f)) PermissionRequester( - permission = arrayOf(Manifest.permission.RECORD_AUDIO), - icon = { - Icon( - Icons.Default.Mic, - contentDescription = null, - ) - }, + permission = Manifest.permission.RECORD_AUDIO, + icon = Icons.Default.Mic, onPermissionAvailable = { RecorderService.startService(context, connection) }, diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/atoms/MessageBox.kt b/app/src/main/java/app/myzel394/alibi/ui/components/atoms/MessageBox.kt index 31db793..cf0f0c9 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/atoms/MessageBox.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/atoms/MessageBox.kt @@ -37,7 +37,7 @@ fun MessageBox( } val onContainerColor = when(type) { MessageType.ERROR -> MaterialTheme.colorScheme.onError - MessageType.INFO -> MaterialTheme.colorScheme.onTertiary + MessageType.INFO -> MaterialTheme.colorScheme.onTertiaryContainer MessageType.SUCCESS -> Color.Green MessageType.WARNING -> Color.Yellow } diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/atoms/PermissionRequester.kt b/app/src/main/java/app/myzel394/alibi/ui/components/atoms/PermissionRequester.kt index 2ad69be..59be983 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/atoms/PermissionRequester.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/atoms/PermissionRequester.kt @@ -1,10 +1,17 @@ package app.myzel394.alibi.ui.components.atoms +import android.app.Activity +import android.content.pm.PackageManager +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Cancel +import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.OpenInNew import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button @@ -12,55 +19,136 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.core.app.ActivityCompat import app.myzel394.alibi.R import app.myzel394.alibi.ui.utils.PermissionHelper import app.myzel394.alibi.ui.utils.openAppSystemSettings @Composable fun PermissionRequester( - permission: Array, - icon: (@Composable () -> Unit)? = null, + permission: String, + icon: ImageVector, onPermissionAvailable: () -> Unit, content: @Composable (trigger: () -> Unit) -> Unit ) { val context = LocalContext.current - var showExplanationDialog by remember { mutableStateOf(false) } + var isGranted by remember { mutableStateOf(PermissionHelper.hasGranted(context, permission)) } + var visibleDialog by remember { mutableStateOf(null) } + val requestPermission = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission(), + onResult = { isPermissionGranted: Boolean -> + isGranted = isPermissionGranted + + if (isGranted) { + onPermissionAvailable() + } else { + if (ActivityCompat.shouldShowRequestPermissionRationale(context as Activity, permission)) { + visibleDialog = VisibleDialog.REQUEST + } else { + visibleDialog = VisibleDialog.PERMANENTLY_DENIED + } + } + } + ) fun callback() { - if (PermissionHelper.hasPermanentlyDenied(context, permission)) { - showExplanationDialog = true - return - } - - if (PermissionHelper.checkPermissions(context, permission)) { + if (isGranted) { onPermissionAvailable() + } else { + requestPermission.launch(permission) } } - if (showExplanationDialog) { + if (visibleDialog == VisibleDialog.REQUEST) { AlertDialog( onDismissRequest = { - showExplanationDialog = false + visibleDialog = null + }, + icon = { + Icon( + icon, + contentDescription = null, + ) }, - icon = icon, title = { Text(stringResource(R.string.ui_permissions_request_title)) }, text = { - Text(stringResource(R.string.ui_permissions_request_message)) + Text(stringResource(R.string.ui_permissions_request)) }, confirmButton = { Button( onClick = { - showExplanationDialog = false + visibleDialog = null + callback() + } + ) { + Icon( + Icons.Default.Check, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) + Text(stringResource(R.string.dialog_close_neutral_label)) + } + }, + dismissButton = { + Button( + onClick = { + visibleDialog = null + }, + colors = ButtonDefaults.textButtonColors(), + ) { + Icon( + Icons.Default.Cancel, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) + Text(stringResource(R.string.dialog_close_cancel_label)) + } + } + ) + } + if (visibleDialog == VisibleDialog.PERMANENTLY_DENIED) { + AlertDialog( + onDismissRequest = { + visibleDialog = null + }, + icon = { + Icon( + icon, + contentDescription = null, + ) + }, + title = { + Text(stringResource(R.string.ui_permissions_request_title)) + }, + text = { + Column { + Text(stringResource(R.string.ui_permissions_request)) + Spacer(modifier = Modifier.height(32.dp)) + MessageBox( + type = MessageType.INFO, + message = stringResource(R.string.ui_permissions_permanentlyDenied_message) + ) + } + }, + confirmButton = { + Button( + onClick = { + visibleDialog = null context.openAppSystemSettings() } ) { @@ -76,7 +164,7 @@ fun PermissionRequester( dismissButton = { Button( onClick = { - showExplanationDialog = false + visibleDialog = null }, colors = ButtonDefaults.textButtonColors(), ) { @@ -92,4 +180,9 @@ fun PermissionRequester( ) } content(::callback) +} + +enum class VisibleDialog { + REQUEST, + PERMANENTLY_DENIED } \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/ui/utils/PermissionHelper.kt b/app/src/main/java/app/myzel394/alibi/ui/utils/PermissionHelper.kt index df2adf6..8d42b6b 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/utils/PermissionHelper.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/utils/PermissionHelper.kt @@ -10,34 +10,20 @@ import androidx.core.app.ActivityCompat // From @Bnyro object PermissionHelper { - fun checkPermissions(context: Context, permissions: Array): Boolean { - permissions.forEach { - if (!hasGranted(context, it)) { - ActivityCompat.requestPermissions( - context as Activity, - arrayOf(it), - 1 - ) - return false - } + fun checkPermission(context: Context, permission: String): Boolean { + if (!hasGranted(context, permission)) { + ActivityCompat.requestPermissions( + context as Activity, + arrayOf(permission), + 1 + ) + return false } return true } fun hasGranted(context: Context, permission: String): Boolean = ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED - - fun hasPermanentlyDenied(context: Context, permission: String): Boolean = - !hasGranted(context, permission) && - !ActivityCompat.shouldShowRequestPermissionRationale(context as Activity, permission) - - fun hasPermanentlyDenied(context: Context, permission: Array): Boolean { - permission.forEach { - if (hasPermanentlyDenied(context, it)) - return true - } - return false - } } fun Context.openAppSystemSettings() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index de209fa..824f89e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,7 +15,8 @@ Shows the current recording status Permission denied - Please grant the permission to continue. You will be redirected to the app settings to grant the permission there. + Please grant the permission to continue + You will be redirected to the app settings to grant the permission there. Start Recording Save Recording from %s