From 1269c6cb0064c1d20d8a1b6878b197c3c3306fe8 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:50:05 +0200 Subject: [PATCH] ui: Improve design --- .../app/myzel394/locationtest/ui/Constants.kt | 1 + .../AudioRecorder/atoms/AudioVisualizer.kt | 32 +++++----- .../atoms/RealTimeAudioVisualizer.kt | 13 +--- .../AudioRecorder/atoms/RecordingStatus.kt | 27 ++++++++- .../AudioRecorder/atoms/StartRecording.kt | 59 +++++++++++-------- .../locationtest/ui/utils/interpolation.kt | 2 - 6 files changed, 75 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/app/myzel394/locationtest/ui/Constants.kt b/app/src/main/java/app/myzel394/locationtest/ui/Constants.kt index 0ca5175..51ba12e 100644 --- a/app/src/main/java/app/myzel394/locationtest/ui/Constants.kt +++ b/app/src/main/java/app/myzel394/locationtest/ui/Constants.kt @@ -3,3 +3,4 @@ package app.myzel394.locationtest.ui import androidx.compose.ui.unit.dp val BIG_PRIMARY_BUTTON_SIZE = 64.dp +val MAX_AMPLITUDE = 20000 diff --git a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/AudioVisualizer.kt b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/AudioVisualizer.kt index a782304..5ec7dda 100644 --- a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/AudioVisualizer.kt +++ b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/AudioVisualizer.kt @@ -3,7 +3,6 @@ package app.myzel394.locationtest.ui.components.AudioRecorder.atoms import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.width import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -12,13 +11,13 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.unit.dp +import app.myzel394.locationtest.ui.MAX_AMPLITUDE // Inspired by https://github.com/Bnyro/RecordYou/blob/main/app/src/main/java/com/bnyro/recorder/ui/components/AudioVisualizer.kt -private const val MAX_AMPLITUDE = 10000 - @Composable fun AudioVisualizer( + modifier: Modifier = Modifier, amplitudes: List, ) { val primary = MaterialTheme.colorScheme.primary @@ -27,26 +26,23 @@ fun AudioVisualizer( Canvas( modifier = Modifier .fillMaxWidth() - .height(300.dp), + .then(modifier) ) { val height = this.size.height / 2f val width = this.size.width + val boxWidth = width / amplitudes.size - translate(width, height) { - amplitudes.forEachIndexed { index, amplitude -> - val amplitudePercentage = (amplitude.toFloat() / MAX_AMPLITUDE).coerceAtMost(1f) - val boxHeight = height * amplitudePercentage + amplitudes.forEachIndexed {index, amplitude -> + val x = boxWidth * index + val amplitudePercentage = (amplitude.toFloat() / MAX_AMPLITUDE).coerceAtMost(1f) + val boxHeight = height * amplitudePercentage - drawRoundRect( - color = if (amplitudePercentage > 0.05f) primary else primaryMuted, - topLeft = Offset( - -width / amplitudes.size * index, - -boxHeight / 2f - ), - size = Size(width, boxHeight), - cornerRadius = CornerRadius(3f, 3f) - ) - } + drawRoundRect( + color = if (amplitudePercentage > 0.05f) primary else primaryMuted, + topLeft = Offset(x, -boxHeight / 2f), + size = Size(boxWidth, boxHeight), + cornerRadius = CornerRadius(3f, 3f) + ) } } } \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RealTimeAudioVisualizer.kt b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RealTimeAudioVisualizer.kt index 5320ec7..e51b0d5 100644 --- a/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RealTimeAudioVisualizer.kt +++ b/app/src/main/java/app/myzel394/locationtest/ui/components/AudioRecorder/atoms/RealTimeAudioVisualizer.kt @@ -1,23 +1,14 @@ package app.myzel394.locationtest.ui.components.AudioRecorder.atoms -import android.inputmethodservice.Keyboard import androidx.compose.animation.core.Animatable -import androidx.compose.animation.core.AnimationVector1D import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyRow import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.mutableStateListOf -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -26,13 +17,11 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.unit.dp -import androidx.core.math.MathUtils import app.myzel394.locationtest.services.RecorderService +import app.myzel394.locationtest.ui.MAX_AMPLITUDE import app.myzel394.locationtest.ui.utils.clamp -import app.myzel394.locationtest.ui.utils.interpolate import kotlinx.coroutines.launch -private const val MAX_AMPLITUDE = 10000 private const val BOX_WIDTH = 15f private const val BOX_GAP = 15f private const val BOX_DIFF = BOX_WIDTH + BOX_GAP 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 5923497..28e11f9 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 @@ -9,10 +9,12 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size 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.Save import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -31,6 +33,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import app.myzel394.locationtest.services.RecorderService import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE @@ -63,7 +67,8 @@ fun RecordingStatus( } Column( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.SpaceBetween, ) { @@ -100,18 +105,32 @@ fun RecordingStatus( ) Spacer(modifier = Modifier.height(32.dp)) Button( + modifier = Modifier + .semantics { + contentDescription = "Delete Recording" + }, onClick = { RecorderService.stopService(context) }, colors = ButtonDefaults.textButtonColors(), ) { - Text("Cancel") + Icon( + Icons.Default.Cancel, + contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), + ) + Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) + Text("Delete") } } Button( modifier = Modifier + .padding(16.dp) .fillMaxWidth() - .height(BIG_PRIMARY_BUTTON_SIZE), + .height(BIG_PRIMARY_BUTTON_SIZE) + .semantics { + contentDescription = "Save Recording" + }, onClick = { RecorderService.stopService(context) @@ -121,7 +140,9 @@ fun RecordingStatus( Icon( Icons.Default.Save, contentDescription = null, + modifier = Modifier.size(ButtonDefaults.IconSize), ) + Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) Text("Save Recording") } } 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 a7dc1c9..efe47df 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 @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape @@ -35,6 +36,8 @@ import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE import app.myzel394.locationtest.ui.utils.rememberFileSaverDialog import java.time.format.DateTimeFormatter +val VISUALIZER_HEIGHT = 200.dp + @Composable fun StartRecording( connection: ServiceConnection, @@ -44,17 +47,14 @@ fun StartRecording( val saveFile = rememberFileSaverDialog("audio/*") + val hasAmplitudes = service?.amplitudes?.isNotEmpty() ?: false + Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.SpaceBetween, horizontalAlignment = Alignment.CenterHorizontally, ) { - Box {} - if (service != null && service.amplitudes.isNotEmpty()) { - Box {} - } - - val primary = MaterialTheme.colorScheme.primary + Spacer(modifier = Modifier.weight(1f)) Button( onClick = { RecorderService.startService(context, connection) @@ -83,28 +83,39 @@ fun StartRecording( ) } } - if (service != null && service.amplitudes.isNotEmpty()) { - AudioVisualizer(amplitudes = service.amplitudes) - } if (service?.originalRecordingStart != null) - Button( - modifier = Modifier - .fillMaxWidth() - .height(BIG_PRIMARY_BUTTON_SIZE), - onClick = { - saveFile(service.concatenateFiles()) - } + Column( + modifier = Modifier.weight(1f), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Bottom, ) { - Icon( - Icons.Default.Save, - contentDescription = null, + if (hasAmplitudes) + AudioVisualizer( + modifier = Modifier + .height(100.dp) + .padding(bottom = 32.dp), + amplitudes = service.amplitudes, + ) + Button( modifier = Modifier - .size(ButtonDefaults.IconSize), - ) - Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) - Text("Save Recording from ${service.originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}") + .padding(16.dp) + .fillMaxWidth() + .height(BIG_PRIMARY_BUTTON_SIZE), + onClick = { + saveFile(service.concatenateFiles()) + } + ) { + Icon( + Icons.Default.Save, + contentDescription = null, + modifier = Modifier + .size(ButtonDefaults.IconSize), + ) + Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) + Text("Save Recording from ${service.originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}") + } } else - Box {} + Spacer(modifier = Modifier.weight(1f)) } } \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/ui/utils/interpolation.kt b/app/src/main/java/app/myzel394/locationtest/ui/utils/interpolation.kt index 5f5fe68..5613e1e 100644 --- a/app/src/main/java/app/myzel394/locationtest/ui/utils/interpolation.kt +++ b/app/src/main/java/app/myzel394/locationtest/ui/utils/interpolation.kt @@ -1,7 +1,5 @@ package app.myzel394.locationtest.ui.utils -import androidx.compose.animation.core.Easing - fun clamp(value: Float, min: Float, max: Float): Float { return value