Less garbage and bad decisions in code

This commit is contained in:
sadellie 2023-08-03 14:29:39 +03:00
parent e03fa61a17
commit 588474529f
18 changed files with 82 additions and 168 deletions

View File

@ -153,11 +153,11 @@ fun DatePickerDialog(
Box(modifier = Modifier
.align(Alignment.End)
.padding(DialogButtonsPadding)) {
.padding(_dialogButtonsPadding)) {
AlertDialogFlowRow(
mainAxisSpacing = DialogButtonsMainAxisSpacing,
crossAxisSpacing = DialogButtonsCrossAxisSpacing
mainAxisSpacing = _dialogButtonsMainAxisSpacing,
crossAxisSpacing = _dialogButtonsCrossAxisSpacing
) {
TextButton(
onClick = onDismiss
@ -277,6 +277,6 @@ private fun AlertDialogFlowRow(
}
}
private val DialogButtonsPadding by lazy { PaddingValues(bottom = 8.dp, end = 6.dp) }
private val DialogButtonsMainAxisSpacing by lazy { 8.dp }
private val DialogButtonsCrossAxisSpacing by lazy { 12.dp }
private val _dialogButtonsPadding by lazy { PaddingValues(bottom = 8.dp, end = 6.dp) }
private val _dialogButtonsMainAxisSpacing by lazy { 8.dp }
private val _dialogButtonsCrossAxisSpacing by lazy { 12.dp }

View File

@ -46,6 +46,7 @@ fun Modifier.squashable(
val cornerRadius: Int by animateIntAsState(
targetValue = if (isPressed) cornerRadiusRange.first else cornerRadiusRange.last,
animationSpec = tween(easing = FastOutSlowInEasing),
label = "Squashed animation"
)
Modifier
@ -72,6 +73,7 @@ fun Modifier.squashable(
val cornerRadius: Dp by animateDpAsState(
targetValue = if (isPressed) cornerRadiusRange.start else cornerRadiusRange.endInclusive,
animationSpec = tween(easing = FastOutSlowInEasing),
label = "Squashed animation"
)
Modifier

View File

@ -19,7 +19,7 @@
package com.sadellie.unitto.core.ui.common
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Divider
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.NavigationDrawerItemDefaults
@ -64,7 +64,7 @@ fun UnittoDrawerSheet(
)
}
Divider(Modifier.padding(28.dp, 16.dp))
HorizontalDivider(Modifier.padding(28.dp, 16.dp))
additionalTabs.forEach { drawerItem ->
val selected = drawerItem.destination.start == currentDestination

View File

@ -18,35 +18,15 @@
package com.sadellie.unitto.core.ui.common
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowDropDown
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.R
/**
* Represents one item in list on Settings screen.
@ -83,83 +63,3 @@ fun UnittoListItem(
}
)
}
/**
* Represents one item in list on Settings screen with drop-down menu.
*
* @param label Main text.
* @param supportText Text that is located below label.
* @param allOptions Options in drop-down menu. Key is option itself and value is the string that
* will be shown.
* @param selected Selected option.
* @param onSelectedChange Action to perform when drop-down menu item is selected.
*/
@Composable
fun <T> UnittoListItem(
label: String,
supportText: String? = null,
allOptions: Map<T, String>,
leadingContent: @Composable (() -> Unit)?,
selected: T,
onSelectedChange: (T) -> Unit
) {
var dropDownExpanded by rememberSaveable { mutableStateOf(false) }
var currentOption by rememberSaveable { mutableStateOf(selected) }
val dropDownRotation: Float by animateFloatAsState(
targetValue = if (dropDownExpanded) 180f else 0f,
animationSpec = tween(easing = FastOutSlowInEasing)
)
ListItem(
headlineContent = { Text(label) },
supportingContent = { supportText?.let { Text(text = it) } },
leadingContent = leadingContent,
trailingContent = {
ExposedDropdownMenuBox(
modifier = Modifier,
expanded = dropDownExpanded,
onExpandedChange = { dropDownExpanded = it }
) {
OutlinedTextField(
modifier = Modifier
.menuAnchor()
.widthIn(1.dp),
value = allOptions[currentOption] ?: selected.toString(),
onValueChange = {},
readOnly = true,
singleLine = true,
enabled = false,
textStyle = MaterialTheme.typography.bodyLarge,
colors = OutlinedTextFieldDefaults.colors(
disabledTextColor = MaterialTheme.colorScheme.onSurface,
disabledBorderColor = MaterialTheme.colorScheme.outline,
disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
),
trailingIcon = {
Icon(
imageVector = Icons.Outlined.ArrowDropDown,
modifier = Modifier.rotate(dropDownRotation),
contentDescription = stringResource(R.string.drop_down_description)
)
}
)
ExposedDropdownMenu(
modifier = Modifier.exposedDropdownSize(),
expanded = dropDownExpanded,
onDismissRequest = { dropDownExpanded = false }
) {
allOptions.forEach {
DropdownMenuItem(
text = { Text(it.value) },
onClick = {
currentOption = it.key
onSelectedChange(it.key)
dropDownExpanded = false
}
)
}
}
}
}
)
}

View File

@ -70,13 +70,13 @@ fun UnittoSearchBar(
scrollBehavior: TopAppBarScrollBehavior? = null,
colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors()
) {
var showSearch by remember { mutableStateOf(false) }
var showSearchInput by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() }
fun stagedNavigateUp() {
if (showSearch) {
if (showSearchInput) {
// Search text field is open, need to close it and clear search query
showSearch = false
showSearchInput = false
// focusManager.clearFocus()
onQueryChange("")
} else {
@ -88,8 +88,8 @@ fun UnittoSearchBar(
TopAppBar(
modifier = modifier,
title = {
Crossfade(showSearch) { _showSearch ->
if (_showSearch) {
Crossfade(showSearchInput) { showSearch ->
if (showSearch) {
LaunchedEffect(Unit) { focusRequester.requestFocus() }
SearchTextField(
@ -113,13 +113,13 @@ fun UnittoSearchBar(
NavigateUpButton { stagedNavigateUp() }
},
actions = {
Crossfade(showSearch) { _showSearch ->
Crossfade(showSearchInput) { showSearch ->
Row(verticalAlignment = Alignment.CenterVertically) {
if (_showSearch) {
if (showSearch) {
ClearButton(visible = query.isNotEmpty()) { onQueryChange("") }
searchActions()
} else {
SearchButton { showSearch = true }
SearchButton { showSearchInput = true }
noSearchActions()
}
}

View File

@ -59,7 +59,8 @@ fun UnittoSlider(
) {
val animated = animateFloatAsState(
targetValue = value.roundToInt().toFloat(),
animationSpec = spring()
animationSpec = spring(),
label = "Thumb animation"
)
Slider(
@ -82,7 +83,11 @@ private fun SquigglyTrack(
) {
val coroutineScope = rememberCoroutineScope()
var direct by remember { mutableFloatStateOf(0.72f) }
val animatedDirect = animateFloatAsState(direct, spring(stiffness = Spring.StiffnessLow))
val animatedDirect = animateFloatAsState(
targetValue = direct,
animationSpec = spring(stiffness = Spring.StiffnessLow),
label = "Track animation"
)
LaunchedEffect(sliderState.value) {
coroutineScope.launch {

View File

@ -21,9 +21,9 @@ package com.sadellie.unitto.core.ui.common.textfield
import com.sadellie.unitto.core.base.Separator
sealed class FormatterSymbols(val grouping: String, val fractional: String) {
object Spaces : FormatterSymbols(" ", ".")
object Period : FormatterSymbols(".", ",")
object Comma : FormatterSymbols(",", ".")
data object Spaces : FormatterSymbols(" ", ".")
data object Period : FormatterSymbols(".", ",")
data object Comma : FormatterSymbols(",", ".")
}
object AllFormatterSymbols {

View File

@ -37,31 +37,31 @@ sealed class DrawerItems(
val selectedIcon: ImageVector,
val defaultIcon: ImageVector
) {
object Calculator : DrawerItems(
data object Calculator : DrawerItems(
destination = TopLevelDestinations.Calculator,
selectedIcon = Icons.Filled.Calculate,
defaultIcon = Icons.Outlined.Calculate
)
object Converter : DrawerItems(
data object Converter : DrawerItems(
destination = TopLevelDestinations.Converter,
selectedIcon = Icons.Filled.SwapHoriz,
defaultIcon = Icons.Outlined.SwapHoriz
)
object DateDifference : DrawerItems(
data object DateDifference : DrawerItems(
destination = TopLevelDestinations.DateCalculator,
selectedIcon = Icons.Filled.Event,
defaultIcon = Icons.Outlined.Event
)
object TimeZones : DrawerItems(
data object TimeZones : DrawerItems(
destination = TopLevelDestinations.TimeZone,
selectedIcon = Icons.Filled.Schedule,
defaultIcon = Icons.Outlined.Schedule
)
object Settings : DrawerItems(
data object Settings : DrawerItems(
destination = TopLevelDestinations.Settings,
selectedIcon = Icons.Filled.Settings,
defaultIcon = Icons.Outlined.Settings

View File

@ -36,6 +36,6 @@ data class CalculatorUIState(
sealed class CalculationResult(@StringRes val label: Int? = null) {
data class Default(val text: String = "") : CalculationResult()
object DivideByZeroError : CalculationResult(R.string.divide_by_zero_error)
object Error : CalculationResult(R.string.error_label)
data object DivideByZeroError : CalculationResult(R.string.divide_by_zero_error)
data object Error : CalculationResult(R.string.error_label)
}

View File

@ -158,7 +158,8 @@ private fun PortraitKeyboard(
var invMode: Boolean by remember { mutableStateOf(false) }
val expandRotation: Float by animateFloatAsState(
targetValue = if (showAdditional) 0f else 180f,
animationSpec = tween(easing = FastOutSlowInEasing)
animationSpec = tween(easing = FastOutSlowInEasing),
label = "Rotate on expand"
)
ColumnWithConstraints(

View File

@ -60,6 +60,6 @@ sealed class ConversionResult {
data class Default(val result: String) : ConversionResult()
data class Time(val result: String) : ConversionResult()
data class NumberBase(val result: String) : ConversionResult()
object Loading : ConversionResult()
object Error : ConversionResult()
data object Loading : ConversionResult()
data object Error : ConversionResult()
}

View File

@ -103,7 +103,8 @@ internal fun TopScreenPart(
var swapped by remember { mutableStateOf(false) }
val swapButtonRotation: Float by animateFloatAsState(
targetValue = if (swapped) 0f else 180f,
animationSpec = tween(easing = FastOutSlowInEasing)
animationSpec = tween(easing = FastOutSlowInEasing),
label = "Swap button rotation"
)
val mContext = LocalContext.current
@ -165,7 +166,8 @@ internal fun TopScreenPart(
(expandHorizontally(clip = false, expandFrom = Alignment.Start) + fadeIn()
togetherWith fadeOut())
.using(SizeTransform(clip = false))
}
},
label = "Animated short name from"
) { value ->
Text(
text = value,
@ -262,7 +264,8 @@ internal fun TopScreenPart(
// Exit animation
togetherWith fadeOut())
.using(SizeTransform(clip = false))
}
},
label = "Animated short label to"
) { value ->
Text(
text = value,

View File

@ -73,12 +73,12 @@ internal fun DateTimeSelectorBlock(
if (DateFormat.is24HourFormat(LocalContext.current)) {
AnimatedContent(
targetState = dateTime.format(UnittoDateTimeFormatter.time24Formatter),
label = "date time change",
transitionSpec = {
slideInVertically { height -> height } + fadeIn() togetherWith
slideOutVertically { height -> -height } + fadeOut() using
SizeTransform()
}
},
label = "Animated 24 hour",
) { time ->
Text(
modifier = Modifier.clickable(
@ -105,7 +105,8 @@ internal fun DateTimeSelectorBlock(
slideInVertically { height -> height } + fadeIn() togetherWith
slideOutVertically { height -> -height } + fadeOut() using
SizeTransform()
}
},
label = "Animated 12 hour",
) { time ->
Text(
text = time.format(UnittoDateTimeFormatter.time12Formatter1),
@ -120,7 +121,8 @@ internal fun DateTimeSelectorBlock(
slideInVertically { height -> height } + fadeIn() togetherWith
slideOutVertically { height -> -height } + fadeOut() using
SizeTransform()
}
},
label = "Animated am/pm",
) { time ->
Text(
text = time.format(UnittoDateTimeFormatter.time12Formatter2),
@ -137,7 +139,8 @@ internal fun DateTimeSelectorBlock(
slideInVertically { height -> height } + fadeIn() togetherWith
slideOutVertically { height -> -height } + fadeOut() using
SizeTransform()
}
},
label = "Animated date",
) { date ->
Text(
modifier = Modifier.clickable(

View File

@ -42,7 +42,7 @@ internal sealed class ZonedDateTimeDifference(
minutes = minutes,
)
object Zero : ZonedDateTimeDifference()
data object Zero : ZonedDateTimeDifference()
}
// https://stackoverflow.com/a/25760725

View File

@ -82,8 +82,9 @@ internal fun LeftSideScreen(
}
val chipsBackground = animateColorAsState(
if (needToTint) elevatedColor else MaterialTheme.colorScheme.surface,
tween(durationMillis = 500, easing = LinearOutSlowInEasing)
targetValue = if (needToTint) elevatedColor else MaterialTheme.colorScheme.surface,
animationSpec = tween(durationMillis = 500, easing = LinearOutSlowInEasing),
label = "Chips background",
)
Scaffold(
@ -99,10 +100,9 @@ internal fun LeftSideScreen(
title = stringResource(R.string.units_screen_from),
placeholder = stringResource(R.string.search_bar_placeholder),
noSearchActions = {
FavoritesButton(
favoritesOnly = uiState.value.favoritesOnly,
favoriteAction = { viewModel.toggleFavoritesOnly(false) }
)
FavoritesButton(uiState.value.favoritesOnly) {
viewModel.toggleFavoritesOnly(false)
}
}
)
ChipsRow(

View File

@ -100,10 +100,9 @@ internal fun RightSideScreen(
title = stringResource(R.string.units_screen_to),
placeholder = stringResource(R.string.search_bar_placeholder),
noSearchActions = {
FavoritesButton(
favoritesOnly = uiState.value.favoritesOnly,
favoriteAction = { viewModel.toggleFavoritesOnly(true) }
)
FavoritesButton(uiState.value.favoritesOnly) {
viewModel.toggleFavoritesOnly(true)
}
}
)
}

View File

@ -34,15 +34,16 @@ import com.sadellie.unitto.core.base.R
@Composable
internal fun FavoritesButton(
favoritesOnly: Boolean,
favoriteAction: () -> Unit
state: Boolean,
onClick: () -> Unit
) {
IconButton(onClick = favoriteAction) {
IconButton(onClick = onClick) {
AnimatedContent(
targetState = favoritesOnly,
targetState = state,
transitionSpec = {
(scaleIn() togetherWith scaleOut()).using(SizeTransform(clip = false))
}
},
label = "Animated click"
) {
Icon(
if (it) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder,

View File

@ -27,18 +27,18 @@ import com.sadellie.unitto.feature.unitslist.LeftSideScreen
import com.sadellie.unitto.feature.unitslist.RightSideScreen
import com.sadellie.unitto.feature.unitslist.UnitsListViewModel
const val leftSideRoute = "left_side_route"
const val rightSideRoute = "right_side_route"
private const val unitFromIdArg = "unitFromId"
private const val unitToIdArg = "unitToId"
private const val inputArg = "input"
private const val LEFT_SIDE_ROUTE = "LEFT_SIDE_ROUTE"
private const val RIGHT_SIDE_ROUTE = "RIGHT_SIDE_ROUTE"
private const val UNIT_FROM_ARG = "UNIT_FROM_ARG"
private const val UNIT_TO_ARG = "UNIT_FROM_ARG"
private const val INPUT_ARG = "INPUT_ARG"
fun NavController.navigateToLeftSide(unitFromId: String) {
navigate("$leftSideRoute/$unitFromId")
navigate("$LEFT_SIDE_ROUTE/$unitFromId")
}
fun NavController.navigateToRightSide(unitFromId: String, unitToId: String, input: String?) {
navigate("$rightSideRoute/$unitFromId/$unitToId/$input")
navigate("$RIGHT_SIDE_ROUTE/$unitFromId/$unitToId/$input")
}
fun NavGraphBuilder.leftScreen(
@ -48,11 +48,11 @@ fun NavGraphBuilder.leftScreen(
onSelect: (AbstractUnit) -> Unit
) {
composable(
route = "$leftSideRoute/{$unitFromIdArg}"
route = "$LEFT_SIDE_ROUTE/{$UNIT_FROM_ARG}"
) {
LeftSideScreen(
viewModel = viewModel,
currentUnitId = it.arguments?.getString(unitFromIdArg),
currentUnitId = it.arguments?.getString(UNIT_FROM_ARG),
navigateUp = navigateUp,
navigateToSettingsAction = navigateToUnitGroups,
selectAction = onSelect
@ -68,11 +68,11 @@ fun NavGraphBuilder.rightScreen(
) {
composable(
route = "$rightSideRoute/{$unitFromIdArg}/{$unitToIdArg}/{$inputArg}"
route = "$RIGHT_SIDE_ROUTE/{$UNIT_FROM_ARG}/{$UNIT_TO_ARG}/{$INPUT_ARG}"
) {
val unitFromId = it.arguments?.getString(unitFromIdArg) ?: return@composable
val unitToId = it.arguments?.getString(unitToIdArg) ?: return@composable
val input = it.arguments?.getString(inputArg)
val unitFromId = it.arguments?.getString(UNIT_FROM_ARG) ?: return@composable
val unitToId = it.arguments?.getString(UNIT_TO_ARG) ?: return@composable
val input = it.arguments?.getString(INPUT_ARG)
viewModel.setSelectedChip(unitFromId, true)
RightSideScreen(