From 671c8da56ab43344f5f95c6fd9c1dc3fca866a79 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 16 Mar 2024 17:28:45 +0100 Subject: [PATCH] refactor: Move recording save stuff out to audio and video recording statuses component Signed-off-by: Myzel394 <50424412+Myzel394@users.noreply.github.com> --- .../java/app/myzel394/alibi/db/AppSettings.kt | 11 ++ .../organisms/AudioRecordingStatus.kt | 103 ++++++++---------- .../organisms/RecorderEventsHandler.kt | 51 +++------ .../organisms/VideoRecordingStatus.kt | 16 ++- .../alibi/ui/models/BaseRecorderModel.kt | 4 +- .../alibi/ui/screens/RecorderScreen.kt | 27 +++-- 6 files changed, 107 insertions(+), 105 deletions(-) diff --git a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt index 1f45583..3b00d06 100644 --- a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt +++ b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt @@ -11,6 +11,7 @@ import app.myzel394.alibi.helpers.AudioBatchesFolder import app.myzel394.alibi.helpers.VideoBatchesFolder import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE +import app.myzel394.alibi.ui.components.RecorderScreen.organisms.RecorderModel import app.myzel394.alibi.ui.utils.PermissionHelper import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json @@ -102,6 +103,16 @@ data class AppSettings( return copy(appLockSettings = appLockSettings) } + fun saveLastRecording(recorder: RecorderModel): AppSettings { + return if (deleteRecordingsImmediately) { + this + } else { + setLastRecording( + recorder.recorderService!!.getRecordingInformation() + ) + } + } + // If the object is present, biometric authentication is enabled. // To disable biometric authentication, set the instance to null. fun isAppLockEnabled() = appLockSettings != null diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/AudioRecordingStatus.kt b/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/AudioRecordingStatus.kt index 2a639a0..bc97706 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/AudioRecordingStatus.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/AudioRecordingStatus.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp +import app.myzel394.alibi.dataStore import app.myzel394.alibi.ui.components.RecorderScreen.atoms.RealtimeAudioVisualizer import app.myzel394.alibi.ui.components.RecorderScreen.molecules.MicrophoneStatus import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingControl @@ -39,8 +40,6 @@ fun AudioRecordingStatus( val context = LocalContext.current val configuration = LocalConfiguration.current.orientation - val scope = rememberCoroutineScope() - var now by remember { mutableStateOf(LocalDateTime.now()) } LaunchedEffect(Unit) { @@ -90,34 +89,7 @@ fun AudioRecordingStatus( MicrophoneStatus(audioRecorder) } - RecordingControl( - modifier = Modifier - .weight(1f) - .fillMaxWidth(), - isPaused = audioRecorder.isPaused, - recordingTime = audioRecorder.recordingTime, - onDelete = { - scope.launch { - runCatching { - audioRecorder.stopRecording(context) - } - runCatching { - audioRecorder.destroyService(context) - } - audioRecorder.batchesFolder!!.deleteRecordings() - } - }, - onPauseResume = { - if (audioRecorder.isPaused) { - audioRecorder.resumeRecording() - } else { - audioRecorder.pauseRecording() - } - }, - onSave = { - audioRecorder.onRecordingSave(false) - } - ) + _PrimitiveControls(audioRecorder) } } @@ -138,33 +110,54 @@ fun AudioRecordingStatus( HorizontalDivider() - RecordingControl( - isPaused = audioRecorder.isPaused, - recordingTime = audioRecorder.recordingTime, - onDelete = { - scope.launch { - runCatching { - audioRecorder.stopRecording(context) - } - runCatching { - audioRecorder.destroyService(context) - } - audioRecorder.batchesFolder!!.deleteRecordings() - } - }, - onPauseResume = { - if (audioRecorder.isPaused) { - audioRecorder.resumeRecording() - } else { - audioRecorder.pauseRecording() - } - }, - onSave = { - audioRecorder.onRecordingSave(false) - } - ) + _PrimitiveControls(audioRecorder) } } } } +} + +@Composable +fun _PrimitiveControls(audioRecorder: AudioRecorderModel) { + val context = LocalContext.current + val dataStore = context.dataStore + val scope = rememberCoroutineScope() + + RecordingControl( + isPaused = audioRecorder.isPaused, + recordingTime = audioRecorder.recordingTime, + onDelete = { + scope.launch { + runCatching { + audioRecorder.stopRecording(context) + } + runCatching { + audioRecorder.destroyService(context) + } + audioRecorder.batchesFolder!!.deleteRecordings() + } + }, + onPauseResume = { + if (audioRecorder.isPaused) { + audioRecorder.resumeRecording() + } else { + audioRecorder.pauseRecording() + } + }, + onSave = { + scope.launch { + audioRecorder.stopRecording(context) + + dataStore.updateData { + it.saveLastRecording(audioRecorder as RecorderModel) + } + + audioRecorder.onRecordingSave() + + runCatching { + audioRecorder.destroyService(context) + } + } + } + ) } \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/RecorderEventsHandler.kt b/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/RecorderEventsHandler.kt index 4db1b32..bd2c241 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/RecorderEventsHandler.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/RecorderEventsHandler.kt @@ -30,7 +30,6 @@ import app.myzel394.alibi.ui.models.AudioRecorderModel import app.myzel394.alibi.ui.models.BaseRecorderModel import app.myzel394.alibi.ui.models.VideoRecorderModel import app.myzel394.alibi.ui.utils.rememberFileSaverDialog -import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -224,26 +223,15 @@ fun RecorderEventsHandler( // Register audio recorder events DisposableEffect(key1 = audioRecorder, key2 = settings) { - audioRecorder.onRecordingSave = { justSave -> - val completer = CompletableDeferred() - + audioRecorder.onRecordingSave = { + // We create our own coroutine because we show our own dialog and we want to + // keep saving until it's finished. + // So it's smarter to take things into our own hands and use our local coroutine, + // instead of hoping that the coroutine from where this will be called will be alive + // until the end of the saving process scope.launch { - if (justSave) { - saveRecording(audioRecorder as RecorderModel) - } else { - audioRecorder.stopRecording(context) - - saveAsLastRecording(audioRecorder as RecorderModel) - - saveRecording(audioRecorder) - - audioRecorder.destroyService(context) - } - - completer.complete(Unit) + saveRecording(audioRecorder as RecorderModel) } - - completer } audioRecorder.onRecordingStart = { snackbarHostState.currentSnackbarData?.dismiss() @@ -278,26 +266,15 @@ fun RecorderEventsHandler( // Register video recorder events DisposableEffect(key1 = videoRecorder, key2 = settings) { - videoRecorder.onRecordingSave = { justSave -> - val completer = CompletableDeferred() - + videoRecorder.onRecordingSave = { + // We create our own coroutine because we show our own dialog and we want to + // keep saving until it's finished. + // So it's smarter to take things into our own hands and use our local coroutine, + // instead of hoping that the coroutine from where this will be called will be alive + // until the end of the saving process scope.launch { - if (justSave) { - saveRecording(videoRecorder as RecorderModel) - } else { - videoRecorder.stopRecording(context) - - saveAsLastRecording(videoRecorder as RecorderModel) - - saveRecording(videoRecorder) - - videoRecorder.destroyService(context) - } - - completer.complete(Unit) + saveRecording(videoRecorder as RecorderModel) } - - completer } videoRecorder.onRecordingStart = { snackbarHostState.currentSnackbarData?.dismiss() diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/VideoRecordingStatus.kt b/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/VideoRecordingStatus.kt index 47479d9..e6f1b5a 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/VideoRecordingStatus.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/RecorderScreen/organisms/VideoRecordingStatus.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import app.myzel394.alibi.R +import app.myzel394.alibi.dataStore import app.myzel394.alibi.ui.components.RecorderScreen.atoms.TorchStatus import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingControl import app.myzel394.alibi.ui.components.RecorderScreen.molecules.RecordingStatus @@ -189,6 +190,7 @@ fun _VideoRecordingStatus(videoRecorder: VideoRecorderModel) { @Composable fun _PrimitiveControls(videoRecorder: VideoRecorderModel) { val context = LocalContext.current + val dataStore = context.dataStore val scope = rememberCoroutineScope() RecordingControl( @@ -218,7 +220,19 @@ fun _PrimitiveControls(videoRecorder: VideoRecorderModel) { } }, onSave = { - videoRecorder.onRecordingSave(false) + scope.launch { + videoRecorder.stopRecording(context) + + dataStore.updateData { + it.saveLastRecording(videoRecorder as RecorderModel) + } + + videoRecorder.onRecordingSave() + + runCatching { + videoRecorder.destroyService(context) + } + } } ) } diff --git a/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt b/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt index ebc054e..1b54229 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt @@ -17,7 +17,7 @@ import app.myzel394.alibi.helpers.BatchesFolder import app.myzel394.alibi.services.IntervalRecorderService import app.myzel394.alibi.services.RecorderNotificationHelper import app.myzel394.alibi.services.RecorderService -import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Job import kotlinx.serialization.json.Json abstract class BaseRecorderModel> : @@ -46,7 +46,7 @@ abstract class BaseRecorderModel CompletableDeferred = { + var onRecordingSave: () -> Job = { throw NotImplementedError("onRecordingSave not implemented") } var onRecordingStart: () -> Unit = {} diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt index 68752b3..ae5cb01 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/RecorderScreen.kt @@ -16,22 +16,26 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable -import androidx.compose.runtime.* +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.navigation.NavController -import app.myzel394.alibi.ui.components.RecorderScreen.organisms.AudioRecordingStatus -import app.myzel394.alibi.ui.components.RecorderScreen.organisms.StartRecording -import app.myzel394.alibi.ui.enums.Screen import app.myzel394.alibi.R import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.db.RecordingInformation +import app.myzel394.alibi.ui.components.RecorderScreen.organisms.AudioRecordingStatus import app.myzel394.alibi.ui.components.RecorderScreen.organisms.RecorderEventsHandler +import app.myzel394.alibi.ui.components.RecorderScreen.organisms.StartRecording import app.myzel394.alibi.ui.components.RecorderScreen.organisms.VideoRecordingStatus import app.myzel394.alibi.ui.models.AudioRecorderModel import app.myzel394.alibi.ui.models.VideoRecorderModel +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -43,6 +47,7 @@ fun RecorderScreen( ) { val snackbarHostState = remember { SnackbarHostState() } val context = LocalContext.current + val scope = rememberCoroutineScope() RecorderEventsHandler( settings = settings, @@ -112,12 +117,14 @@ fun RecorderScreen( videoRecorder = videoRecorder, appSettings = appSettings, onSaveLastRecording = { - when (settings.lastRecording!!.type) { - RecordingInformation.Type.AUDIO -> - audioRecorder.onRecordingSave(true) + scope.launch { + when (settings.lastRecording!!.type) { + RecordingInformation.Type.AUDIO -> + audioRecorder.onRecordingSave() - RecordingInformation.Type.VIDEO -> - videoRecorder.onRecordingSave(true) + RecordingInformation.Type.VIDEO -> + videoRecorder.onRecordingSave() + } } }, showAudioRecorder = topBarVisible,