diff --git a/app/src/main/java/app/myzel394/locationtest/services/RecorderService.kt b/app/src/main/java/app/myzel394/locationtest/services/RecorderService.kt index 690f256..d35f9af 100644 --- a/app/src/main/java/app/myzel394/locationtest/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/locationtest/services/RecorderService.kt @@ -11,9 +11,6 @@ import android.os.Handler import android.os.IBinder import android.os.Looper import android.util.Log -import androidx.compose.animation.core.Animatable -import androidx.compose.animation.core.LinearEasing -import androidx.compose.animation.core.tween import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.core.app.NotificationCompat @@ -35,7 +32,7 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import java.util.Date -import java.util.UUID; +import java.util.UUID const val AMPLITUDE_UPDATE_INTERVAL = 100L @@ -47,26 +44,20 @@ class RecorderService: Service() { private var mediaRecorder: MediaRecorder? = null private var onError: MediaRecorder.OnErrorListener? = null - private var onStateChange: (RecorderState) -> Unit = {} private var onAmplitudeUpdate: () -> Unit = {} private var counter = 0 lateinit var settings: Settings - var recordingStart = mutableStateOf(null) - private set var fileFolder: String? = null private set - var recordingState: RecorderState = RecorderState.IDLE - private set - val isRecording: Boolean - get() = recordingStart.value != null + val isRecording = mutableStateOf(false) val filePaths = mutableListOf() val amplitudes = mutableStateListOf() - var originalRecordingStart: LocalDateTime? = null + var recordingStart: LocalDateTime? = null private set override fun onBind(p0: Intent?): IBinder = binder @@ -90,21 +81,26 @@ class RecorderService: Service() { scope.cancel() } - fun setOnErrorListener(onError: MediaRecorder.OnErrorListener) { - this.onError = onError - } - fun setOnAmplitudeUpdateListener(onAmplitudeUpdate: () -> Unit) { this.onAmplitudeUpdate = onAmplitudeUpdate } - fun setOnStateChangeListener(onStateChange: (RecorderState) -> Unit) { - this.onStateChange = onStateChange + fun reset() { + recordingStart = null + counter = 0 + amplitudes.clear() + isRecording.value = false + + filePaths.forEach { + File(it).delete() + } + + filePaths.clear() } fun concatenateFiles(forceConcatenation: Boolean = false): File { val paths = filePaths.joinToString("|") - val outputFile = "$fileFolder/${originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}.${settings.fileExtension}" + val outputFile = "$fileFolder/${recordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}.${settings.fileExtension}" if (File(outputFile).exists() && !forceConcatenation) { return File(outputFile) @@ -132,7 +128,7 @@ class RecorderService: Service() { } private fun updateAmplitude() { - if (!isRecording || mediaRecorder == null) { + if (!isRecording.value || mediaRecorder == null) { return } @@ -144,7 +140,7 @@ class RecorderService: Service() { } private fun startNewRecording() { - if (!isRecording) { + if (!isRecording.value) { return } @@ -205,17 +201,15 @@ class RecorderService: Service() { private fun start() { - amplitudes.clear() - filePaths.clear() + reset() // Create folder File(this.fileFolder!!).mkdirs() scope.launch { dataStore.data.collectLatest { preferenceSettings -> settings = Settings.from(preferenceSettings.audioRecorderSettings) - recordingState = RecorderState.RECORDING - recordingStart.value = LocalDateTime.now() - originalRecordingStart = recordingStart.value + recordingStart = LocalDateTime.now() + isRecording.value = true showNotification() startNewRecording() @@ -225,22 +219,20 @@ class RecorderService: Service() { } private fun stop() { - recordingState = RecorderState.IDLE - mediaRecorder?.apply { runCatching { stop() release() } } - recordingStart.value = null + isRecording.value = false stopForeground(STOP_FOREGROUND_REMOVE) stopSelf() } private fun showNotification() { - if (recordingStart.value == null) { + if (!isRecording.value) { return } @@ -254,7 +246,7 @@ class RecorderService: Service() { .setOnlyAlertOnce(true) .setUsesChronometer(true) .setChronometerCountDown(false) - .setWhen(Date.from(recordingStart.value!!.atZone(ZoneId.systemDefault()).toInstant()).time) + .setWhen(Date.from(recordingStart!!.atZone(ZoneId.systemDefault()).toInstant()).time) .setShowWhen(true) .build() @@ -267,10 +259,10 @@ class RecorderService: Service() { // To avoid int overflow, we'll use the number of seconds since 2023-01-01 01:01:01 private fun getNotificationId(): Int { - val offset = ZoneId.of("UTC").rules.getOffset(recordingStart.value) + val offset = ZoneId.of("UTC").rules.getOffset(recordingStart!!) return ( - recordingStart.value!!.toEpochSecond(offset) - + recordingStart!!.toEpochSecond(offset) - LocalDateTime.of(2023, 1, 1, 1, 1).toEpochSecond(offset) ).toInt() } @@ -286,12 +278,6 @@ class RecorderService: Service() { STOP, } - enum class RecorderState { - IDLE, - RECORDING, - PAUSED, - } - companion object { fun getRandomFileFolder(context: Context): String { // uuid @@ -302,7 +288,7 @@ class RecorderService: Service() { fun startService(context: Context, connection: ServiceConnection?) { Intent(context, RecorderService::class.java).also { intent -> - intent.action = RecorderService.Actions.START.toString() + intent.action = Actions.START.toString() ContextCompat.startForegroundService(context, intent) @@ -314,7 +300,7 @@ class RecorderService: Service() { fun stopService(context: Context) { Intent(context, RecorderService::class.java).also { intent -> - intent.action = RecorderService.Actions.STOP.toString() + intent.action = Actions.STOP.toString() context.startService(intent) } diff --git a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RecordingStatus.kt b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RecordingStatus.kt index 28e11f9..914d52c 100644 --- a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RecordingStatus.kt +++ b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RecordingStatus.kt @@ -15,7 +15,9 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Cancel +import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Save +import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon @@ -55,7 +57,7 @@ fun RecordingStatus( var now by remember { mutableStateOf(LocalDateTime.now()) } - val start = service.recordingStart.value!! + val start = service.recordingStart!! val duration = now.toEpochSecond(ZoneId.systemDefault().rules.getOffset(now)) - start.toEpochSecond(ZoneId.systemDefault().rules.getOffset(start)) val progress = duration / (service.settings.maxDuration / 1000f) @@ -81,7 +83,7 @@ fun RecordingStatus( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center, ) { - val distance = Duration.between(service.recordingStart.value, now).toMillis() + val distance = Duration.between(service.recordingStart, now).toMillis() Pulsating { Box( @@ -104,18 +106,81 @@ fun RecordingStatus( .width(300.dp) ) Spacer(modifier = Modifier.height(32.dp)) + + var showDeleteDialog by remember { mutableStateOf(false) } + + if (showDeleteDialog) { + AlertDialog( + onDismissRequest = { + showDeleteDialog = false + }, + title = { + Text("Delete Recording?") + }, + text = { + Text("Are you sure you want to delete this recording?") + }, + icon = { + Icon( + Icons.Default.Delete, + contentDescription = null, + ) + }, + confirmButton = { + Button( + modifier = Modifier + .semantics { + contentDescription = "Confirm Recording Deletion" + }, + onClick = { + showDeleteDialog = false + RecorderService.stopService(context) + service.reset() + }, + ) { + Icon( + Icons.Default.Delete, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) + Text("Delete") + } + }, + dismissButton = { + Button( + modifier = Modifier + .semantics { + contentDescription = "Cancel Recording Deletion" + }, + onClick = { + showDeleteDialog = false + }, + colors = ButtonDefaults.textButtonColors(), + ) { + Icon( + Icons.Default.Cancel, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) + Text("Cancel") + } + } + ) + } Button( modifier = Modifier .semantics { contentDescription = "Delete Recording" }, onClick = { - RecorderService.stopService(context) + showDeleteDialog = true }, colors = ButtonDefaults.textButtonColors(), ) { Icon( - Icons.Default.Cancel, + Icons.Default.Delete, contentDescription = null, modifier = Modifier.size(ButtonDefaults.IconSize), ) diff --git a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/StartRecording.kt b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/StartRecording.kt index efe47df..fde0c3d 100644 --- a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/StartRecording.kt +++ b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/StartRecording.kt @@ -1,9 +1,7 @@ package app.myzel394.locationtest.ui.components.AudioRecorder.atoms import android.content.ServiceConnection -import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -25,8 +23,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Size import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics @@ -83,7 +79,7 @@ fun StartRecording( ) } } - if (service?.originalRecordingStart != null) + if (service?.recordingStart != null) Column( modifier = Modifier.weight(1f), horizontalAlignment = Alignment.CenterHorizontally, @@ -112,7 +108,7 @@ fun StartRecording( .size(ButtonDefaults.IconSize), ) Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) - Text("Save Recording from ${service.originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}") + Text("Save Recording from ${service.recordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}") } } else diff --git a/app/src/main/java/app/myzel394/locationtest/ui/screens/AudioRecorder.kt b/app/src/main/java/app/myzel394/locationtest/ui/screens/AudioRecorder.kt index 0a839f5..0c87f76 100644 --- a/app/src/main/java/app/myzel394/locationtest/ui/screens/AudioRecorder.kt +++ b/app/src/main/java/app/myzel394/locationtest/ui/screens/AudioRecorder.kt @@ -58,9 +58,6 @@ fun AudioRecorder( object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, binder: IBinder?) { service = (binder as RecorderService.LocalBinder).getService().also { service -> - service.setOnStateChangeListener { - println("asd") - } } } @@ -69,7 +66,7 @@ fun AudioRecorder( } } - val isRecording = service?.isRecording ?: false + val isRecording = service?.isRecording?.value ?: false LaunchedEffect(Unit) { Intent(context, RecorderService::class.java).also { intent ->