diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderNotificationHelper.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderNotificationHelper.kt index 469a8a6..d0835f3 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderNotificationHelper.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderNotificationHelper.kt @@ -8,7 +8,9 @@ import androidx.core.app.NotificationCompat import app.myzel394.alibi.MainActivity import app.myzel394.alibi.NotificationHelper import app.myzel394.alibi.R +import app.myzel394.alibi.db.NotificationSettings import app.myzel394.alibi.enums.RecorderState +import kotlinx.serialization.Serializable import java.time.LocalDateTime import java.time.ZoneId import java.util.Calendar @@ -18,12 +20,36 @@ data class RecorderNotificationHelper( val context: Context, val details: NotificationDetails? = null, ) { + @Serializable data class NotificationDetails( val title: String, val description: String, val icon: Int, val isOngoing: Boolean, - ) + ) { + companion object { + fun fromNotificationSettings( + context: Context, + settings: NotificationSettings, + ): NotificationDetails { + return if (settings.preset == null) { + NotificationDetails( + settings.title, + settings.message, + settings.iconID, + settings.showOngoing, + ) + } else { + NotificationDetails( + context.getString(settings.preset.titleID), + context.getString(settings.preset.messageID), + settings.preset.iconID, + settings.preset.showOngoing, + ) + } + } + } + } private fun getNotificationChangeStateIntent( newState: RecorderState, diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt index 6adfa17..750d3ea 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt @@ -14,6 +14,7 @@ import app.myzel394.alibi.NotificationHelper import app.myzel394.alibi.R import app.myzel394.alibi.enums.RecorderState import app.myzel394.alibi.ui.utils.PermissionHelper +import kotlinx.serialization.json.Json import java.time.LocalDateTime import java.time.ZoneId import java.util.Calendar @@ -51,6 +52,15 @@ abstract class RecorderService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { when (intent?.action) { + "init" -> { + notificationDetails = intent.getStringExtra("notificationDetails")?.let { + Json.decodeFromString( + RecorderNotificationHelper.NotificationDetails.serializer(), + it + ) + } + } + "changeState" -> { val newState = intent.getStringExtra("newState")?.let { RecorderState.valueOf(it) 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 a040e48..0c3c046 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 @@ -20,8 +20,15 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.rememberStandardBottomSheetState 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.rememberCoroutineScope +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 @@ -31,22 +38,51 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import app.myzel394.alibi.NotificationHelper import app.myzel394.alibi.R import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.AppSettings +import app.myzel394.alibi.services.RecorderNotificationHelper import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE import app.myzel394.alibi.ui.components.atoms.PermissionRequester import app.myzel394.alibi.ui.models.AudioRecorderModel import app.myzel394.alibi.ui.utils.rememberFileSaverDialog +import kotlinx.coroutines.flow.last +import kotlinx.coroutines.flow.lastOrNull +import kotlinx.coroutines.launch import java.time.format.DateTimeFormatter import java.time.format.FormatStyle @Composable fun StartRecording( audioRecorder: AudioRecorderModel, + // 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. + 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.notificationDetails = appSettings.notificationSettings.let { + if (it == null) + null + else + RecorderNotificationHelper.NotificationDetails.fromNotificationSettings( + context, + it + ) + } + audioRecorder.startRecording(context) + } + } + Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.SpaceBetween, @@ -57,14 +93,12 @@ fun StartRecording( permission = Manifest.permission.RECORD_AUDIO, icon = Icons.Default.Mic, onPermissionAvailable = { - audioRecorder.startRecording(context) + startRecording = true }, ) { trigger -> val label = stringResource(R.string.ui_audioRecorder_action_start_label) Button( - onClick = { - trigger() - }, + onClick = trigger, modifier = Modifier .semantics { contentDescription = label @@ -98,7 +132,10 @@ fun StartRecording( .value Text( - stringResource(R.string.ui_audioRecorder_action_start_description, settings.audioRecorderSettings.maxDuration / 1000 / 60), + stringResource( + R.string.ui_audioRecorder_action_start_description, + settings.audioRecorderSettings.maxDuration / 1000 / 60 + ), style = MaterialTheme.typography.bodySmall.copy( color = MaterialTheme.colorScheme.onSurfaceVariant, ), @@ -115,7 +152,8 @@ fun StartRecording( ) { val label = stringResource( R.string.ui_audioRecorder_action_saveOldRecording_label, - DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(audioRecorder.lastRecording!!.recordingStart), + DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) + .format(audioRecorder.lastRecording!!.recordingStart), ) Button( modifier = Modifier @@ -140,8 +178,7 @@ fun StartRecording( Text(label) } } - } - else + } else Spacer(modifier = Modifier.weight(1f)) } } \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt index 3b666cb..7e278ee 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt @@ -13,10 +13,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModel +import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.LastRecording import app.myzel394.alibi.enums.RecorderState import app.myzel394.alibi.services.AudioRecorderService +import app.myzel394.alibi.services.RecorderNotificationHelper import app.myzel394.alibi.services.RecorderService +import kotlinx.coroutines.flow.last +import kotlinx.serialization.json.Json class AudioRecorderModel : ViewModel() { var recorderState by mutableStateOf(RecorderState.IDLE) @@ -45,6 +49,7 @@ class AudioRecorderModel : ViewModel() { var onRecordingSave: () -> Unit = {} var onError: () -> Unit = {} + var notificationDetails: RecorderNotificationHelper.NotificationDetails? = null private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { @@ -90,7 +95,19 @@ class AudioRecorderModel : ViewModel() { context.unbindService(connection) } - val intent = Intent(context, AudioRecorderService::class.java) + val intent = Intent(context, AudioRecorderService::class.java).apply { + action = "init" + + if (notificationDetails != null) { + putExtra( + "notificationDetails", + Json.encodeToString( + RecorderNotificationHelper.NotificationDetails.serializer(), + notificationDetails!!, + ), + ) + } + } ContextCompat.startForegroundService(context, intent) context.bindService(intent, connection, Context.BIND_AUTO_CREATE) } @@ -118,10 +135,6 @@ class AudioRecorderModel : ViewModel() { recorderService!!.changeState(RecorderState.RECORDING) } - fun setNotificationDetails(details: RecorderService.NotificationDetails) { - recorderService?.notificationDetails = details - } - fun setMaxAmplitudesAmount(amount: Int) { recorderService?.amplitudesAmount = amount } diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorder.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorder.kt index 1e121bf..99845dc 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorder.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorder.kt @@ -38,6 +38,7 @@ import app.myzel394.alibi.R import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.db.LastRecording +import app.myzel394.alibi.services.RecorderNotificationHelper import app.myzel394.alibi.ui.effects.rememberSettings import app.myzel394.alibi.ui.models.AudioRecorderModel import kotlinx.coroutines.launch @@ -171,10 +172,13 @@ fun AudioRecorder( .fillMaxSize() .padding(padding), ) { + val appSettings = + context.dataStore.data.collectAsState(AppSettings.getDefaultInstance()).value + if (audioRecorder.isInRecording) RecordingStatus(audioRecorder = audioRecorder) else - StartRecording(audioRecorder = audioRecorder) + StartRecording(audioRecorder = audioRecorder, appSettings = appSettings) } } } \ No newline at end of file