feat: Request external storage permission on recording start if not granted already

This commit is contained in:
Myzel394 2024-01-04 21:39:59 +01:00
parent fc9e6d7721
commit b1fc546f3b
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
2 changed files with 120 additions and 81 deletions

View File

@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.InsertDriveFile
import androidx.compose.material.icons.filled.Mic import androidx.compose.material.icons.filled.Mic
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
@ -29,8 +30,10 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.myzel394.alibi.R import app.myzel394.alibi.R
import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
import app.myzel394.alibi.ui.components.atoms.PermissionRequester import app.myzel394.alibi.ui.components.atoms.PermissionRequester
import app.myzel394.alibi.ui.models.AudioRecorderModel import app.myzel394.alibi.ui.models.AudioRecorderModel
import app.myzel394.alibi.ui.utils.PermissionHelper
@Composable @Composable
fun AudioRecordingStart( fun AudioRecordingStart(
@ -52,38 +55,54 @@ fun AudioRecordingStart(
} }
PermissionRequester( PermissionRequester(
permission = Manifest.permission.RECORD_AUDIO, permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
icon = Icons.Default.Mic, icon = Icons.Default.InsertDriveFile,
onPermissionAvailable = { onPermissionAvailable = {
startRecording = true startRecording = true
} }
) { trigger -> ) { triggerExternalStorage ->
val label = stringResource(R.string.ui_audioRecorder_action_start_label) PermissionRequester(
permission = Manifest.permission.RECORD_AUDIO,
Button( icon = Icons.Default.Mic,
onClick = trigger, onPermissionAvailable = {
modifier = Modifier if (!SUPPORTS_SCOPED_STORAGE && !PermissionHelper.hasGranted(
.semantics { context,
contentDescription = label Manifest.permission.WRITE_EXTERNAL_STORAGE
)
) {
triggerExternalStorage()
} else {
startRecording = true
} }
.size(250.dp) }
.clip(shape = CircleShape), ) { triggerRecordAudio ->
colors = ButtonDefaults.outlinedButtonColors(), val label = stringResource(R.string.ui_audioRecorder_action_start_label)
) {
Column( Button(
horizontalAlignment = Alignment.CenterHorizontally, onClick = triggerRecordAudio,
modifier = Modifier
.semantics {
contentDescription = label
}
.size(250.dp)
.clip(shape = CircleShape),
colors = ButtonDefaults.outlinedButtonColors(),
) { ) {
Icon( Column(
Icons.Default.Mic, horizontalAlignment = Alignment.CenterHorizontally,
contentDescription = null, ) {
modifier = Modifier Icon(
.size(80.dp), Icons.Default.Mic,
) contentDescription = null,
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing)) modifier = Modifier
Text( .size(80.dp),
label, )
style = MaterialTheme.typography.titleSmall, Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing))
) Text(
label,
style = MaterialTheme.typography.titleSmall,
)
}
} }
} }
} }

View File

@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CameraAlt import androidx.compose.material.icons.filled.CameraAlt
import androidx.compose.material.icons.filled.InsertDriveFile
import androidx.compose.material.ripple.rememberRipple import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
@ -44,6 +45,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import app.myzel394.alibi.R import app.myzel394.alibi.R
import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
import app.myzel394.alibi.ui.components.atoms.PermissionRequester import app.myzel394.alibi.ui.components.atoms.PermissionRequester
import app.myzel394.alibi.ui.models.VideoRecorderModel import app.myzel394.alibi.ui.models.VideoRecorderModel
import app.myzel394.alibi.ui.utils.PermissionHelper import app.myzel394.alibi.ui.utils.PermissionHelper
@ -78,65 +80,83 @@ fun VideoRecordingStart(
) )
} }
val hasGrantedStorage = SUPPORTS_SCOPED_STORAGE || PermissionHelper.hasGranted(
context,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
PermissionRequester( PermissionRequester(
permission = Manifest.permission.CAMERA, permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
icon = Icons.Default.CameraAlt, icon = Icons.Default.InsertDriveFile,
onPermissionAvailable = { onPermissionAvailable = {
showSheet = true showSheet = true
}, }
) { trigger -> ) { triggerExternalStorage ->
val label = stringResource(R.string.ui_videoRecorder_action_start_label) PermissionRequester(
permission = Manifest.permission.CAMERA,
icon = Icons.Default.CameraAlt,
onPermissionAvailable = {
showSheet = true
},
) { triggerCamera ->
val label = stringResource(R.string.ui_videoRecorder_action_start_label)
Column( Column(
modifier = Modifier
.size(250.dp)
.clip(CircleShape)
.semantics {
contentDescription = label
}
.combinedClickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
onClick = {
if (PermissionHelper.hasGranted(
context,
Manifest.permission.CAMERA
) && PermissionHelper.hasGranted(
context,
Manifest.permission.RECORD_AUDIO
)
) {
videoRecorder.startRecording(context, appSettings)
} else {
showSheet = true
}
},
onLongClick = {
showSheet = true
},
),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Icon(
Icons.Default.CameraAlt,
contentDescription = null,
modifier = Modifier modifier = Modifier
.size(80.dp), .size(250.dp)
tint = MaterialTheme.colorScheme.primary, .clip(CircleShape)
) .semantics {
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing)) contentDescription = label
Text( }
label, .combinedClickable(
style = MaterialTheme.typography.titleSmall, interactionSource = remember { MutableInteractionSource() },
color = MaterialTheme.colorScheme.primary, indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
) onClick = {
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing)) if (!hasGrantedStorage) {
Text( triggerExternalStorage()
stringResource(R.string.ui_videoRecorder_action_configure_label), return@combinedClickable
style = MaterialTheme.typography.bodySmall, }
color = MaterialTheme.colorScheme.onSurfaceVariant,
) if (PermissionHelper.hasGranted(
context,
Manifest.permission.CAMERA
) && PermissionHelper.hasGranted(
context,
Manifest.permission.RECORD_AUDIO
)
) {
videoRecorder.startRecording(context, appSettings)
} else {
showSheet = true
}
},
onLongClick = {
showSheet = true
},
),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Icon(
Icons.Default.CameraAlt,
contentDescription = null,
modifier = Modifier
.size(80.dp),
tint = MaterialTheme.colorScheme.primary,
)
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing))
Text(
label,
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.primary,
)
Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing))
Text(
stringResource(R.string.ui_videoRecorder_action_configure_label),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
} }
} }
} }