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
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.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<Int>,
) {
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)
)
}
}
}

View File

@ -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

View File

@ -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")
}
}

View File

@ -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))
}
}

View File

@ -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