Move unit converter supported units to a different screen

This commit is contained in:
MM20
2024-08-12 19:34:38 +02:00
parent 827eb08908
commit 3887324d37
19 changed files with 236 additions and 116 deletions
@@ -66,6 +66,7 @@ import de.mm20.launcher2.ui.settings.plugins.PluginsSettingsScreen
import de.mm20.launcher2.ui.settings.search.SearchSettingsScreen
import de.mm20.launcher2.ui.settings.searchactions.SearchActionsSettingsScreen
import de.mm20.launcher2.ui.settings.tags.TagsSettingsScreen
import de.mm20.launcher2.ui.settings.unitconverter.UnitConverterHelpSettingsScreen
import de.mm20.launcher2.ui.settings.unitconverter.UnitConverterSettingsScreen
import de.mm20.launcher2.ui.settings.weather.WeatherIntegrationSettingsScreen
import de.mm20.launcher2.ui.settings.wikipedia.WikipediaSettingsScreen
@@ -169,6 +170,9 @@ class SettingsActivity : BaseActivity() {
composable("settings/search/unitconverter") {
UnitConverterSettingsScreen()
}
composable("settings/search/unitconverter/help") {
UnitConverterHelpSettingsScreen()
}
composable("settings/search/wikipedia") {
WikipediaSettingsScreen()
}
@@ -0,0 +1,100 @@
package de.mm20.launcher2.ui.settings.unitconverter
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.launcher.search.unitconverter.getDimensionIcon
import de.mm20.launcher2.unitconverter.Dimension
import de.mm20.launcher2.unitconverter.MeasureUnit
import kotlinx.coroutines.flow.flow
@Composable
fun UnitConverterHelpSettingsScreen() {
val viewModel: UnitConverterSettingsScreenVM = viewModel()
val availableConverters by viewModel.availableConverters.collectAsState(emptyList())
val availableUnits by viewModel.availableUnits.collectAsState(emptyList())
PreferenceScreen(title = stringResource(R.string.preference_search_unitconverter),
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/search/unit-converter") {
for (i in availableConverters.indices) {
stickyHeader {
DimensionHeader(availableConverters[i].dimension)
}
items(availableUnits.getOrNull(i)?.size ?: 0) {
val unit = availableUnits[i].getOrNull(it) ?: return@items
Preference(
title = unit.formatName(LocalContext.current, 1.0),
controls = {
Box(
modifier = Modifier.size(36.dp)
.background(MaterialTheme.colorScheme.secondaryContainer, MaterialTheme.shapes.extraSmall),
contentAlignment = Alignment.Center,
) {
Text(unit.symbol, style = MaterialTheme.typography.labelSmall)
}
}
)
}
}
}
}
@Composable
private fun DimensionHeader(dimension: Dimension) {
Row(
modifier = Modifier.background(MaterialTheme.colorScheme.surfaceContainer).fillMaxWidth().padding(top = 16.dp, bottom = 16.dp)
) {
Icon(
getDimensionIcon(dimension),
null,
modifier = Modifier.padding(horizontal = 24.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
Text(
stringResource(dimension.resource),
style = MaterialTheme.typography.titleSmall,
modifier = Modifier.weight(1f),
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
@Composable
private fun UnitList(units: List<MeasureUnit>) {
val context = LocalContext.current
for (unit in units) {
Preference(
title = unit.formatName(context, 1.0),
controls = {
Box(
modifier = Modifier.size(36.dp)
.background(MaterialTheme.colorScheme.secondaryContainer, MaterialTheme.shapes.extraSmall),
contentAlignment = Alignment.Center,
) {
Text(unit.symbol, style = MaterialTheme.typography.labelSmall)
}
}
)
}
}
@@ -1,49 +1,28 @@
package de.mm20.launcher2.ui.settings.unitconverter
import android.icu.util.Currency
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Help
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.preferences.search.UnitConverterSettings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.launcher.search.unitconverter.getDimensionIcon
import de.mm20.launcher2.unitconverter.converters.CurrencyConverter
import de.mm20.launcher2.unitconverter.converters.SimpleFactorConverter
import de.mm20.launcher2.unitconverter.converters.TemperatureConverter
import org.koin.androidx.compose.inject
import de.mm20.launcher2.ui.locals.LocalNavController
@Composable
fun UnitConverterSettingsScreen() {
val settings: UnitConverterSettings by inject()
val viewModel: UnitConverterSettingsScreenVM = viewModel()
val loading by viewModel.loading
val navController = LocalNavController.current
val currenciesEnabled by settings.currencies.collectAsState(initial = false)
LaunchedEffect(currenciesEnabled) {
viewModel.loadCurrencies()
}
PreferenceScreen(title = stringResource(R.string.preference_search_unitconverter),
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/search/unit-converter") {
if (loading) {
item {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth()
)
}
}
PreferenceScreen(
title = stringResource(R.string.preference_search_unitconverter),
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/search/unit-converter"
) {
item {
PreferenceCategory {
val unitConverter by viewModel.unitConverter.collectAsState()
@@ -66,46 +45,16 @@ fun UnitConverterSettingsScreen() {
}
)
}
PreferenceCategory(
title = stringResource(R.string.preference_search_supportedunits)
) {
for (converter in viewModel.convertersList.value) {
val units = buildString {
when (converter) {
is SimpleFactorConverter -> {
converter.standardUnits.forEachIndexed { index, unit ->
if (index > 0) append(", ")
append(pluralStringResource(unit.nameResource, 1))
append(" (${unit.symbol})")
}
}
is TemperatureConverter -> {
converter.units.forEachIndexed { index, unit ->
if (index > 0) append(", ")
append(pluralStringResource(unit.nameResource, 1))
append(" (${unit.symbol})")
}
}
is CurrencyConverter -> {
viewModel.currenciesList.value.forEachIndexed { index, currency ->
if (index > 0) append(", ")
append(Currency.getInstance(currency)?.displayName ?: currency)
append(" ($currency)")
}
}
}
PreferenceCategory {
Preference(
title = stringResource(R.string.preference_search_supportedunits),
icon = Icons.AutoMirrored.Default.Help,
onClick = {
navController?.navigate("settings/search/unitconverter/help")
}
Preference(
title = stringResource(converter.dimension.resource),
icon = getDimensionIcon(converter.dimension),
summary = units
)
}
)
}
}
}
}
}
@@ -6,12 +6,13 @@ import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.search.UnitConverterSettings
import de.mm20.launcher2.unitconverter.UnitConverterRepository
import de.mm20.launcher2.unitconverter.converters.Converter
import de.mm20.launcher2.unitconverter.converters.CurrencyConverter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
@@ -22,10 +23,6 @@ class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
private val settings: UnitConverterSettings by inject()
private val repository: UnitConverterRepository by inject()
val loading = mutableStateOf(false)
val convertersList = mutableStateOf(emptyList<Converter>())
val currenciesList = mutableStateOf(emptyList<String>())
val unitConverter = settings.enabled
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setUnitConverter(unitConverter: Boolean) {
@@ -37,18 +34,12 @@ class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
fun setCurrencyConverter(currencyConverter: Boolean) {
settings.setCurrencies(currencyConverter)
}
fun loadCurrencies() {
loading.value = true
viewModelScope.launch(Dispatchers.Default) {
convertersList.value = repository.availableConverters(
settings.currencies.distinctUntilChanged().first()
)
val currencyConverter = convertersList.value.find { it is CurrencyConverter }
if (currencyConverter != null) {
currenciesList.value = (currencyConverter as CurrencyConverter).getAbbreviations()
}
}
loading.value = false
}
val availableConverters = settings.currencies.map {
repository.getAvailableConverters(includeCurrencies = it)
}.shareIn(viewModelScope, SharingStarted.WhileSubscribed(100), 1)
val availableUnits = availableConverters.map {
it.map { converter -> converter.getSupportedUnits() }
}.shareIn(viewModelScope, SharingStarted.WhileSubscribed(100), 1)
}