From dde503378409f8fded18a80d7e07d400b5d44636 Mon Sep 17 00:00:00 2001 From: Sad Ellie Date: Tue, 14 Nov 2023 17:46:59 +0300 Subject: [PATCH] Redesign Date calculator pages --- .../addsubtract/AddSubtractPage.kt | 197 +++++++++++------- .../components/DateTimeSelectorBlock.kt | 132 ++++++------ .../components/TimeUnitTextField.kt | 3 +- .../difference/DateDifferencePage.kt | 10 +- 4 files changed, 206 insertions(+), 136 deletions(-) diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt index 9a3073de..8ef1105b 100644 --- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt +++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/addsubtract/AddSubtractPage.kt @@ -25,20 +25,23 @@ import android.content.Intent import android.provider.CalendarContract import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Event @@ -47,6 +50,7 @@ import androidx.compose.material.icons.outlined.Remove import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SegmentedButton import androidx.compose.material3.SegmentedButtonDefaults @@ -142,6 +146,16 @@ private fun AddSubtractView( focusedTextFieldValue = null } + val showResult = remember(uiState.start, uiState.result) { uiState.start != uiState.result } + val inputWidth = animateFloatAsState( + targetValue = if (showResult) 0.5f else 1f, + label = "inputWidth" + ) + val resultWidth = animateFloatAsState( + targetValue = if (showResult) 1f else 0f, + label = "resultWidth" + ) + Column(Modifier.fillMaxSize()) { Scaffold( modifier = Modifier @@ -159,24 +173,23 @@ private fun AddSubtractView( ) } }, - contentWindowInsets = WindowInsets(0,0,0,0) + contentWindowInsets = WindowInsets(0, 0, 0, 0) ) { Column( modifier = Modifier .verticalScroll(rememberScrollState()) - .padding(horizontal = 16.dp), - verticalArrangement = Arrangement.spacedBy(2.dp), + .padding(horizontal = 16.dp, vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), ) { - FlowRow( - modifier = Modifier.padding(vertical = 16.dp), - maxItemsInEachRow = 2, - verticalArrangement = Arrangement.spacedBy(16.dp), - horizontalArrangement = Arrangement.spacedBy(16.dp) + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) ) { DateTimeSelectorBlock( modifier = Modifier - .weight(1f) - .fillMaxWidth(), + .fillMaxWidth(inputWidth.value), + containerColor = MaterialTheme.colorScheme.secondaryContainer, title = stringResource(R.string.date_calculator_start), dateTime = uiState.start, onLongClick = { updateStart(ZonedDateTime.now()) }, @@ -187,8 +200,8 @@ private fun AddSubtractView( DateTimeSelectorBlock( modifier = Modifier - .weight(1f) - .fillMaxWidth(), + .fillMaxWidth(resultWidth.value), + containerColor = MaterialTheme.colorScheme.tertiaryContainer, title = stringResource(R.string.date_calculator_end), dateTime = uiState.result, ) @@ -212,74 +225,110 @@ private fun AddSubtractView( shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2), icon = {} ) { - Icon(Icons.Outlined.Remove, stringResource(R.string.date_calculator_subtract)) + Icon( + Icons.Outlined.Remove, + stringResource(R.string.date_calculator_subtract) + ) } } - TimeUnitTextField( - modifier = Modifier.onFocusEvent { - if (it.hasFocus) { - addSymbol = updateYears - focusedTextFieldValue = uiState.years - } - }, - value = uiState.years, - onValueChange = updateYears, - label = stringResource(R.string.date_calculator_years), - formatterSymbols = uiState.formatterSymbols - ) + Column( + modifier = Modifier + .fillMaxWidth() + .background( + MaterialTheme.colorScheme.secondaryContainer, + RoundedCornerShape(32.dp) + ) + .padding(16.dp, 24.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + TimeUnitTextField( + modifier = Modifier + .onFocusEvent { + if (it.hasFocus) { + addSymbol = updateYears + focusedTextFieldValue = uiState.years + } + } + .fillMaxWidth(), + value = uiState.years, + onValueChange = updateYears, + label = stringResource(R.string.date_calculator_years), + formatterSymbols = uiState.formatterSymbols + ) - TimeUnitTextField( - modifier = Modifier.onFocusEvent { - if (it.hasFocus) { - addSymbol = updateMonths - focusedTextFieldValue = uiState.months - } - }, - value = uiState.months, - onValueChange = updateMonths, - label = stringResource(R.string.date_calculator_months), - formatterSymbols = uiState.formatterSymbols - ) + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + TimeUnitTextField( + modifier = Modifier + .onFocusEvent { + if (it.hasFocus) { + addSymbol = updateMonths + focusedTextFieldValue = uiState.months + } + } + .weight(1f), + value = uiState.months, + onValueChange = updateMonths, + label = stringResource(R.string.date_calculator_months), + formatterSymbols = uiState.formatterSymbols + ) - TimeUnitTextField( - modifier = Modifier.onFocusEvent { - if (it.hasFocus) { - addSymbol = updateDays - focusedTextFieldValue = uiState.days - } - }, - value = uiState.days, - onValueChange = updateDays, - label = stringResource(R.string.date_calculator_days), - formatterSymbols = uiState.formatterSymbols - ) + TimeUnitTextField( + modifier = Modifier + .onFocusEvent { + if (it.hasFocus) { + addSymbol = updateDays + focusedTextFieldValue = uiState.days + } + } + .weight(1f), + value = uiState.days, + onValueChange = updateDays, + label = stringResource(R.string.date_calculator_days), + formatterSymbols = uiState.formatterSymbols + ) + } - TimeUnitTextField( - modifier = Modifier.onFocusEvent { - if (it.hasFocus) { - addSymbol = updateHours - focusedTextFieldValue = uiState.hours - } - }, - value = uiState.hours, - onValueChange = updateHours, - label = stringResource(R.string.date_calculator_hours), - formatterSymbols = uiState.formatterSymbols - ) + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + TimeUnitTextField( + modifier = Modifier + .onFocusEvent { + if (it.hasFocus) { + addSymbol = updateHours + focusedTextFieldValue = uiState.hours + } + } + .weight(1f), + value = uiState.hours, + onValueChange = updateHours, + label = stringResource(R.string.date_calculator_hours), + formatterSymbols = uiState.formatterSymbols + ) - TimeUnitTextField( - modifier = Modifier.onFocusEvent { - if (it.hasFocus) { - addSymbol = updateMinutes - focusedTextFieldValue = uiState.minutes - } - }, - value = uiState.minutes, - onValueChange = updateMinutes, - label = stringResource(R.string.date_calculator_minutes), - formatterSymbols = uiState.formatterSymbols - ) + TimeUnitTextField( + modifier = Modifier + .onFocusEvent { + if (it.hasFocus) { + addSymbol = updateMinutes + focusedTextFieldValue = uiState.minutes + } + } + .weight(1f), + value = uiState.minutes, + onValueChange = updateMinutes, + label = stringResource(R.string.date_calculator_minutes), + formatterSymbols = uiState.formatterSymbols + ) + } + } } } AnimatedVisibility( diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/DateTimeSelectorBlock.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/DateTimeSelectorBlock.kt index 6ae6ead3..6cfbe9e7 100644 --- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/DateTimeSelectorBlock.kt +++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/DateTimeSelectorBlock.kt @@ -35,14 +35,17 @@ import androidx.compose.foundation.layout.width import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.sadellie.unitto.core.ui.LocalLocale +import com.sadellie.unitto.core.ui.common.ProvideColor import com.sadellie.unitto.core.ui.common.squashable import com.sadellie.unitto.core.ui.datetime.formatDateWeekDayMonthYear import com.sadellie.unitto.core.ui.datetime.formatTimeAmPm @@ -52,6 +55,7 @@ import java.time.ZonedDateTime @Composable internal fun DateTimeSelectorBlock( modifier: Modifier = Modifier, + containerColor: Color, title: String, dateTime: ZonedDateTime, onClick: () -> Unit = {}, @@ -62,44 +66,35 @@ internal fun DateTimeSelectorBlock( val locale = LocalLocale.current val is24Hour = DateFormat.is24HourFormat(LocalContext.current) - Column( - modifier = modifier - .squashable( - onClick = onClick, - onLongClick = onLongClick, - interactionSource = remember { MutableInteractionSource() }, - cornerRadiusRange = 8.dp..32.dp - ) - .background(MaterialTheme.colorScheme.secondaryContainer) - .padding(16.dp), - horizontalAlignment = Alignment.Start + ProvideColor( + MaterialTheme.colorScheme.contentColorFor(containerColor) ) { - Text(title, style = MaterialTheme.typography.labelMedium) - Column( - modifier = Modifier.clickable( - indication = rememberRipple(), - interactionSource = remember { MutableInteractionSource() }, - onClick = onTimeClick - ) - ) { - AnimatedContent( - targetState = dateTime, - transitionSpec = { - slideInVertically { height -> height } + fadeIn() togetherWith - slideOutVertically { height -> -height } + fadeOut() using - SizeTransform() - }, - label = "Animated time", - ) { time -> - Text( - text = time.formatTimeShort(locale, is24Hour), - style = MaterialTheme.typography.displaySmall, - maxLines = 1 + modifier = Modifier + .squashable( + onClick = onClick, + onLongClick = onLongClick, + interactionSource = remember { MutableInteractionSource() }, + cornerRadiusRange = 8.dp..32.dp ) - } + .background(containerColor) + .then(modifier) + .padding(16.dp), + horizontalAlignment = Alignment.Start + ) { + Text( + text = title, + style = MaterialTheme.typography.labelMedium, + maxLines = 1, + ) - if (!is24Hour) { + Column( + modifier = Modifier.clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() }, + onClick = onTimeClick + ) + ) { AnimatedContent( targetState = dateTime, transitionSpec = { @@ -107,35 +102,54 @@ internal fun DateTimeSelectorBlock( slideOutVertically { height -> -height } + fadeOut() using SizeTransform() }, - label = "Animated am/pm", + label = "Animated time", ) { time -> Text( - text = time.formatTimeAmPm(locale), - style = MaterialTheme.typography.bodyLarge, + text = time.formatTimeShort(locale, is24Hour), + style = MaterialTheme.typography.displaySmall, maxLines = 1 ) } - } - } - AnimatedContent( - targetState = dateTime, - transitionSpec = { - slideInVertically { height -> height } + fadeIn() togetherWith - slideOutVertically { height -> -height } + fadeOut() using - SizeTransform() - }, - label = "Animated date", - ) { date -> - Text( - modifier = Modifier.clickable( - indication = rememberRipple(), - interactionSource = remember { MutableInteractionSource() }, - onClick = onDateClick - ), - text = date.formatDateWeekDayMonthYear(locale), - style = MaterialTheme.typography.bodySmall - ) + if (!is24Hour) { + AnimatedContent( + targetState = dateTime, + transitionSpec = { + slideInVertically { height -> height } + fadeIn() togetherWith + slideOutVertically { height -> -height } + fadeOut() using + SizeTransform() + }, + label = "Animated am/pm", + ) { time -> + Text( + text = time.formatTimeAmPm(locale), + style = MaterialTheme.typography.bodyLarge, + maxLines = 1 + ) + } + } + } + + AnimatedContent( + targetState = dateTime, + transitionSpec = { + slideInVertically { height -> height } + fadeIn() togetherWith + slideOutVertically { height -> -height } + fadeOut() using + SizeTransform() + }, + label = "Animated date", + ) { date -> + Text( + modifier = Modifier.clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() }, + onClick = onDateClick + ), + text = date.formatDateWeekDayMonthYear(locale), + style = MaterialTheme.typography.bodySmall, + maxLines = 1 + ) + } } } } @@ -144,8 +158,10 @@ internal fun DateTimeSelectorBlock( @Composable fun DateTimeSelectorBlockPreview() { DateTimeSelectorBlock( + modifier = Modifier + .width(224.dp), + containerColor = MaterialTheme.colorScheme.secondaryContainer, title = "End", dateTime = ZonedDateTime.now(), - modifier = Modifier.width(224.dp) ) } diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt index 8e63858e..8507c138 100644 --- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt +++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/components/TimeUnitTextField.kt @@ -21,7 +21,6 @@ package com.sadellie.unitto.feature.datecalculator.components import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Clear import androidx.compose.material3.Icon @@ -46,7 +45,7 @@ internal fun TimeUnitTextField( formatterSymbols: FormatterSymbols ) = CompositionLocalProvider(LocalTextInputService provides null) { OutlinedTextField( - modifier = modifier.fillMaxWidth(), + modifier = modifier, value = value, onValueChange = { newValue -> onValueChange(newValue.copy(newValue.text.filter { it.isDigit() })) diff --git a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/difference/DateDifferencePage.kt b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/difference/DateDifferencePage.kt index d93f5ef0..f1075d17 100644 --- a/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/difference/DateDifferencePage.kt +++ b/feature/datecalculator/src/main/java/com/sadellie/unitto/feature/datecalculator/difference/DateDifferencePage.kt @@ -21,12 +21,14 @@ package com.sadellie.unitto.feature.datecalculator.difference import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -72,11 +74,12 @@ private fun DateDifferenceView( .fillMaxSize() .padding(16.dp), maxItemsInEachRow = 2, - verticalArrangement = Arrangement.spacedBy(16.dp), - horizontalArrangement = Arrangement.spacedBy(16.dp) + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) ) { DateTimeSelectorBlock( modifier = Modifier + .background(MaterialTheme.colorScheme.secondaryContainer) .weight(1f) .fillMaxWidth(), title = stringResource(R.string.date_calculator_start), @@ -85,10 +88,12 @@ private fun DateDifferenceView( onLongClick = { setStartDate(ZonedDateTime.now()) }, onTimeClick = { dialogState = DialogState.FROM_TIME }, onDateClick = { dialogState = DialogState.FROM_DATE }, + containerColor = MaterialTheme.colorScheme.secondaryContainer ) DateTimeSelectorBlock( modifier = Modifier + .background(MaterialTheme.colorScheme.secondaryContainer) .weight(1f) .fillMaxWidth(), title = stringResource(R.string.date_calculator_end), @@ -97,6 +102,7 @@ private fun DateDifferenceView( onLongClick = { setStartDate(ZonedDateTime.now()) }, onTimeClick = { dialogState = DialogState.TO_TIME }, onDateClick = { dialogState = DialogState.TO_DATE }, + containerColor = MaterialTheme.colorScheme.secondaryContainer ) AnimatedVisibility(