mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 08:45:27 +02:00
Personal UnitGroups list
User can now reorder/add/hide unit groups. Lots of stuff were implemented in a very strange/ugly way, but will be fixed in later commits.
This commit is contained in:
parent
0f25e83c6e
commit
e3c1c5376f
@ -194,4 +194,7 @@ dependencies {
|
|||||||
|
|
||||||
// Themmo
|
// Themmo
|
||||||
implementation("com.github.sadellie:themmo:0.0.3")
|
implementation("com.github.sadellie:themmo:0.0.3")
|
||||||
|
|
||||||
|
// ComposeReorderable
|
||||||
|
implementation("org.burnoutcrew.composereorderable:reorderable:0.9.2")
|
||||||
}
|
}
|
@ -40,15 +40,17 @@ import com.sadellie.unitto.data.NavRoutes.RIGHT_LIST_SCREEN
|
|||||||
import com.sadellie.unitto.data.NavRoutes.SETTINGS_GRAPH
|
import com.sadellie.unitto.data.NavRoutes.SETTINGS_GRAPH
|
||||||
import com.sadellie.unitto.data.NavRoutes.SETTINGS_SCREEN
|
import com.sadellie.unitto.data.NavRoutes.SETTINGS_SCREEN
|
||||||
import com.sadellie.unitto.data.NavRoutes.THEMES_SCREEN
|
import com.sadellie.unitto.data.NavRoutes.THEMES_SCREEN
|
||||||
|
import com.sadellie.unitto.data.NavRoutes.UNIT_GROUPS_SCREEN
|
||||||
import com.sadellie.unitto.screens.MainViewModel
|
import com.sadellie.unitto.screens.MainViewModel
|
||||||
import com.sadellie.unitto.screens.setttings.SettingsViewModel
|
|
||||||
import com.sadellie.unitto.screens.setttings.AboutScreen
|
|
||||||
import com.sadellie.unitto.screens.main.MainScreen
|
import com.sadellie.unitto.screens.main.MainScreen
|
||||||
import com.sadellie.unitto.screens.second.LeftSideScreen
|
import com.sadellie.unitto.screens.second.LeftSideScreen
|
||||||
import com.sadellie.unitto.screens.second.RightSideScreen
|
import com.sadellie.unitto.screens.second.RightSideScreen
|
||||||
import com.sadellie.unitto.screens.second.SecondViewModel
|
import com.sadellie.unitto.screens.second.SecondViewModel
|
||||||
|
import com.sadellie.unitto.screens.setttings.AboutScreen
|
||||||
import com.sadellie.unitto.screens.setttings.SettingsScreen
|
import com.sadellie.unitto.screens.setttings.SettingsScreen
|
||||||
|
import com.sadellie.unitto.screens.setttings.SettingsViewModel
|
||||||
import com.sadellie.unitto.screens.setttings.ThemesScreen
|
import com.sadellie.unitto.screens.setttings.ThemesScreen
|
||||||
|
import com.sadellie.unitto.screens.setttings.UnitGroupsScreen
|
||||||
import com.sadellie.unitto.ui.theme.AppTypography
|
import com.sadellie.unitto.ui.theme.AppTypography
|
||||||
import com.sadellie.unitto.ui.theme.DarkThemeColors
|
import com.sadellie.unitto.ui.theme.DarkThemeColors
|
||||||
import com.sadellie.unitto.ui.theme.LightThemeColors
|
import com.sadellie.unitto.ui.theme.LightThemeColors
|
||||||
@ -168,5 +170,12 @@ private fun NavGraphBuilder.settingGraph(
|
|||||||
composable(ABOUT_SCREEN) {
|
composable(ABOUT_SCREEN) {
|
||||||
AboutScreen(navigateUpAction = { navController.navigateUp() })
|
AboutScreen(navigateUpAction = { navController.navigateUp() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composable(UNIT_GROUPS_SCREEN) {
|
||||||
|
UnitGroupsScreen(
|
||||||
|
viewModel = settingsViewModel,
|
||||||
|
navigateUpAction = { navController.navigateUp() }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,4 +31,5 @@ object NavRoutes {
|
|||||||
const val SETTINGS_SCREEN = "SettingsScreen"
|
const val SETTINGS_SCREEN = "SettingsScreen"
|
||||||
const val THEMES_SCREEN = "ThemesScreen"
|
const val THEMES_SCREEN = "ThemesScreen"
|
||||||
const val ABOUT_SCREEN = "AboutScreen"
|
const val ABOUT_SCREEN = "AboutScreen"
|
||||||
|
const val UNIT_GROUPS_SCREEN = "UnitGroupScreen"
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
package com.sadellie.unitto.data.preferences
|
package com.sadellie.unitto.data.preferences
|
||||||
|
|
||||||
|
import android.text.TextUtils.split
|
||||||
|
import android.util.Log
|
||||||
import androidx.datastore.core.DataStore
|
import androidx.datastore.core.DataStore
|
||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||||
@ -25,8 +27,10 @@ import androidx.datastore.preferences.core.edit
|
|||||||
import androidx.datastore.preferences.core.emptyPreferences
|
import androidx.datastore.preferences.core.emptyPreferences
|
||||||
import androidx.datastore.preferences.core.intPreferencesKey
|
import androidx.datastore.preferences.core.intPreferencesKey
|
||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
|
import com.sadellie.unitto.data.units.ALL_UNIT_GROUPS
|
||||||
import com.sadellie.unitto.data.units.AbstractUnit
|
import com.sadellie.unitto.data.units.AbstractUnit
|
||||||
import com.sadellie.unitto.data.units.MyUnitIDS
|
import com.sadellie.unitto.data.units.MyUnitIDS
|
||||||
|
import com.sadellie.unitto.data.units.UnitGroup
|
||||||
import io.github.sadellie.themmo.ThemingMode
|
import io.github.sadellie.themmo.ThemingMode
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
@ -47,6 +51,7 @@ import javax.inject.Inject
|
|||||||
* @property latestLeftSideUnit Latest [AbstractUnit] that was on the left side
|
* @property latestLeftSideUnit Latest [AbstractUnit] that was on the left side
|
||||||
* @property latestRightSideUnit Latest [AbstractUnit] that was on the right side
|
* @property latestRightSideUnit Latest [AbstractUnit] that was on the right side
|
||||||
* @property enableAnalytics Whether or not user wants to share application usage data
|
* @property enableAnalytics Whether or not user wants to share application usage data
|
||||||
|
* @property shownUnitGroups [UnitGroup]s that user wants to see. Excludes other [UnitGroup]s
|
||||||
*/
|
*/
|
||||||
data class UserPreferences(
|
data class UserPreferences(
|
||||||
val themingMode: ThemingMode? = null,
|
val themingMode: ThemingMode? = null,
|
||||||
@ -57,7 +62,8 @@ data class UserPreferences(
|
|||||||
val outputFormat: Int = OutputFormat.PLAIN,
|
val outputFormat: Int = OutputFormat.PLAIN,
|
||||||
val latestLeftSideUnit: String = MyUnitIDS.kilometer,
|
val latestLeftSideUnit: String = MyUnitIDS.kilometer,
|
||||||
val latestRightSideUnit: String = MyUnitIDS.mile,
|
val latestRightSideUnit: String = MyUnitIDS.mile,
|
||||||
val enableAnalytics: Boolean = true
|
val enableAnalytics: Boolean = true,
|
||||||
|
val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,6 +83,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
|||||||
val LATEST_LEFT_SIDE = stringPreferencesKey("LATEST_LEFT_SIDE_PREF_KEY")
|
val LATEST_LEFT_SIDE = stringPreferencesKey("LATEST_LEFT_SIDE_PREF_KEY")
|
||||||
val LATEST_RIGHT_SIDE = stringPreferencesKey("LATEST_RIGHT_SIDE_PREF_KEY")
|
val LATEST_RIGHT_SIDE = stringPreferencesKey("LATEST_RIGHT_SIDE_PREF_KEY")
|
||||||
val ENABLE_ANALYTICS = booleanPreferencesKey("ENABLE_ANALYTICS_PREF_KEY")
|
val ENABLE_ANALYTICS = booleanPreferencesKey("ENABLE_ANALYTICS_PREF_KEY")
|
||||||
|
val SHOWN_UNIT_GROUPS = stringPreferencesKey("SHOWN_UNIT_GROUPS_PREF_KEY")
|
||||||
}
|
}
|
||||||
|
|
||||||
val userPreferencesFlow: Flow<UserPreferences> = dataStore.data
|
val userPreferencesFlow: Flow<UserPreferences> = dataStore.data
|
||||||
@ -107,6 +114,19 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
|||||||
preferences[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile
|
preferences[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile
|
||||||
val enableAnalytics: Boolean =
|
val enableAnalytics: Boolean =
|
||||||
preferences[PrefsKeys.ENABLE_ANALYTICS] ?: true
|
preferences[PrefsKeys.ENABLE_ANALYTICS] ?: true
|
||||||
|
val shownUnitGroups: List<UnitGroup> =
|
||||||
|
preferences[PrefsKeys.SHOWN_UNIT_GROUPS]?.let { list ->
|
||||||
|
// Everything is in hidden (nothing in shown)
|
||||||
|
list.ifEmpty { return@let listOf() }
|
||||||
|
|
||||||
|
try {
|
||||||
|
list.split(",").map { UnitGroup.valueOf(it) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Bad thing happened, return null so all units will be shown
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
} ?: ALL_UNIT_GROUPS
|
||||||
|
|
||||||
UserPreferences(
|
UserPreferences(
|
||||||
themingMode = themingMode,
|
themingMode = themingMode,
|
||||||
@ -117,7 +137,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
|||||||
outputFormat = outputFormat,
|
outputFormat = outputFormat,
|
||||||
latestLeftSideUnit = latestLeftSideUnit,
|
latestLeftSideUnit = latestLeftSideUnit,
|
||||||
latestRightSideUnit = latestRightSideUnit,
|
latestRightSideUnit = latestRightSideUnit,
|
||||||
enableAnalytics = enableAnalytics
|
enableAnalytics = enableAnalytics,
|
||||||
|
shownUnitGroups = shownUnitGroups
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,4 +232,10 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
|||||||
preferences[PrefsKeys.ENABLE_AMOLED_THEME] = enabled
|
preferences[PrefsKeys.ENABLE_AMOLED_THEME] = enabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>) {
|
||||||
|
dataStore.edit { preferences ->
|
||||||
|
preferences[PrefsKeys.SHOWN_UNIT_GROUPS] = shownUnitGroups.joinToString(",")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,16 +96,21 @@ class AllUnitsRepository @Inject constructor() {
|
|||||||
* @param favoritesOnly When True will filter only [AbstractUnit]s with [AbstractUnit.isFavorite]
|
* @param favoritesOnly When True will filter only [AbstractUnit]s with [AbstractUnit.isFavorite]
|
||||||
* set to True.
|
* set to True.
|
||||||
* @param searchQuery When not empty, will search by [AbstractUnit.renderedName] using [sortByLev].
|
* @param searchQuery When not empty, will search by [AbstractUnit.renderedName] using [sortByLev].
|
||||||
|
* @param allUnitsGroups All [UnitGroup]s. Determines which units will be used for filtering.
|
||||||
* @return Grouped by [UnitGroup] list of [AbstractUnit]s.
|
* @return Grouped by [UnitGroup] list of [AbstractUnit]s.
|
||||||
*/
|
*/
|
||||||
fun filterUnits(
|
fun filterUnits(
|
||||||
hideBrokenCurrencies: Boolean,
|
hideBrokenCurrencies: Boolean,
|
||||||
chosenUnitGroup: UnitGroup?,
|
chosenUnitGroup: UnitGroup?,
|
||||||
favoritesOnly: Boolean,
|
favoritesOnly: Boolean,
|
||||||
searchQuery: String
|
searchQuery: String,
|
||||||
|
allUnitsGroups: List<UnitGroup>
|
||||||
): Map<UnitGroup, List<AbstractUnit>> {
|
): Map<UnitGroup, List<AbstractUnit>> {
|
||||||
|
val shownUnits: List<AbstractUnit> =
|
||||||
|
allUnitsGroups.flatMap { getCollectionByGroup(it) ?: listOf() }
|
||||||
|
|
||||||
var basicFilteredUnits: Sequence<AbstractUnit> =
|
var basicFilteredUnits: Sequence<AbstractUnit> =
|
||||||
getCollectionByGroup(unitGroup = chosenUnitGroup)?.asSequence() ?: allUnits.asSequence()
|
getCollectionByGroup(unitGroup = chosenUnitGroup)?.asSequence() ?: shownUnits.asSequence()
|
||||||
|
|
||||||
if (favoritesOnly) {
|
if (favoritesOnly) {
|
||||||
basicFilteredUnits = basicFilteredUnits.filter { it.isFavorite }
|
basicFilteredUnits = basicFilteredUnits.filter { it.isFavorite }
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Unitto is a unit converter for Android
|
||||||
|
* Copyright (c) 2022 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.data.units
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import org.burnoutcrew.reorderable.ItemPosition
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository that holds information about shown and hidden [UnitGroup]s and provides methods to
|
||||||
|
* show/hide [UnitGroup]s.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
class UnitGroupsRepository @Inject constructor() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex is need needed because we work with flow (sync stuff).
|
||||||
|
*/
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently shown [UnitGroup]s.
|
||||||
|
*/
|
||||||
|
var shownUnitGroups = MutableStateFlow(listOf<UnitGroup>())
|
||||||
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently hidden [UnitGroup]s.
|
||||||
|
*/
|
||||||
|
var hiddenUnitGroups = MutableStateFlow(listOf<UnitGroup>())
|
||||||
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets [shownUnitGroups] and updates [hiddenUnitGroups] as a side effect. [hiddenUnitGroups] is
|
||||||
|
* everything from [ALL_UNIT_GROUPS] that was not in [shownUnitGroups].
|
||||||
|
*
|
||||||
|
* @param list List of [UnitGroup]s that need to be shown.
|
||||||
|
*/
|
||||||
|
suspend fun updateShownGroups(list: List<UnitGroup>) {
|
||||||
|
mutex.withLock {
|
||||||
|
shownUnitGroups.value = list
|
||||||
|
hiddenUnitGroups.value = ALL_UNIT_GROUPS - list.toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves [UnitGroup] from [shownUnitGroups] to [hiddenUnitGroups]
|
||||||
|
*
|
||||||
|
* @param unitGroup [UnitGroup] to hide.
|
||||||
|
*/
|
||||||
|
suspend fun markUnitGroupAsHidden(unitGroup: UnitGroup) {
|
||||||
|
mutex.withLock {
|
||||||
|
shownUnitGroups.value = shownUnitGroups.value - unitGroup
|
||||||
|
// Newly hidden unit will appear at the top of the list
|
||||||
|
hiddenUnitGroups.value = listOf(unitGroup) + hiddenUnitGroups.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves [UnitGroup] from [hiddenUnitGroups] to [shownUnitGroups]
|
||||||
|
*
|
||||||
|
* @param unitGroup [UnitGroup] to show.
|
||||||
|
*/
|
||||||
|
suspend fun markUnitGroupAsShown(unitGroup: UnitGroup) {
|
||||||
|
mutex.withLock {
|
||||||
|
hiddenUnitGroups.value = hiddenUnitGroups.value - unitGroup
|
||||||
|
shownUnitGroups.value = shownUnitGroups.value + unitGroup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves [UnitGroup] in [shownUnitGroups] from one index to another (reorder).
|
||||||
|
*
|
||||||
|
* @param from Position from which we need to move from
|
||||||
|
* @param to Position where to put [UnitGroup]
|
||||||
|
*/
|
||||||
|
suspend fun moveShownUnitGroups(from: ItemPosition, to: ItemPosition) {
|
||||||
|
mutex.withLock {
|
||||||
|
shownUnitGroups.value = shownUnitGroups.value.toMutableList().apply {
|
||||||
|
add(
|
||||||
|
shownUnitGroups.value.indexOfFirst { it == to.key },
|
||||||
|
removeAt(shownUnitGroups.value.indexOfFirst { it == from.key })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -151,6 +151,7 @@ fun LeftSideScreen(
|
|||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
chipsRow = { unitGroup, lazyListState ->
|
chipsRow = { unitGroup, lazyListState ->
|
||||||
ChipsRow(
|
ChipsRow(
|
||||||
|
items = viewModel.uiState.shownUnitGroups,
|
||||||
chosenUnitGroup = unitGroup,
|
chosenUnitGroup = unitGroup,
|
||||||
selectAction = {
|
selectAction = {
|
||||||
viewModel.toggleSelectedChip(it)
|
viewModel.toggleSelectedChip(it)
|
||||||
|
@ -27,11 +27,13 @@ import com.sadellie.unitto.data.units.UnitGroup
|
|||||||
* @property favoritesOnly Whether or not show only favorite [AbstractUnit]s.
|
* @property favoritesOnly Whether or not show only favorite [AbstractUnit]s.
|
||||||
* @property unitsToShow Grouped list of [AbstractUnit]s.
|
* @property unitsToShow Grouped list of [AbstractUnit]s.
|
||||||
* @property searchQuery Search query in search bar.
|
* @property searchQuery Search query in search bar.
|
||||||
|
* @property shownUnitGroups All [UnitGroup]s that can be seen in chips row
|
||||||
* @property chosenUnitGroup Currently selected chip. Nul means that no chip is selected.
|
* @property chosenUnitGroup Currently selected chip. Nul means that no chip is selected.
|
||||||
*/
|
*/
|
||||||
data class SecondScreenUIState(
|
data class SecondScreenUIState(
|
||||||
val favoritesOnly: Boolean = false,
|
val favoritesOnly: Boolean = false,
|
||||||
val unitsToShow: Map<UnitGroup, List<AbstractUnit>> = emptyMap(),
|
val unitsToShow: Map<UnitGroup, List<AbstractUnit>> = emptyMap(),
|
||||||
val searchQuery: String = "",
|
val searchQuery: String = "",
|
||||||
|
val shownUnitGroups: List<UnitGroup> = listOf(),
|
||||||
val chosenUnitGroup: UnitGroup? = null
|
val chosenUnitGroup: UnitGroup? = null
|
||||||
)
|
)
|
||||||
|
@ -26,6 +26,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.sadellie.unitto.data.units.AbstractUnit
|
import com.sadellie.unitto.data.units.AbstractUnit
|
||||||
import com.sadellie.unitto.data.units.AllUnitsRepository
|
import com.sadellie.unitto.data.units.AllUnitsRepository
|
||||||
import com.sadellie.unitto.data.units.UnitGroup
|
import com.sadellie.unitto.data.units.UnitGroup
|
||||||
|
import com.sadellie.unitto.data.units.UnitGroupsRepository
|
||||||
import com.sadellie.unitto.data.units.database.MyBasedUnit
|
import com.sadellie.unitto.data.units.database.MyBasedUnit
|
||||||
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
|
import com.sadellie.unitto.data.units.database.MyBasedUnitsRepository
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
@ -37,7 +38,8 @@ import javax.inject.Inject
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SecondViewModel @Inject constructor(
|
class SecondViewModel @Inject constructor(
|
||||||
private val basedUnitRepository: MyBasedUnitsRepository,
|
private val basedUnitRepository: MyBasedUnitsRepository,
|
||||||
private val allUnitsRepository: AllUnitsRepository
|
private val allUnitsRepository: AllUnitsRepository,
|
||||||
|
private val unitGroupsRepository: UnitGroupsRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
var uiState: SecondScreenUIState by mutableStateOf(SecondScreenUIState())
|
var uiState: SecondScreenUIState by mutableStateOf(SecondScreenUIState())
|
||||||
@ -93,7 +95,8 @@ class SecondViewModel @Inject constructor(
|
|||||||
hideBrokenCurrencies = hideBrokenCurrencies,
|
hideBrokenCurrencies = hideBrokenCurrencies,
|
||||||
chosenUnitGroup = uiState.chosenUnitGroup,
|
chosenUnitGroup = uiState.chosenUnitGroup,
|
||||||
favoritesOnly = uiState.favoritesOnly,
|
favoritesOnly = uiState.favoritesOnly,
|
||||||
searchQuery = uiState.searchQuery
|
searchQuery = uiState.searchQuery,
|
||||||
|
allUnitsGroups = uiState.shownUnitGroups
|
||||||
)
|
)
|
||||||
|
|
||||||
uiState = uiState.copy(unitsToShow = unitsToShow)
|
uiState = uiState.copy(unitsToShow = unitsToShow)
|
||||||
@ -119,4 +122,12 @@ class SecondViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
viewModelScope.launch {
|
||||||
|
unitGroupsRepository.shownUnitGroups.collect {
|
||||||
|
uiState = uiState.copy(shownUnitGroups = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,12 @@ import androidx.compose.ui.unit.dp
|
|||||||
* Unit group header.
|
* Unit group header.
|
||||||
*
|
*
|
||||||
* @param text Unit group name.
|
* @param text Unit group name.
|
||||||
|
* @param modifier Modifier that will be applied to Text composable.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun Header(text: String) {
|
fun Header(text: String, modifier: Modifier = Modifier) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.background(MaterialTheme.colorScheme.background)
|
.background(MaterialTheme.colorScheme.background)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 12.dp, horizontal = 8.dp),
|
.padding(vertical = 12.dp, horizontal = 8.dp),
|
||||||
|
@ -30,6 +30,7 @@ import com.sadellie.unitto.BuildConfig
|
|||||||
import com.sadellie.unitto.R
|
import com.sadellie.unitto.R
|
||||||
import com.sadellie.unitto.data.NavRoutes.ABOUT_SCREEN
|
import com.sadellie.unitto.data.NavRoutes.ABOUT_SCREEN
|
||||||
import com.sadellie.unitto.data.NavRoutes.THEMES_SCREEN
|
import com.sadellie.unitto.data.NavRoutes.THEMES_SCREEN
|
||||||
|
import com.sadellie.unitto.data.NavRoutes.UNIT_GROUPS_SCREEN
|
||||||
import com.sadellie.unitto.data.preferences.OUTPUT_FORMAT
|
import com.sadellie.unitto.data.preferences.OUTPUT_FORMAT
|
||||||
import com.sadellie.unitto.data.preferences.PRECISIONS
|
import com.sadellie.unitto.data.preferences.PRECISIONS
|
||||||
import com.sadellie.unitto.data.preferences.SEPARATORS
|
import com.sadellie.unitto.data.preferences.SEPARATORS
|
||||||
@ -59,42 +60,49 @@ fun SettingsScreen(
|
|||||||
// GENERAL GROUP
|
// GENERAL GROUP
|
||||||
item { SettingsHeader(stringResource(R.string.general_settings_group)) }
|
item { SettingsHeader(stringResource(R.string.general_settings_group)) }
|
||||||
|
|
||||||
|
// THEME
|
||||||
|
item {
|
||||||
|
SettingsListItem(
|
||||||
|
label = stringResource(id = R.string.unit_groups_setting)
|
||||||
|
) { navControllerAction(UNIT_GROUPS_SCREEN) }
|
||||||
|
}
|
||||||
|
|
||||||
// PRECISION
|
// PRECISION
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.precision_setting),
|
label = stringResource(R.string.precision_setting),
|
||||||
stringResource(R.string.precision_setting_support)
|
supportText = stringResource(R.string.precision_setting_support)
|
||||||
) { dialogState = DialogState.PRECISION }
|
) { dialogState = DialogState.PRECISION }
|
||||||
}
|
}
|
||||||
|
|
||||||
// SEPARATOR
|
// SEPARATOR
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.separator_setting),
|
label = stringResource(R.string.separator_setting),
|
||||||
stringResource(R.string.separator_setting_support)
|
supportText = stringResource(R.string.separator_setting_support)
|
||||||
) { dialogState = DialogState.SEPARATOR }
|
) { dialogState = DialogState.SEPARATOR }
|
||||||
}
|
}
|
||||||
|
|
||||||
// OUTPUT FORMAT
|
// OUTPUT FORMAT
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.output_format_setting),
|
label = stringResource(R.string.output_format_setting),
|
||||||
stringResource(R.string.output_format_setting_support)
|
supportText = stringResource(R.string.output_format_setting_support)
|
||||||
) { dialogState = DialogState.OUTPUT_FORMAT }
|
) { dialogState = DialogState.OUTPUT_FORMAT }
|
||||||
}
|
}
|
||||||
|
|
||||||
// THEME
|
// THEME
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.theme_setting),
|
label = stringResource(R.string.theme_setting),
|
||||||
stringResource(R.string.theme_setting_support)
|
supportText = stringResource(R.string.theme_setting_support)
|
||||||
) { navControllerAction(THEMES_SCREEN) }
|
) { navControllerAction(THEMES_SCREEN) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// CURRENCY RATE NOTE
|
// CURRENCY RATE NOTE
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.currency_rates_note_setting)
|
label = stringResource(R.string.currency_rates_note_setting)
|
||||||
) { dialogState = DialogState.CURRENCY_RATE }
|
) { dialogState = DialogState.CURRENCY_RATE }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,14 +112,14 @@ fun SettingsScreen(
|
|||||||
// TERMS AND CONDITIONS
|
// TERMS AND CONDITIONS
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.terms_and_conditions)
|
label = stringResource(R.string.terms_and_conditions)
|
||||||
) { openLink(mContext, "http://sadellie.github.io/unitto/terms-app.html") }
|
) { openLink(mContext, "http://sadellie.github.io/unitto/terms-app.html") }
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIVACY POLICY
|
// PRIVACY POLICY
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.privacy_policy)
|
label = stringResource(R.string.privacy_policy)
|
||||||
) { openLink(mContext, "http://sadellie.github.io/unitto/privacy-app.html") }
|
) { openLink(mContext, "http://sadellie.github.io/unitto/privacy-app.html") }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +127,9 @@ fun SettingsScreen(
|
|||||||
if (BuildConfig.ANALYTICS) {
|
if (BuildConfig.ANALYTICS) {
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.send_usage_statistics),
|
label = stringResource(R.string.send_usage_statistics),
|
||||||
stringResource(R.string.send_usage_statistics_support),
|
supportText = stringResource(R.string.send_usage_statistics_support),
|
||||||
viewModel.userPrefs.enableAnalytics
|
switchState = viewModel.userPrefs.enableAnalytics
|
||||||
) { viewModel.updateEnableAnalytics(it) }
|
) { viewModel.updateEnableAnalytics(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +137,7 @@ fun SettingsScreen(
|
|||||||
// THIRD PARTY
|
// THIRD PARTY
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.third_party_licenses)
|
label = stringResource(R.string.third_party_licenses)
|
||||||
) { navControllerAction(ABOUT_SCREEN) }
|
) { navControllerAction(ABOUT_SCREEN) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +145,7 @@ fun SettingsScreen(
|
|||||||
if (BuildConfig.STORE_LINK.isNotEmpty()) {
|
if (BuildConfig.STORE_LINK.isNotEmpty()) {
|
||||||
item {
|
item {
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
stringResource(R.string.rate_this_app)
|
label = stringResource(R.string.rate_this_app)
|
||||||
) { openLink(mContext, BuildConfig.STORE_LINK) }
|
) { openLink(mContext, BuildConfig.STORE_LINK) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,18 +27,25 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.sadellie.unitto.FirebaseHelper
|
import com.sadellie.unitto.FirebaseHelper
|
||||||
import com.sadellie.unitto.data.preferences.UserPreferences
|
import com.sadellie.unitto.data.preferences.UserPreferences
|
||||||
import com.sadellie.unitto.data.preferences.UserPreferencesRepository
|
import com.sadellie.unitto.data.preferences.UserPreferencesRepository
|
||||||
|
import com.sadellie.unitto.data.units.UnitGroup
|
||||||
|
import com.sadellie.unitto.data.units.UnitGroupsRepository
|
||||||
import com.sadellie.unitto.screens.Formatter
|
import com.sadellie.unitto.screens.Formatter
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import io.github.sadellie.themmo.ThemingMode
|
import io.github.sadellie.themmo.ThemingMode
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.burnoutcrew.reorderable.ItemPosition
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SettingsViewModel @Inject constructor(
|
class SettingsViewModel @Inject constructor(
|
||||||
private val userPrefsRepository: UserPreferencesRepository,
|
private val userPrefsRepository: UserPreferencesRepository,
|
||||||
|
private val unitGroupsRepository: UnitGroupsRepository,
|
||||||
private val application: Application,
|
private val application: Application,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
var userPrefs: UserPreferences by mutableStateOf(UserPreferences())
|
var userPrefs: UserPreferences by mutableStateOf(UserPreferences())
|
||||||
|
val shownUnitGroups = unitGroupsRepository.shownUnitGroups
|
||||||
|
val hiddenUnitGroups = unitGroupsRepository.hiddenUnitGroups
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see [UserPreferencesRepository.updateThemingMode]
|
* @see [UserPreferencesRepository.updateThemingMode]
|
||||||
@ -104,8 +111,53 @@ class SettingsViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See [UnitGroupsRepository.markUnitGroupAsHidden] and
|
||||||
|
* [UserPreferencesRepository.updateShownUnitGroups]
|
||||||
|
*/
|
||||||
|
fun hideUnitGroup(unitGroup: UnitGroup) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
unitGroupsRepository.markUnitGroupAsHidden(unitGroup)
|
||||||
|
userPrefsRepository.updateShownUnitGroups(unitGroupsRepository.shownUnitGroups.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See [UnitGroupsRepository.markUnitGroupAsShown] and
|
||||||
|
* [UserPreferencesRepository.updateShownUnitGroups]
|
||||||
|
*/
|
||||||
|
fun returnUnitGroup(unitGroup: UnitGroup) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
unitGroupsRepository.markUnitGroupAsShown(unitGroup)
|
||||||
|
userPrefsRepository.updateShownUnitGroups(unitGroupsRepository.shownUnitGroups.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See [UnitGroupsRepository.moveShownUnitGroups] and
|
||||||
|
* [UserPreferencesRepository.updateShownUnitGroups]
|
||||||
|
*/
|
||||||
|
fun onMove(from: ItemPosition, to: ItemPosition) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
unitGroupsRepository.moveShownUnitGroups(from, to)
|
||||||
|
userPrefsRepository.updateShownUnitGroups(unitGroupsRepository.shownUnitGroups.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent from dragging over non-draggable items (headers and hidden)
|
||||||
|
*
|
||||||
|
* @param pos Position we are dragging over.
|
||||||
|
* @return True if can drag over given item.
|
||||||
|
*/
|
||||||
|
fun canDragOver(pos: ItemPosition) = shownUnitGroups.value.any { it == pos.key }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
unitGroupsRepository.updateShownGroups(
|
||||||
|
userPrefsRepository.userPreferencesFlow.first().shownUnitGroups
|
||||||
|
)
|
||||||
|
|
||||||
userPrefsRepository.userPreferencesFlow.collect {
|
userPrefsRepository.userPreferencesFlow.collect {
|
||||||
userPrefs = it
|
userPrefs = it
|
||||||
Formatter.setSeparator(it.separator)
|
Formatter.setSeparator(it.separator)
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Unitto is a unit converter for Android
|
||||||
|
* Copyright (c) 2022 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.screens.setttings
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.sadellie.unitto.R
|
||||||
|
import com.sadellie.unitto.screens.common.UnittoLargeTopAppBar
|
||||||
|
import com.sadellie.unitto.screens.second.components.Header
|
||||||
|
import com.sadellie.unitto.screens.setttings.components.SettingsListItem
|
||||||
|
import org.burnoutcrew.reorderable.ReorderableItem
|
||||||
|
import org.burnoutcrew.reorderable.detectReorderAfterLongPress
|
||||||
|
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
|
||||||
|
import org.burnoutcrew.reorderable.reorderable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UnitGroupsScreen(
|
||||||
|
viewModel: SettingsViewModel,
|
||||||
|
navigateUpAction: () -> Unit
|
||||||
|
) {
|
||||||
|
UnittoLargeTopAppBar(
|
||||||
|
title = stringResource(R.string.unit_groups_setting),
|
||||||
|
navigateUpAction = navigateUpAction
|
||||||
|
) { paddingValues ->
|
||||||
|
|
||||||
|
val shownUnits = viewModel.shownUnitGroups.collectAsState()
|
||||||
|
val hiddenUnits = viewModel.hiddenUnitGroups.collectAsState()
|
||||||
|
|
||||||
|
val state = rememberReorderableLazyListState(
|
||||||
|
onMove = viewModel::onMove,
|
||||||
|
canDragOver = viewModel::canDragOver
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
state = state.listState,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
|
.reorderable(state)
|
||||||
|
.detectReorderAfterLongPress(state)
|
||||||
|
) {
|
||||||
|
item(key = "enabled") {
|
||||||
|
Header(text = "Enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
items(shownUnits.value, { it }) { item ->
|
||||||
|
ReorderableItem(state, key = item) { isDragging ->
|
||||||
|
val background = animateColorAsState(
|
||||||
|
if (isDragging) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface
|
||||||
|
)
|
||||||
|
val cornerRadius = animateDpAsState(if (isDragging) 16.dp else 0.dp)
|
||||||
|
|
||||||
|
SettingsListItem(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = cornerRadius.value)
|
||||||
|
.clip(RoundedCornerShape(cornerRadius.value))
|
||||||
|
.background(background.value),
|
||||||
|
label = stringResource(item.res),
|
||||||
|
onClick = { viewModel.hideUnitGroup(item) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item(key = "disabled") {
|
||||||
|
Header(
|
||||||
|
text = "Disabled",
|
||||||
|
modifier = Modifier.animateItemPlacement()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
items(hiddenUnits.value, { it }) {
|
||||||
|
SettingsListItem(
|
||||||
|
modifier = Modifier.animateItemPlacement(),
|
||||||
|
label = stringResource(it.res),
|
||||||
|
onClick = { viewModel.returnUnitGroup(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -59,6 +59,7 @@ import com.sadellie.unitto.R
|
|||||||
* This component can be easily modified if you provide additional component to it,
|
* This component can be easily modified if you provide additional component to it,
|
||||||
* for example a switch or a checkbox.
|
* for example a switch or a checkbox.
|
||||||
*
|
*
|
||||||
|
* @param modifier Modifier that will be applied to a Row.
|
||||||
* @param label Main text.
|
* @param label Main text.
|
||||||
* @param supportText Text that is located below label.
|
* @param supportText Text that is located below label.
|
||||||
* @param onClick Action to perform when user clicks on this component (whole component is clickable).
|
* @param onClick Action to perform when user clicks on this component (whole component is clickable).
|
||||||
@ -66,13 +67,14 @@ import com.sadellie.unitto.R
|
|||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
private fun BasicSettingsListItem(
|
private fun BasicSettingsListItem(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
label: String,
|
label: String,
|
||||||
supportText: String? = null,
|
supportText: String? = null,
|
||||||
onClick: () -> Unit = {},
|
onClick: () -> Unit = {},
|
||||||
content: @Composable RowScope.() -> Unit = {}
|
content: @Composable RowScope.() -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable(
|
.clickable(
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
@ -111,16 +113,18 @@ private fun BasicSettingsListItem(
|
|||||||
/**
|
/**
|
||||||
* Represents one item in list on Settings screen.
|
* Represents one item in list on Settings screen.
|
||||||
*
|
*
|
||||||
|
* @param modifier Modifier that will be applied to a Row.
|
||||||
* @param label Main text.
|
* @param label Main text.
|
||||||
* @param supportText Text that is located below label.
|
* @param supportText Text that is located below label.
|
||||||
* @param onClick Action to perform when user clicks on this component (whole component is clickable).
|
* @param onClick Action to perform when user clicks on this component (whole component is clickable).
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsListItem(
|
fun SettingsListItem(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
label: String,
|
label: String,
|
||||||
supportText: String? = null,
|
supportText: String? = null,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) = BasicSettingsListItem(label, supportText, onClick)
|
) = BasicSettingsListItem(modifier, label, supportText, onClick)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents one item in list on Settings screen.
|
* Represents one item in list on Settings screen.
|
||||||
@ -137,7 +141,7 @@ fun SettingsListItem(
|
|||||||
supportText: String? = null,
|
supportText: String? = null,
|
||||||
switchState: Boolean,
|
switchState: Boolean,
|
||||||
onSwitchChange: (Boolean) -> Unit
|
onSwitchChange: (Boolean) -> Unit
|
||||||
) = BasicSettingsListItem(label, supportText, { onSwitchChange(!switchState) }) {
|
) = BasicSettingsListItem(Modifier, label, supportText, { onSwitchChange(!switchState) }) {
|
||||||
Switch(checked = switchState, onCheckedChange = { onSwitchChange(it) })
|
Switch(checked = switchState, onCheckedChange = { onSwitchChange(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +162,7 @@ fun <T> SettingsListItem(
|
|||||||
allOptions: Map<T, String>,
|
allOptions: Map<T, String>,
|
||||||
selected: T,
|
selected: T,
|
||||||
onSelectedChange: (T) -> Unit
|
onSelectedChange: (T) -> Unit
|
||||||
) = BasicSettingsListItem(label, supportText, {}) {
|
) = BasicSettingsListItem(Modifier, label, supportText, {}) {
|
||||||
var dropDownExpanded by rememberSaveable { mutableStateOf(false) }
|
var dropDownExpanded by rememberSaveable { mutableStateOf(false) }
|
||||||
var currentOption by rememberSaveable { mutableStateOf(selected) }
|
var currentOption by rememberSaveable { mutableStateOf(selected) }
|
||||||
val dropDownRotation: Float by animateFloatAsState(
|
val dropDownRotation: Float by animateFloatAsState(
|
||||||
|
@ -741,5 +741,6 @@
|
|||||||
<string name="color_theme">Colour theme</string>
|
<string name="color_theme">Colour theme</string>
|
||||||
<string name="drop_down_description">Open or close drop down menu</string>
|
<string name="drop_down_description">Open or close drop down menu</string>
|
||||||
<string name="hello_label">Hello!</string>
|
<string name="hello_label">Hello!</string>
|
||||||
|
<string name="unit_groups_setting">Unit groups</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -676,5 +676,6 @@
|
|||||||
<string name="color_theme">Цветовая тема</string>
|
<string name="color_theme">Цветовая тема</string>
|
||||||
<string name="drop_down_description">Открыть или закрыть меню</string>
|
<string name="drop_down_description">Открыть или закрыть меню</string>
|
||||||
<string name="hello_label">Привет!</string>
|
<string name="hello_label">Привет!</string>
|
||||||
|
<string name="unit_groups_setting">Группы величин</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -940,6 +940,7 @@
|
|||||||
<string name="precision_setting">Precision</string>
|
<string name="precision_setting">Precision</string>
|
||||||
<string name="separator_setting">Separator</string>
|
<string name="separator_setting">Separator</string>
|
||||||
<string name="output_format_setting">Output format</string>
|
<string name="output_format_setting">Output format</string>
|
||||||
|
<string name="unit_groups_setting">Unit groups</string>
|
||||||
<string name="currency_rates_note_setting">Wrong currency rates?</string>
|
<string name="currency_rates_note_setting">Wrong currency rates?</string>
|
||||||
<string name="currency_rates_note_title">Note</string>
|
<string name="currency_rates_note_title">Note</string>
|
||||||
<string name="currency_rates_note_text">Currency rates are updated daily. There\'s no real-time market monitoring in the app</string>
|
<string name="currency_rates_note_text">Currency rates are updated daily. There\'s no real-time market monitoring in the app</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user