Refactor LeftSideScreen and RightSideScreen

Reusable UnitsList
This commit is contained in:
Sad Ellie 2024-02-07 23:42:51 +03:00
parent 886efdc8b7
commit 3c10fb9b0c
3 changed files with 151 additions and 97 deletions

View File

@ -18,13 +18,9 @@
package com.sadellie.unitto.feature.converter
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
@ -33,12 +29,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.SearchPlaceholder
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.SearchBar
import com.sadellie.unitto.data.converter.UnitID
@ -46,10 +41,9 @@ import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.unit.AbstractUnit
import com.sadellie.unitto.data.model.unit.NormalUnit
import com.sadellie.unitto.feature.converter.components.BasicUnitListItem
import com.sadellie.unitto.feature.converter.components.ChipsRow
import com.sadellie.unitto.feature.converter.components.FavoritesButton
import com.sadellie.unitto.feature.converter.components.UnitGroupHeader
import com.sadellie.unitto.feature.converter.components.UnitsList
import java.math.BigDecimal
@Composable
@ -129,43 +123,20 @@ private fun LeftSideScreen(
}
}
) { paddingValues ->
Crossfade(
targetState = uiState.units.isNotEmpty(),
val resources = LocalContext.current.resources
UnitsList(
modifier = Modifier.padding(paddingValues),
label = "Units list"
) { hasUnits ->
when (hasUnits) {
true -> LazyColumn(Modifier.fillMaxSize()) {
uiState.units.forEach { (unitGroup, units) ->
item(unitGroup.name) {
UnitGroupHeader(Modifier.animateItemPlacement(), unitGroup)
}
items(units, { it.id }) {
BasicUnitListItem(
modifier = Modifier.animateItemPlacement(),
name = stringResource(it.displayName),
supportLabel = stringResource(it.shortName),
isFavorite = it.isFavorite,
isSelected = it.id == uiState.unitFrom.id,
onClick = {
onQueryChange(TextFieldValue())
updateUnitFrom(it)
navigateUp()
},
favoriteUnit = { favoriteUnit(it) }
)
}
}
}
false -> SearchPlaceholder(
onButtonClick = navigateToUnitGroups,
supportText = stringResource(R.string.converter_no_results_support),
buttonLabel = stringResource(R.string.open_settings_label)
)
}
}
groupedUnits = uiState.units,
navigateToUnitGroups = navigateToUnitGroups,
currentUnitId = uiState.unitFrom.id,
supportLabel = { resources.getString(it.shortName) },
onClick = {
onQueryChange(TextFieldValue())
updateUnitFrom(it)
navigateUp()
},
favoriteUnit = { favoriteUnit(it) }
)
}
}

View File

@ -18,38 +18,32 @@
package com.sadellie.unitto.feature.converter
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.SearchPlaceholder
import com.sadellie.unitto.core.ui.common.EmptyScreen
import com.sadellie.unitto.core.ui.common.SearchBar
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
import com.sadellie.unitto.data.common.format
import com.sadellie.unitto.data.converter.UnitID
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.UnitsListSorting
import com.sadellie.unitto.data.model.unit.AbstractUnit
import com.sadellie.unitto.data.model.unit.DefaultUnit
import com.sadellie.unitto.data.model.unit.NormalUnit
import com.sadellie.unitto.data.model.unit.NumberBaseUnit
import com.sadellie.unitto.data.converter.UnitID
import com.sadellie.unitto.feature.converter.components.BasicUnitListItem
import com.sadellie.unitto.feature.converter.components.FavoritesButton
import com.sadellie.unitto.feature.converter.components.UnitGroupHeader
import com.sadellie.unitto.feature.converter.components.UnitsList
import java.math.BigDecimal
@Composable
@ -103,52 +97,31 @@ private fun RightSideScreen(
)
}
) { paddingValues ->
Crossfade(
targetState = uiState.units.isNotEmpty(),
val resources = LocalContext.current.resources
UnitsList(
modifier = Modifier.padding(paddingValues),
label = "Units list"
) { hasUnits ->
when (hasUnits) {
true -> LazyColumn(Modifier.fillMaxSize()) {
uiState.units.forEach { (unitGroup, units) ->
item(unitGroup.name) {
UnitGroupHeader(Modifier.animateItemPlacement(), unitGroup)
}
items(units, { it.id }) {
BasicUnitListItem(
modifier = Modifier.animateItemPlacement(),
name = stringResource(it.displayName),
supportLabel = formatUnitToSupportLabel(
unitFrom = uiState.unitFrom,
unitTo = it,
input = uiState.input,
shortName = stringResource(it.shortName),
scale = uiState.scale,
outputFormat = uiState.outputFormat,
formatterSymbols = uiState.formatterSymbols,
readyCurrencies = uiState.currencyRateUpdateState is CurrencyRateUpdateState.Ready,
),
isFavorite = it.isFavorite,
isSelected = it.id == uiState.unitTo.id,
onClick = {
onQueryChange(TextFieldValue())
updateUnitTo(it)
navigateUp()
},
favoriteUnit = { favoriteUnit(it) }
)
}
}
}
false -> SearchPlaceholder(
onButtonClick = navigateToUnitGroups,
supportText = stringResource(R.string.converter_no_results_support),
buttonLabel = stringResource(R.string.open_settings_label)
groupedUnits = uiState.units,
navigateToUnitGroups = navigateToUnitGroups,
currentUnitId = uiState.unitTo.id,
supportLabel = {
formatUnitToSupportLabel(
unitFrom = uiState.unitFrom,
unitTo = it,
input = uiState.input,
shortName = resources.getString(it.shortName),
scale = uiState.scale,
outputFormat = uiState.outputFormat,
formatterSymbols = uiState.formatterSymbols,
readyCurrencies = uiState.currencyRateUpdateState is CurrencyRateUpdateState.Ready,
)
}
}
},
onClick = {
onQueryChange(TextFieldValue())
updateUnitTo(it)
navigateUp()
},
favoriteUnit = { favoriteUnit(it) }
)
}
}

View File

@ -0,0 +1,110 @@
/*
* Unitto is a calculator for Android
* Copyright (c) 2024 Elshan Agaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.feature.converter.components
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.SearchPlaceholder
import com.sadellie.unitto.data.converter.UnitID
import com.sadellie.unitto.data.model.UnitGroup
import com.sadellie.unitto.data.model.unit.AbstractUnit
import com.sadellie.unitto.data.model.unit.NormalUnit
import java.math.BigDecimal
@Composable
internal fun UnitsList(
modifier: Modifier,
groupedUnits: Map<UnitGroup, List<AbstractUnit>>,
navigateToUnitGroups: () -> Unit,
currentUnitId: String,
supportLabel: (AbstractUnit) -> String,
onClick: (AbstractUnit) -> Unit,
favoriteUnit: (AbstractUnit) -> Unit,
) {
Crossfade(
modifier = modifier,
targetState = groupedUnits.isNotEmpty(),
label = "Units list"
) { hasUnits ->
when (hasUnits) {
true -> LazyColumn(
modifier = Modifier.fillMaxSize()
) {
groupedUnits.forEach { (group, units) ->
item(group.name) {
UnitGroupHeader(Modifier.animateItemPlacement(), group)
}
items(units, { it.id }) {
BasicUnitListItem(
modifier = Modifier.animateItemPlacement(),
name = stringResource(it.displayName),
supportLabel = supportLabel(it),
isFavorite = it.isFavorite,
isSelected = it.id == currentUnitId,
onClick = { onClick(it) },
favoriteUnit = { favoriteUnit(it) },
)
}
}
}
false -> SearchPlaceholder(
onButtonClick = navigateToUnitGroups,
supportText = stringResource(R.string.converter_no_results_support),
buttonLabel = stringResource(R.string.open_settings_label)
)
}
}
}
@Preview
@Composable
private fun PreviewUnitsList() {
val resources = LocalContext.current.resources
val groupedUnits: Map<UnitGroup, List<AbstractUnit>> = mapOf(
UnitGroup.LENGTH to listOf(
NormalUnit(UnitID.meter, BigDecimal.valueOf(1.0E+18), UnitGroup.LENGTH, R.string.unit_meter, R.string.unit_meter_short),
NormalUnit(UnitID.kilometer, BigDecimal.valueOf(1.0E+21), UnitGroup.LENGTH, R.string.unit_kilometer, R.string.unit_kilometer_short),
NormalUnit(UnitID.nautical_mile, BigDecimal.valueOf(1.852E+21), UnitGroup.LENGTH, R.string.unit_nautical_mile, R.string.unit_nautical_mile_short),
NormalUnit(UnitID.inch, BigDecimal.valueOf(25_400_000_000_000_000), UnitGroup.LENGTH, R.string.unit_inch, R.string.unit_inch_short),
NormalUnit(UnitID.foot, BigDecimal.valueOf(304_800_000_000_002_200), UnitGroup.LENGTH, R.string.unit_foot, R.string.unit_foot_short),
NormalUnit(UnitID.yard, BigDecimal.valueOf(914_400_000_000_006_400), UnitGroup.LENGTH, R.string.unit_yard, R.string.unit_yard_short),
NormalUnit(UnitID.mile, BigDecimal.valueOf(1_609_344_000_000_010_500_000.0), UnitGroup.LENGTH, R.string.unit_mile, R.string.unit_mile_short),
)
)
UnitsList(
modifier = Modifier.fillMaxSize(),
groupedUnits = groupedUnits,
navigateToUnitGroups = {},
currentUnitId = UnitID.mile,
supportLabel = { resources.getString(it.shortName) },
onClick = {},
favoriteUnit = {}
)
}