Skip to content

Commit

Permalink
Improve recipe time input field behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
lneugebauer committed Aug 19, 2023
1 parent 4e6288f commit f5a02ba
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 86 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.lukasneugebauer.nextcloudcookbook.recipe.domain.model

data class DurationComponents(
val hours: String = "",
val minutes: String = "",
) {
fun toIsoStringOrNull(): String? {
if (hours.isBlank() && minutes.isBlank() || hours == "0" && minutes == "0") return null
return "PT${hours.ifBlank { "0" }}H${minutes.ifBlank { "0" }}M0S"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ package de.lukasneugebauer.nextcloudcookbook.recipe.domain.state

import de.lukasneugebauer.nextcloudcookbook.category.domain.model.Category
import de.lukasneugebauer.nextcloudcookbook.core.util.UiText
import de.lukasneugebauer.nextcloudcookbook.recipe.domain.model.DurationComponents
import de.lukasneugebauer.nextcloudcookbook.recipe.domain.model.Recipe

typealias DurationComponents = Pair<String, String>

sealed interface RecipeCreateEditState {
object Loading : RecipeCreateEditState
data class Success(
val recipe: Recipe,
val prepTime: DurationComponents,
val cookTime: DurationComponents,
val totalTime: DurationComponents,
val categories: List<Category> = emptyList(),
) : RecipeCreateEditState
data class Updated(val recipeId: Int) : RecipeCreateEditState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,26 @@ import de.lukasneugebauer.nextcloudcookbook.core.presentation.components.Default
import de.lukasneugebauer.nextcloudcookbook.core.presentation.components.Gap
import de.lukasneugebauer.nextcloudcookbook.core.presentation.ui.theme.NcBlue700
import de.lukasneugebauer.nextcloudcookbook.core.presentation.ui.theme.NextcloudCookbookTheme
import de.lukasneugebauer.nextcloudcookbook.recipe.domain.model.DurationComponents
import de.lukasneugebauer.nextcloudcookbook.recipe.domain.model.Recipe
import de.lukasneugebauer.nextcloudcookbook.recipe.domain.state.DurationComponents
import java.time.Duration

@Composable
fun CreateEditRecipeForm(
recipe: Recipe,
prepTime: DurationComponents,
cookTime: DurationComponents,
totalTime: DurationComponents,
categories: List<Category>,
@StringRes title: Int,
onNavIconClick: () -> Unit,
onNameChanged: (name: String) -> Unit,
onDescriptionChanged: (description: String) -> Unit,
onUrlChanged: (url: String) -> Unit,
onImageOriginChanged: (imageUrl: String) -> Unit,
onPrepTimeChanged: (hours: String, minutes: String) -> Unit,
onCookTimeChanged: (time: String) -> Unit,
onTotalTimeChanged: (time: String) -> Unit,
onPrepTimeChanged: (time: DurationComponents) -> Unit,
onCookTimeChanged: (time: DurationComponents) -> Unit,
onTotalTimeChanged: (time: DurationComponents) -> Unit,
onCategoryChanged: (category: String) -> Unit,
onYieldChanged: (yield: String) -> Unit,
onIngredientChanged: (index: Int, ingredient: String) -> Unit,
Expand Down Expand Up @@ -136,19 +138,19 @@ fun CreateEditRecipeForm(
textFieldColors = textFieldColors,
)
PrepTime(
prepTime = prepTime,
focusManager = focusManager,
onPrepTimeChange = onPrepTimeChanged,
prepTime = prepTime,
textFieldColors = textFieldColors,
)
CookTime(
recipe = recipe,
cookTime = cookTime,
focusManager = focusManager,
onCookTimeChange = onCookTimeChanged,
textFieldColors = textFieldColors,
)
TotalTime(
recipe = recipe,
totalTime = totalTime,
focusManager = focusManager,
onTotalTimeChange = onTotalTimeChanged,
textFieldColors = textFieldColors,
Expand Down Expand Up @@ -323,20 +325,14 @@ private fun ImageOrigin(

@Composable
private fun PrepTime(
focusManager: FocusManager,
onPrepTimeChange: (hours: String, minutes: String) -> Unit,
prepTime: DurationComponents,
focusManager: FocusManager,
onPrepTimeChange: (time: DurationComponents) -> Unit,
textFieldColors: TextFieldColors,
) {
TimeTextField(
hours = prepTime.first,
minutes = prepTime.second,
onHoursChange = {
onPrepTimeChange.invoke(it, prepTime.second)
},
onMinutesChange = {
onPrepTimeChange.invoke(prepTime.first, it)
},
time = prepTime,
onTimeChange = onPrepTimeChange,
label = R.string.recipe_prep_time,
modifier = Modifier
.fillMaxWidth()
Expand All @@ -357,24 +353,14 @@ private fun PrepTime(

@Composable
private fun CookTime(
recipe: Recipe,
cookTime: DurationComponents,
focusManager: FocusManager,
onCookTimeChange: (time: String) -> Unit,
onCookTimeChange: (time: DurationComponents) -> Unit,
textFieldColors: TextFieldColors,
) {
TimeTextField(
hours = recipe.cookTime?.toHoursPart()?.toString() ?: "",
minutes = recipe.cookTime?.toMinutesPart()?.toString() ?: "",
onHoursChange = {
val hours = it.ifBlank { "0" }
val minutes = recipe.cookTime?.toMinutesPart() ?: 0
onCookTimeChange.invoke("PT${hours}H${minutes}M0S")
},
onMinutesChange = {
val hours = recipe.cookTime?.toHoursPart() ?: 0
val minutes = it.ifBlank { "0" }
onCookTimeChange.invoke("PT${hours}H${minutes}M0S")
},
time = cookTime,
onTimeChange = onCookTimeChange,
label = R.string.recipe_cook_time,
modifier = Modifier
.fillMaxWidth()
Expand All @@ -395,24 +381,14 @@ private fun CookTime(

@Composable
private fun TotalTime(
recipe: Recipe,
totalTime: DurationComponents,
focusManager: FocusManager,
onTotalTimeChange: (time: String) -> Unit,
onTotalTimeChange: (time: DurationComponents) -> Unit,
textFieldColors: TextFieldColors,
) {
TimeTextField(
hours = recipe.totalTime?.toHoursPart()?.toString() ?: "",
minutes = recipe.totalTime?.toMinutesPart()?.toString() ?: "",
onHoursChange = {
val hours = it.ifBlank { "0" }
val minutes = recipe.totalTime?.toMinutesPart() ?: 0
onTotalTimeChange.invoke("PT${hours}H${minutes}M0S")
},
onMinutesChange = {
val hours = recipe.totalTime?.toHoursPart() ?: 0
val minutes = it.ifBlank { "0" }
onTotalTimeChange.invoke("PT${hours}H${minutes}M0S")
},
time = totalTime,
onTimeChange = onTotalTimeChange,
label = R.string.recipe_total_time,
modifier = Modifier
.fillMaxWidth()
Expand Down Expand Up @@ -703,15 +679,17 @@ private fun CreateEditRecipeFormPreview() {
NextcloudCookbookTheme {
CreateEditRecipeForm(
recipe = recipe,
prepTime = DurationComponents("1", "50"),
prepTime = DurationComponents("0", "25"),
cookTime = DurationComponents("1", "50"),
totalTime = DurationComponents("2", "15"),
categories = categories,
title = R.string.recipe_new,
onNavIconClick = {},
onNameChanged = {},
onDescriptionChanged = {},
onUrlChanged = {},
onImageOriginChanged = {},
onPrepTimeChanged = {_, _ -> },
onPrepTimeChanged = {},
onCookTimeChanged = {},
onTotalTimeChanged = {},
onCategoryChanged = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import de.lukasneugebauer.nextcloudcookbook.R
import de.lukasneugebauer.nextcloudcookbook.core.presentation.ui.theme.NextcloudCookbookTheme
import de.lukasneugebauer.nextcloudcookbook.recipe.domain.model.DurationComponents

@Composable
fun TimeTextField(
hours: String,
minutes: String,
onHoursChange: (hours: String) -> Unit,
onMinutesChange: (minutes: String) -> Unit,
time: DurationComponents,
onTimeChange: (time: DurationComponents) -> Unit,
@StringRes label: Int,
modifier: Modifier = Modifier,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors(
Expand All @@ -53,8 +52,8 @@ fun TimeTextField(
verticalAlignment = Alignment.CenterVertically,
) {
OutlinedTextField(
value = hours,
onValueChange = onHoursChange,
value = time.hours,
onValueChange = { onTimeChange(DurationComponents(it, time.minutes)) },
modifier = Modifier.weight(1f),
label = { Text(text = stringResource(id = R.string.common_hours)) },
keyboardOptions = KeyboardOptions.Default.copy(
Expand All @@ -67,8 +66,8 @@ fun TimeTextField(
)
Text(text = ":")
OutlinedTextField(
value = minutes,
onValueChange = onMinutesChange,
value = time.minutes,
onValueChange = { onTimeChange(DurationComponents(time.hours, it)) },
modifier = Modifier.weight(1f),
label = { Text(text = stringResource(id = R.string.common_minutes)) },
keyboardOptions = KeyboardOptions.Default.copy(
Expand All @@ -88,10 +87,8 @@ fun TimeTextField(
private fun TimeTextFieldPreview() {
NextcloudCookbookTheme {
TimeTextField(
hours = "1",
minutes = "25",
onHoursChange = {},
onMinutesChange = {},
time = DurationComponents("1", "25"),
onTimeChange = {},
label = R.string.recipe_cook_time,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ fun RecipeCreateScreen(
is RecipeCreateEditState.Success -> {
val recipe = (uiState as RecipeCreateEditState.Success).recipe
val prepTime = (uiState as RecipeCreateEditState.Success).prepTime
val cookTime = (uiState as RecipeCreateEditState.Success).cookTime
val totalTime = (uiState as RecipeCreateEditState.Success).totalTime
val categories = (uiState as RecipeCreateEditState.Success).categories

CreateEditRecipeForm(
recipe = recipe,
prepTime = prepTime,
cookTime = cookTime,
totalTime = totalTime,
categories = categories,
title = R.string.recipe_new,
title = R.string.recipe_edit,
onNavIconClick = { navigator.popBackStack() },
onNameChanged = { newName ->
viewModel.changeName(newName)
Expand All @@ -47,8 +51,8 @@ fun RecipeCreateScreen(
onImageOriginChanged = { newImageUrl ->
viewModel.changeImageOrigin(newImageUrl)
},
onPrepTimeChanged = { hours, minutes ->
viewModel.changePrepTime(hours, minutes)
onPrepTimeChanged = { newPrepTime ->
viewModel.changePrepTime(newPrepTime)
},
onCookTimeChanged = { newCookTime ->
viewModel.changeCookTime(newCookTime)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ fun RecipeEditScreen(
is RecipeCreateEditState.Success -> {
val recipe = (uiState as RecipeCreateEditState.Success).recipe
val prepTime = (uiState as RecipeCreateEditState.Success).prepTime
val cookTime = (uiState as RecipeCreateEditState.Success).cookTime
val totalTime = (uiState as RecipeCreateEditState.Success).totalTime
val categories = (uiState as RecipeCreateEditState.Success).categories

CreateEditRecipeForm(
recipe = recipe,
prepTime = prepTime,
cookTime = cookTime,
totalTime = totalTime,
categories = categories,
title = R.string.recipe_edit,
onNavIconClick = { navigator.popBackStack() },
Expand All @@ -48,8 +52,8 @@ fun RecipeEditScreen(
onImageOriginChanged = { newImageUrl ->
viewModel.changeImageOrigin(newImageUrl)
},
onPrepTimeChanged = { hours, minutes ->
viewModel.changePrepTime(hours, minutes)
onPrepTimeChanged = { newPrepTime ->
viewModel.changePrepTime(newPrepTime)
},
onCookTimeChanged = { newCookTime ->
viewModel.changeCookTime(newCookTime)
Expand Down Expand Up @@ -95,6 +99,7 @@ fun RecipeEditScreen(
},
)
}

is RecipeCreateEditState.Updated -> resultNavigator.navigateBack(true)
is RecipeCreateEditState.Error -> {
val text = (uiState as RecipeCreateEditState.Error).error.asString()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.lukasneugebauer.nextcloudcookbook.recipe.util

import de.lukasneugebauer.nextcloudcookbook.recipe.domain.model.DurationComponents
import java.time.Duration
import kotlin.time.toKotlinDuration

fun Duration.toDurationComponents(): DurationComponents = this.toKotlinDuration().toComponents { hours, minutes, _, _ ->
return DurationComponents(hours.toString(), minutes.toString())
}
Loading

0 comments on commit f5a02ba

Please sign in to comment.