|
|
@@ -0,0 +1,197 @@
|
|
|
+package com.example.torus.ui
|
|
|
+
|
|
|
+import androidx.compose.foundation.BorderStroke
|
|
|
+import androidx.compose.foundation.background
|
|
|
+import androidx.compose.foundation.border
|
|
|
+import androidx.compose.foundation.layout.Arrangement
|
|
|
+import androidx.compose.foundation.layout.Column
|
|
|
+import androidx.compose.foundation.layout.Row
|
|
|
+import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
+import androidx.compose.foundation.layout.padding
|
|
|
+import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
+import androidx.compose.material3.ButtonDefaults
|
|
|
+import androidx.compose.material3.MaterialTheme
|
|
|
+import androidx.compose.material3.OutlinedButton
|
|
|
+import androidx.compose.material3.OutlinedTextField
|
|
|
+import androidx.compose.material3.OutlinedTextFieldDefaults
|
|
|
+import androidx.compose.material3.Text
|
|
|
+import androidx.compose.material3.TextButton
|
|
|
+import androidx.compose.material3.TextFieldColors
|
|
|
+import androidx.compose.runtime.Composable
|
|
|
+import androidx.compose.ui.Alignment
|
|
|
+import androidx.compose.ui.Modifier
|
|
|
+import androidx.compose.ui.res.stringResource
|
|
|
+import androidx.compose.ui.unit.dp
|
|
|
+import com.example.torus.R
|
|
|
+import com.example.torus.model.DraftExercise
|
|
|
+
|
|
|
+fun updateExercise(
|
|
|
+ exercises: MutableList<DraftExercise>,
|
|
|
+ id: String,
|
|
|
+ transform: (DraftExercise) -> DraftExercise
|
|
|
+) {
|
|
|
+ val index = exercises.indexOfFirst { it.id == id }
|
|
|
+ if (index >= 0) {
|
|
|
+ exercises[index] = transform(exercises[index])
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fun moveExercise(exercises: MutableList<DraftExercise>, id: String, offset: Int) {
|
|
|
+ val index = exercises.indexOfFirst { it.id == id }
|
|
|
+ val target = index + offset
|
|
|
+ if (index < 0 || target !in exercises.indices) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ val exercise = exercises.removeAt(index)
|
|
|
+ exercises.add(target, exercise)
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+fun NamedExerciseEditor(
|
|
|
+ number: Int,
|
|
|
+ typeLabel: String,
|
|
|
+ name: String,
|
|
|
+ onNameChange: (String) -> Unit,
|
|
|
+ modifier: Modifier = Modifier,
|
|
|
+ onMoveUp: (() -> Unit)? = null,
|
|
|
+ onMoveDown: (() -> Unit)? = null,
|
|
|
+ onRemove: (() -> Unit)? = null
|
|
|
+) {
|
|
|
+ val shape = RoundedCornerShape(14.dp)
|
|
|
+ Column(
|
|
|
+ modifier = modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .border(1.dp, MaterialTheme.colorScheme.outline, shape)
|
|
|
+ .padding(16.dp),
|
|
|
+ verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
|
+ ) {
|
|
|
+ Row(
|
|
|
+ modifier = Modifier.fillMaxWidth(),
|
|
|
+ horizontalArrangement = Arrangement.SpaceBetween,
|
|
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ text = typeLabel,
|
|
|
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
+ style = MaterialTheme.typography.labelLarge
|
|
|
+ )
|
|
|
+ Text(
|
|
|
+ text = number.toString(),
|
|
|
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
+ style = MaterialTheme.typography.labelSmall
|
|
|
+ )
|
|
|
+ }
|
|
|
+ TorusTextField(
|
|
|
+ value = name,
|
|
|
+ onValueChange = onNameChange,
|
|
|
+ label = stringResource(R.string.exercise_name)
|
|
|
+ )
|
|
|
+ if (onMoveUp != null || onMoveDown != null || onRemove != null) {
|
|
|
+ Row(
|
|
|
+ modifier = Modifier.fillMaxWidth(),
|
|
|
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
+ ) {
|
|
|
+ if (onMoveUp != null) {
|
|
|
+ TextButton(onClick = onMoveUp) {
|
|
|
+ Text(text = stringResource(R.string.move_up))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (onMoveDown != null) {
|
|
|
+ TextButton(onClick = onMoveDown) {
|
|
|
+ Text(text = stringResource(R.string.move_down))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (onRemove != null) {
|
|
|
+ TextButton(onClick = onRemove) {
|
|
|
+ Text(
|
|
|
+ text = stringResource(R.string.remove_exercise),
|
|
|
+ color = MaterialTheme.colorScheme.error
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+fun ExerciseTypePicker(
|
|
|
+ onWeightsClick: () -> Unit,
|
|
|
+ onRunClick: () -> Unit = {}
|
|
|
+) {
|
|
|
+ val shape = RoundedCornerShape(14.dp)
|
|
|
+ Column(
|
|
|
+ modifier = Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .background(MaterialTheme.colorScheme.surfaceVariant, shape)
|
|
|
+ .border(1.dp, MaterialTheme.colorScheme.primary, shape)
|
|
|
+ .padding(16.dp),
|
|
|
+ verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ text = stringResource(R.string.choose_exercise_type),
|
|
|
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
+ style = MaterialTheme.typography.titleSmall
|
|
|
+ )
|
|
|
+ ExerciseTypeOption(
|
|
|
+ label = stringResource(R.string.exercise_type_weights),
|
|
|
+ onClick = onWeightsClick
|
|
|
+ )
|
|
|
+ ExerciseTypeOption(
|
|
|
+ label = stringResource(R.string.exercise_type_run),
|
|
|
+ onClick = onRunClick
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+private fun ExerciseTypeOption(
|
|
|
+ label: String,
|
|
|
+ onClick: () -> Unit = {}
|
|
|
+) {
|
|
|
+ OutlinedButton(
|
|
|
+ onClick = onClick,
|
|
|
+ modifier = Modifier.fillMaxWidth(),
|
|
|
+ shape = RoundedCornerShape(50),
|
|
|
+ colors = ButtonDefaults.outlinedButtonColors(
|
|
|
+ contentColor = MaterialTheme.colorScheme.onBackground
|
|
|
+ ),
|
|
|
+ border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant)
|
|
|
+ ) {
|
|
|
+ Text(text = label)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+fun TorusTextField(
|
|
|
+ value: String,
|
|
|
+ onValueChange: (String) -> Unit,
|
|
|
+ label: String,
|
|
|
+ modifier: Modifier = Modifier
|
|
|
+) {
|
|
|
+ OutlinedTextField(
|
|
|
+ value = value,
|
|
|
+ onValueChange = onValueChange,
|
|
|
+ modifier = modifier.fillMaxWidth(),
|
|
|
+ label = { Text(text = label) },
|
|
|
+ singleLine = true,
|
|
|
+ shape = RoundedCornerShape(14.dp),
|
|
|
+ colors = torusTextFieldColors()
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+private fun torusTextFieldColors(): TextFieldColors {
|
|
|
+ return OutlinedTextFieldDefaults.colors(
|
|
|
+ focusedTextColor = MaterialTheme.colorScheme.onBackground,
|
|
|
+ unfocusedTextColor = MaterialTheme.colorScheme.onBackground,
|
|
|
+ focusedBorderColor = MaterialTheme.colorScheme.primary,
|
|
|
+ unfocusedBorderColor = MaterialTheme.colorScheme.outline,
|
|
|
+ focusedLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
+ unfocusedLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
+ cursorColor = MaterialTheme.colorScheme.primary,
|
|
|
+ focusedContainerColor = MaterialTheme.colorScheme.surface,
|
|
|
+ unfocusedContainerColor = MaterialTheme.colorScheme.surface
|
|
|
+ )
|
|
|
+}
|