From 261753ad7509dccf1add43a49bcd20fcfe5576a9 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 2 Dec 2023 18:45:25 +0100 Subject: [PATCH] feat: Add AudioRecordingStart and VideoRecordingStart --- .../java/app/myzel394/alibi/ui/Navigation.kt | 6 +- .../atoms/AudioRecordingStart.kt | 90 ++++++++++++++++++ .../atoms/VideoRecordingStart.kt | 92 +++++++++++++++++++ .../AudioRecorder/molecules/StartRecording.kt | 80 +++------------- ...dioRecorderScreen.kt => RecorderScreen.kt} | 8 +- app/src/main/res/values/strings.xml | 3 +- 6 files changed, 207 insertions(+), 72 deletions(-) create mode 100644 app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/AudioRecordingStart.kt create mode 100644 app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/VideoRecordingStart.kt rename app/src/main/java/app/myzel394/alibi/ui/screens/{AudioRecorderScreen.kt => RecorderScreen.kt} (97%) diff --git a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt index 8a94752..beff2e4 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt @@ -23,9 +23,8 @@ import app.myzel394.alibi.ui.enums.Screen import app.myzel394.alibi.ui.models.AudioRecorderModel import app.myzel394.alibi.ui.models.VideoRecorderModel import app.myzel394.alibi.ui.screens.AboutScreen -import app.myzel394.alibi.ui.screens.AudioRecorderScreen +import app.myzel394.alibi.ui.screens.RecorderScreen import app.myzel394.alibi.ui.screens.CustomRecordingNotificationsScreen -import app.myzel394.alibi.ui.screens.POCVideo import app.myzel394.alibi.ui.screens.SettingsScreen import app.myzel394.alibi.ui.screens.WelcomeScreen @@ -73,9 +72,10 @@ fun Navigation( scaleOut(targetScale = SCALE_IN) + fadeOut(tween(durationMillis = 150)) } ) { - AudioRecorderScreen( + RecorderScreen( navController = navController, audioRecorder = audioRecorder, + videoRecorder = videoRecorder, ) } composable( diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/AudioRecordingStart.kt b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/AudioRecordingStart.kt new file mode 100644 index 0000000..7970417 --- /dev/null +++ b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/AudioRecordingStart.kt @@ -0,0 +1,90 @@ +package app.myzel394.alibi.ui.components.AudioRecorder.atoms + +import android.Manifest +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.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Mic +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp +import app.myzel394.alibi.R +import app.myzel394.alibi.db.AppSettings +import app.myzel394.alibi.ui.components.atoms.PermissionRequester +import app.myzel394.alibi.ui.models.AudioRecorderModel + +@Composable +fun AudioRecordingStart( + audioRecorder: AudioRecorderModel, + appSettings: AppSettings, +) { + val context = LocalContext.current + + // We can't get the current `notificationDetails` inside the + // `onPermissionAvailable` function. We'll instead use this hack + // with `LaunchedEffect` to get the current value. + var startRecording by rememberSaveable { mutableStateOf(false) } + LaunchedEffect(startRecording) { + if (startRecording) { + startRecording = false + + audioRecorder.startRecording(context, appSettings) + } + } + + PermissionRequester( + permission = Manifest.permission.RECORD_AUDIO, + icon = Icons.Default.Mic, + onPermissionAvailable = { + startRecording = true + } + ) { trigger -> + val label = stringResource(R.string.ui_audioRecorder_action_start_label) + + Button( + onClick = trigger, + modifier = Modifier + .semantics { + contentDescription = label + } + .size(200.dp) + .clip(shape = CircleShape), + colors = ButtonDefaults.outlinedButtonColors(), + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon( + Icons.Default.Mic, + contentDescription = null, + modifier = Modifier + .size(80.dp), + ) + Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing)) + Text( + label, + style = MaterialTheme.typography.titleSmall, + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/VideoRecordingStart.kt b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/VideoRecordingStart.kt new file mode 100644 index 0000000..7f1fe5b --- /dev/null +++ b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/atoms/VideoRecordingStart.kt @@ -0,0 +1,92 @@ +package app.myzel394.alibi.ui.components.AudioRecorder.atoms + +import android.Manifest +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.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CameraAlt +import androidx.compose.material.icons.filled.Mic +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp +import app.myzel394.alibi.R +import app.myzel394.alibi.db.AppSettings +import app.myzel394.alibi.ui.components.atoms.PermissionRequester +import app.myzel394.alibi.ui.models.AudioRecorderModel +import app.myzel394.alibi.ui.models.VideoRecorderModel + +@Composable +fun VideoRecordingStart( + videoRecorder: VideoRecorderModel, + appSettings: AppSettings, +) { + val context = LocalContext.current + + // We can't get the current `notificationDetails` inside the + // `onPermissionAvailable` function. We'll instead use this hack + // with `LaunchedEffect` to get the current value. + var startRecording by rememberSaveable { mutableStateOf(false) } + LaunchedEffect(startRecording) { + if (startRecording) { + startRecording = false + + videoRecorder.startRecording(context, appSettings) + } + } + + PermissionRequester( + permission = Manifest.permission.RECORD_AUDIO, + icon = Icons.Default.Mic, + onPermissionAvailable = { + startRecording = true + } + ) { trigger -> + val label = stringResource(R.string.ui_videoRecorder_action_start_label) + + Button( + onClick = trigger, + modifier = Modifier + .semantics { + contentDescription = label + } + .size(200.dp) + .clip(shape = CircleShape), + colors = ButtonDefaults.outlinedButtonColors(), + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon( + Icons.Default.CameraAlt, + contentDescription = null, + modifier = Modifier + .size(80.dp), + ) + Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing)) + Text( + label, + style = MaterialTheme.typography.titleSmall, + ) + } + } + } +} \ No newline at end of file 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 7289b2f..75b4b06 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 @@ -1,6 +1,5 @@ package app.myzel394.alibi.ui.components.AudioRecorder.molecules -import android.Manifest import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -11,9 +10,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Mic import androidx.compose.material.icons.filled.Save import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -21,15 +18,8 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.contentDescription @@ -37,18 +27,20 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import app.myzel394.alibi.R -import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE -import app.myzel394.alibi.ui.components.atoms.PermissionRequester +import app.myzel394.alibi.ui.components.AudioRecorder.atoms.AudioRecordingStart +import app.myzel394.alibi.ui.components.AudioRecorder.atoms.VideoRecordingStart import app.myzel394.alibi.ui.effects.rememberForceUpdateOnLifeCycleChange import app.myzel394.alibi.ui.models.AudioRecorderModel +import app.myzel394.alibi.ui.models.VideoRecorderModel import java.time.format.DateTimeFormatter import java.time.format.FormatStyle @Composable fun StartRecording( audioRecorder: AudioRecorderModel, + videoRecorder: VideoRecorderModel, // Loading this from parent, because if we load it ourselves // and permissions have already been granted, initial // settings will be used, instead of the actual settings. @@ -57,70 +49,26 @@ fun StartRecording( ) { val context = LocalContext.current - // We can't get the current `notificationDetails` inside the - // `onPermissionAvailable` function. We'll instead use this hack - // with `LaunchedEffect` to get the current value. - var startRecording by rememberSaveable { mutableStateOf(false) } - LaunchedEffect(startRecording) { - if (startRecording) { - startRecording = false - - audioRecorder.startRecording(context, appSettings) - } - } - Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.SpaceBetween, horizontalAlignment = Alignment.CenterHorizontally, ) { Spacer(modifier = Modifier.weight(1f)) - PermissionRequester( - permission = Manifest.permission.RECORD_AUDIO, - icon = Icons.Default.Mic, - onPermissionAvailable = { - startRecording = true - }, - ) { trigger -> - val label = stringResource(R.string.ui_audioRecorder_action_start_label) - Button( - onClick = trigger, - modifier = Modifier - .semantics { - contentDescription = label - } - .size(200.dp) - .clip(shape = CircleShape), - colors = ButtonDefaults.outlinedButtonColors(), - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Icon( - Icons.Default.Mic, - contentDescription = null, - modifier = Modifier - .size(80.dp), - ) - Spacer(modifier = Modifier.height(ButtonDefaults.IconSpacing)) - Text( - label, - style = MaterialTheme.typography.titleSmall, - ) - } - } - } - val settings = LocalContext - .current - .dataStore - .data - .collectAsState(initial = AppSettings.getDefaultInstance()) - .value + + AudioRecordingStart( + audioRecorder = audioRecorder, + appSettings = appSettings, + ) + VideoRecordingStart( + videoRecorder = videoRecorder, + appSettings = appSettings, + ) Text( stringResource( R.string.ui_audioRecorder_action_start_description, - settings.maxDuration / 1000 / 60 + appSettings.maxDuration / 1000 / 60 ), style = MaterialTheme.typography.bodySmall.copy( color = MaterialTheme.colorScheme.onSurfaceVariant, diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt similarity index 97% rename from app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt rename to app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt index 677e4fc..18168e2 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt @@ -48,14 +48,16 @@ import app.myzel394.alibi.helpers.AudioBatchesFolder import app.myzel394.alibi.helpers.BatchesFolder import app.myzel394.alibi.ui.effects.rememberSettings import app.myzel394.alibi.ui.models.AudioRecorderModel +import app.myzel394.alibi.ui.models.VideoRecorderModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable -fun AudioRecorderScreen( +fun RecorderScreen( navController: NavController, audioRecorder: AudioRecorderModel, + videoRecorder: VideoRecorderModel, ) { val snackbarHostState = remember { SnackbarHostState() } val context = LocalContext.current @@ -299,7 +301,9 @@ fun AudioRecorderScreen( RecordingStatus(audioRecorder = audioRecorder) else StartRecording( - audioRecorder = audioRecorder, appSettings = appSettings, + audioRecorder = audioRecorder, + videoRecorder = videoRecorder, + appSettings = appSettings, onSaveLastRecording = ::saveRecording, ) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b1280a..2f0e955 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -18,7 +18,7 @@ Please grant the permission to continue You will be redirected to the app settings to grant the permission there. - Start Recording + Start Audio Recording Save Recording from %s Delete Delete Recording? @@ -138,4 +138,5 @@ HD Standard Lowest + Start Video Recording \ No newline at end of file