ui: Improve design

This commit is contained in:
Myzel394 2023-08-05 18:50:05 +02:00
parent b9e83114d0
commit 1269c6cb00
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
6 changed files with 75 additions and 59 deletions

View File

@ -3,3 +3,4 @@ package app.myzel394.locationtest.ui
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
val BIG_PRIMARY_BUTTON_SIZE = 64.dp val BIG_PRIMARY_BUTTON_SIZE = 64.dp
val MAX_AMPLITUDE = 20000

View File

@ -3,7 +3,6 @@ package app.myzel394.locationtest.ui.components.AudioRecorder.atoms
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier 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.geometry.Size
import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.unit.dp 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 // 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 @Composable
fun AudioVisualizer( fun AudioVisualizer(
modifier: Modifier = Modifier,
amplitudes: List<Int>, amplitudes: List<Int>,
) { ) {
val primary = MaterialTheme.colorScheme.primary val primary = MaterialTheme.colorScheme.primary
@ -27,26 +26,23 @@ fun AudioVisualizer(
Canvas( Canvas(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(300.dp), .then(modifier)
) { ) {
val height = this.size.height / 2f val height = this.size.height / 2f
val width = this.size.width val width = this.size.width
val boxWidth = width / amplitudes.size
translate(width, height) { amplitudes.forEachIndexed {index, amplitude ->
amplitudes.forEachIndexed { index, amplitude -> val x = boxWidth * index
val amplitudePercentage = (amplitude.toFloat() / MAX_AMPLITUDE).coerceAtMost(1f) val amplitudePercentage = (amplitude.toFloat() / MAX_AMPLITUDE).coerceAtMost(1f)
val boxHeight = height * amplitudePercentage val boxHeight = height * amplitudePercentage
drawRoundRect( drawRoundRect(
color = if (amplitudePercentage > 0.05f) primary else primaryMuted, color = if (amplitudePercentage > 0.05f) primary else primaryMuted,
topLeft = Offset( topLeft = Offset(x, -boxHeight / 2f),
-width / amplitudes.size * index, size = Size(boxWidth, boxHeight),
-boxHeight / 2f
),
size = Size(width, boxHeight),
cornerRadius = CornerRadius(3f, 3f) cornerRadius = CornerRadius(3f, 3f)
) )
} }
} }
}
} }

View File

@ -1,23 +1,14 @@
package app.myzel394.locationtest.ui.components.AudioRecorder.atoms package app.myzel394.locationtest.ui.components.AudioRecorder.atoms
import android.inputmethodservice.Keyboard
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas 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.fillMaxWidth
import androidx.compose.foundation.layout.height 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.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect 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.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier 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.geometry.Size
import androidx.compose.ui.graphics.drawscope.translate import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.math.MathUtils
import app.myzel394.locationtest.services.RecorderService 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.clamp
import app.myzel394.locationtest.ui.utils.interpolate
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
private const val MAX_AMPLITUDE = 10000
private const val BOX_WIDTH = 15f private const val BOX_WIDTH = 15f
private const val BOX_GAP = 15f private const val BOX_GAP = 15f
private const val BOX_DIFF = BOX_WIDTH + BOX_GAP private const val BOX_DIFF = BOX_WIDTH + BOX_GAP

View File

@ -9,10 +9,12 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Cancel
import androidx.compose.material.icons.filled.Save import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
@ -31,6 +33,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext 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 androidx.compose.ui.unit.dp
import app.myzel394.locationtest.services.RecorderService import app.myzel394.locationtest.services.RecorderService
import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE import app.myzel394.locationtest.ui.BIG_PRIMARY_BUTTON_SIZE
@ -63,7 +67,8 @@ fun RecordingStatus(
} }
Column( Column(
modifier = Modifier.fillMaxSize(), modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween, verticalArrangement = Arrangement.SpaceBetween,
) { ) {
@ -100,18 +105,32 @@ fun RecordingStatus(
) )
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))
Button( Button(
modifier = Modifier
.semantics {
contentDescription = "Delete Recording"
},
onClick = { onClick = {
RecorderService.stopService(context) RecorderService.stopService(context)
}, },
colors = ButtonDefaults.textButtonColors(), 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( Button(
modifier = Modifier modifier = Modifier
.padding(16.dp)
.fillMaxWidth() .fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE), .height(BIG_PRIMARY_BUTTON_SIZE)
.semantics {
contentDescription = "Save Recording"
},
onClick = { onClick = {
RecorderService.stopService(context) RecorderService.stopService(context)
@ -121,7 +140,9 @@ fun RecordingStatus(
Icon( Icon(
Icons.Default.Save, Icons.Default.Save,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize),
) )
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Save Recording") Text("Save Recording")
} }
} }

View File

@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape 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 app.myzel394.locationtest.ui.utils.rememberFileSaverDialog
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
val VISUALIZER_HEIGHT = 200.dp
@Composable @Composable
fun StartRecording( fun StartRecording(
connection: ServiceConnection, connection: ServiceConnection,
@ -44,17 +47,14 @@ fun StartRecording(
val saveFile = rememberFileSaverDialog("audio/*") val saveFile = rememberFileSaverDialog("audio/*")
val hasAmplitudes = service?.amplitudes?.isNotEmpty() ?: false
Column( Column(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween, verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Box {} Spacer(modifier = Modifier.weight(1f))
if (service != null && service.amplitudes.isNotEmpty()) {
Box {}
}
val primary = MaterialTheme.colorScheme.primary
Button( Button(
onClick = { onClick = {
RecorderService.startService(context, connection) RecorderService.startService(context, connection)
@ -83,12 +83,22 @@ fun StartRecording(
) )
} }
} }
if (service != null && service.amplitudes.isNotEmpty()) {
AudioVisualizer(amplitudes = service.amplitudes)
}
if (service?.originalRecordingStart != null) if (service?.originalRecordingStart != null)
Column(
modifier = Modifier.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Bottom,
) {
if (hasAmplitudes)
AudioVisualizer(
modifier = Modifier
.height(100.dp)
.padding(bottom = 32.dp),
amplitudes = service.amplitudes,
)
Button( Button(
modifier = Modifier modifier = Modifier
.padding(16.dp)
.fillMaxWidth() .fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE), .height(BIG_PRIMARY_BUTTON_SIZE),
onClick = { onClick = {
@ -104,7 +114,8 @@ fun StartRecording(
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing)) Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text("Save Recording from ${service.originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}") Text("Save Recording from ${service.originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}")
} }
}
else else
Box {} Spacer(modifier = Modifier.weight(1f))
} }
} }

View File

@ -1,7 +1,5 @@
package app.myzel394.locationtest.ui.utils package app.myzel394.locationtest.ui.utils
import androidx.compose.animation.core.Easing
fun clamp(value: Float, min: Float, max: Float): Float { fun clamp(value: Float, min: Float, max: Float): Float {
return value return value