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

View File

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