Reorganize settings

This commit is contained in:
Sad Ellie 2023-09-22 13:21:27 +03:00
parent 49f1520d88
commit c213292f51
9 changed files with 259 additions and 154 deletions

View File

@ -1418,4 +1418,5 @@ Used in this dialog window. Should be short -->
<string name="partial_history_view_setting_support">Peek latest entrance in history</string>
<string name="calculator_settings_support">History view</string>
<string name="converter_settings_support">Unit groups, sorting, formatting</string>
<string name="display_settings">Display</string>
</resources>

View File

@ -81,7 +81,6 @@ data class AppPreferences(
data class GeneralPreferences(
val enableVibrations: Boolean = true,
val middleZero: Boolean = false,
)
data class CalculatorPreferences(
@ -109,8 +108,9 @@ data class ConverterPreferences(
val latestRightSideUnit: String = MyUnitIDS.mile,
)
data class ThemePreferences(
data class DisplayPreferences(
val systemFont: Boolean = false,
val middleZero: Boolean = false,
)
data class FormattingPreferences(
@ -164,7 +164,6 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
.map { preferences ->
GeneralPreferences(
enableVibrations = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true,
middleZero = preferences[PrefsKeys.MIDDLE_ZERO] ?: false,
)
}
@ -205,10 +204,11 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
)
}
val themePrefs: Flow<ThemePreferences> = data
val displayPrefs: Flow<DisplayPreferences> = data
.map { preferences ->
ThemePreferences(
systemFont = preferences[PrefsKeys.SYSTEM_FONT] ?: false
DisplayPreferences(
systemFont = preferences[PrefsKeys.SYSTEM_FONT] ?: false,
middleZero = preferences[PrefsKeys.MIDDLE_ZERO] ?: false,
)
}

View File

@ -18,30 +18,22 @@
package com.sadellie.unitto.feature.settings
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.clickable
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Calculate
import androidx.compose.material.icons.filled.ExposureZero
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.RateReview
import androidx.compose.material.icons.filled.SwapHoriz
import androidx.compose.material.icons.filled.Vibration
import androidx.compose.material.icons.filled._123
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
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 androidx.core.os.LocaleListCompat
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.BuildConfig
@ -52,13 +44,12 @@ import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.data.userprefs.GeneralPreferences
import com.sadellie.unitto.feature.settings.components.AlertDialogWithList
import com.sadellie.unitto.feature.settings.navigation.aboutRoute
import com.sadellie.unitto.feature.settings.navigation.calculatorSettingsRoute
import com.sadellie.unitto.feature.settings.navigation.converterSettingsRoute
import com.sadellie.unitto.feature.settings.navigation.displayRoute
import com.sadellie.unitto.feature.settings.navigation.formattingRoute
import com.sadellie.unitto.feature.settings.navigation.startingScreenRoute
import com.sadellie.unitto.feature.settings.navigation.themesRoute
@Composable
internal fun SettingsRoute(
@ -72,7 +63,6 @@ internal fun SettingsRoute(
userPrefs = userPrefs.value,
navigateUp = navigateUp,
navControllerAction = navControllerAction,
updateMiddleZero = viewModel::updateMiddleZero,
updateVibrations = viewModel::updateVibrations,
)
}
@ -82,11 +72,9 @@ private fun SettingsScreen(
userPrefs: GeneralPreferences,
navigateUp: () -> Unit,
navControllerAction: (String) -> Unit,
updateMiddleZero: (Boolean) -> Unit,
updateVibrations: (Boolean) -> Unit,
) {
val mContext = LocalContext.current
var dialogState: DialogState by rememberSaveable { mutableStateOf(DialogState.NONE) }
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.settings_screen),
@ -98,10 +86,10 @@ private fun SettingsScreen(
item {
UnittoListItem(
icon = Icons.Default.Palette,
iconDescription = stringResource(R.string.theme_setting),
headlineText = stringResource(R.string.theme_setting),
iconDescription = stringResource(R.string.display_settings),
headlineText = stringResource(R.string.display_settings),
supportingText = stringResource(R.string.theme_setting_support),
modifier = Modifier.clickable { navControllerAction(themesRoute) }
modifier = Modifier.clickable { navControllerAction(displayRoute) }
)
}
@ -150,19 +138,6 @@ private fun SettingsScreen(
// ADDITIONAL GROUP
item { Header(stringResource(R.string.additional_settings_group)) }
// MIDDLE ZERO
item {
UnittoListItem(
icon = Icons.Default.ExposureZero,
iconDescription = stringResource(R.string.middle_zero_option),
headlineText = stringResource(R.string.middle_zero_option),
supportingText = stringResource(R.string.middle_zero_option_support),
modifier = Modifier.clickable { navControllerAction(converterSettingsRoute) },
switchState = userPrefs.middleZero,
onSwitchChange = updateMiddleZero
)
}
// VIBRATIONS
item {
UnittoListItem(
@ -176,17 +151,6 @@ private fun SettingsScreen(
)
}
// LANGUAGE
item {
UnittoListItem(
icon = Icons.Default.Language,
iconDescription = stringResource(R.string.language_setting),
headlineText = stringResource(R.string.language_setting),
supportingText = stringResource(R.string.language_setting_support),
modifier = Modifier.clickable { dialogState = DialogState.LANGUAGE }
)
}
// RATE THIS APP
if (BuildConfig.STORE_LINK.isNotEmpty()) {
item {
@ -211,48 +175,6 @@ private fun SettingsScreen(
}
}
}
/**
* Function to reset currently displayed dialog.
*/
fun resetDialog() {
dialogState = DialogState.NONE
}
// Showing dialog
when (dialogState) {
DialogState.LANGUAGE -> {
AlertDialogWithList(
title = stringResource(R.string.language_setting),
listItems = mapOf(
"" to R.string.auto_label,
"en" to R.string.locale_en,
"de" to R.string.locale_de,
"en_rGB" to R.string.locale_en_rGB,
"fr" to R.string.locale_fr,
"it" to R.string.locale_it,
"ru" to R.string.locale_ru,
),
selectedItemIndex = AppCompatDelegate.getApplicationLocales().toLanguageTags(),
selectAction = {
val selectedLocale = if (it == "") LocaleListCompat.getEmptyLocaleList()
else LocaleListCompat.forLanguageTags(it)
AppCompatDelegate.setApplicationLocales(selectedLocale)
},
dismissAction = { resetDialog() }
)
}
// Dismissing alert dialog
else -> {}
}
}
/**
* All possible states for alert dialog that opens when user clicks on settings.
*/
private enum class DialogState {
NONE, LANGUAGE
}
@Preview
@ -262,7 +184,6 @@ private fun PreviewSettingsScreen() {
userPrefs = GeneralPreferences(),
navigateUp = {},
navControllerAction = {},
updateMiddleZero = {},
updateVibrations = {},
)
}

View File

@ -40,11 +40,4 @@ internal class SettingsViewModel @Inject constructor(
fun updateVibrations(enabled: Boolean) = viewModelScope.launch {
userPrefsRepository.updateVibrations(enabled)
}
/**
* @see UserPreferencesRepository.updateMiddleZero
*/
fun updateMiddleZero(enabled: Boolean) = viewModelScope.launch {
userPrefsRepository.updateMiddleZero(enabled)
}
}

View File

@ -29,7 +29,6 @@ import androidx.compose.material.icons.filled.Copyright
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Policy
import androidx.compose.material.icons.filled.PrivacyTip
import androidx.compose.material.icons.filled.Translate
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
@ -122,22 +121,6 @@ internal fun AboutScreen(
)
}
// TRANSLATE
item {
UnittoListItem(
icon = Icons.Default.Translate,
iconDescription = stringResource(R.string.translate_app),
headlineText = stringResource(R.string.translate_app),
supportingText = stringResource(R.string.translate_app_support),
modifier = Modifier.clickable {
openLink(
mContext,
"https://poeditor.com/join/project/T4zjmoq8dx"
)
}
)
}
// THIRD PARTY
item {
UnittoListItem(

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.feature.settings.themes
package com.sadellie.unitto.feature.settings.display
import android.os.Build
import androidx.compose.animation.AnimatedVisibility
@ -24,6 +24,7 @@ import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
@ -33,7 +34,9 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Colorize
import androidx.compose.material.icons.filled.DarkMode
import androidx.compose.material.icons.filled.ExposureZero
import androidx.compose.material.icons.filled.FontDownload
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.outlined.DarkMode
import androidx.compose.material.icons.outlined.HdrAuto
@ -79,15 +82,16 @@ private val colorSchemes: List<Color> by lazy {
}
@Composable
internal fun ThemesRoute(
viewModel: ThemesViewModel = hiltViewModel(),
navigateUpAction: () -> Unit = {},
internal fun DisplayRoute(
viewModel: DisplayViewModel = hiltViewModel(),
navigateUp: () -> Unit = {},
themmoController: ThemmoController,
navigateToLanguages: () -> Unit
) {
val systemFont = viewModel.systemFont.collectAsStateWithLifecycle()
val prefs = viewModel.prefs.collectAsStateWithLifecycle()
ThemesScreen(
navigateUpAction = navigateUpAction,
DisplayScreen(
navigateUp = navigateUp,
currentThemingMode = themmoController.currentThemingMode,
onThemeChange = {
themmoController.setThemingMode(it)
@ -118,14 +122,17 @@ internal fun ThemesRoute(
themmoController.setMonetMode(it)
viewModel.updateMonetMode(it)
},
systemFont = systemFont.value,
onSystemFontChange = viewModel::updateSystemFont
systemFont = prefs.value.systemFont,
updateSystemFont = viewModel::updateSystemFont,
middleZero = prefs.value.middleZero,
updateMiddleZero = viewModel::updateMiddleZero,
navigateToLanguages = navigateToLanguages
)
}
@Composable
private fun ThemesScreen(
navigateUpAction: () -> Unit,
private fun DisplayScreen(
navigateUp: () -> Unit,
currentThemingMode: ThemingMode,
onThemeChange: (ThemingMode) -> Unit,
isDynamicThemeEnabled: Boolean,
@ -137,14 +144,19 @@ private fun ThemesScreen(
monetMode: MonetMode,
onMonetModeChange: (MonetMode) -> Unit,
systemFont: Boolean,
onSystemFontChange: (Boolean) -> Unit,
updateSystemFont: (Boolean) -> Unit,
middleZero: Boolean,
updateMiddleZero: (Boolean) -> Unit,
navigateToLanguages: () -> Unit,
) {
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.theme_setting),
navigationIcon = { NavigateUpButton(navigateUpAction) }
title = stringResource(R.string.display_settings),
navigationIcon = { NavigateUpButton(navigateUp) }
) { paddingValues ->
LazyColumn(contentPadding = paddingValues) {
item { Header(stringResource(R.string.color_scheme)) }
item {
UnittoListItem(
leadingContent = {
@ -204,20 +216,7 @@ private fun ThemesScreen(
}
}
item {
UnittoListItem(
icon = Icons.Default.FontDownload,
iconDescription = stringResource(R.string.system_font_setting),
headlineText = stringResource(R.string.system_font_setting),
supportingText = stringResource(R.string.system_font_setting_support),
switchState = systemFont,
onSwitchChange = onSystemFontChange
)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
item { Header(stringResource(R.string.color_scheme)) }
item {
UnittoListItem(
icon = Icons.Default.Colorize,
@ -274,6 +273,42 @@ private fun ThemesScreen(
}
}
}
item { Header(stringResource(R.string.additional_settings_group)) }
item {
UnittoListItem(
icon = Icons.Default.FontDownload,
iconDescription = stringResource(R.string.system_font_setting),
headlineText = stringResource(R.string.system_font_setting),
supportingText = stringResource(R.string.system_font_setting_support),
switchState = systemFont,
onSwitchChange = updateSystemFont
)
}
// MIDDLE ZERO
item {
UnittoListItem(
icon = Icons.Default.ExposureZero,
iconDescription = stringResource(R.string.middle_zero_option),
headlineText = stringResource(R.string.middle_zero_option),
supportingText = stringResource(R.string.middle_zero_option_support),
switchState = middleZero,
onSwitchChange = updateMiddleZero
)
}
// LANGUAGE
item {
UnittoListItem(
icon = Icons.Default.Language,
iconDescription = stringResource(R.string.language_setting),
headlineText = stringResource(R.string.language_setting),
supportingText = stringResource(R.string.language_setting_support),
modifier = Modifier.clickable { navigateToLanguages() }
)
}
}
}
}
@ -282,8 +317,8 @@ private fun ThemesScreen(
@Composable
private fun Preview() {
Themmo { themmoController ->
ThemesScreen(
navigateUpAction = {},
DisplayScreen(
navigateUp = {},
currentThemingMode = themmoController.currentThemingMode,
onThemeChange = themmoController::setThemingMode,
isDynamicThemeEnabled = themmoController.isDynamicThemeEnabled,
@ -295,7 +330,10 @@ private fun Preview() {
monetMode = themmoController.currentMonetMode,
onMonetModeChange = themmoController::setMonetMode,
systemFont = false,
onSystemFontChange = {}
updateSystemFont = {},
middleZero = false,
updateMiddleZero = {},
navigateToLanguages = {}
)
}
}

View File

@ -16,28 +16,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.feature.settings.themes
package com.sadellie.unitto.feature.settings.display
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sadellie.unitto.data.common.stateIn
import com.sadellie.unitto.data.userprefs.DisplayPreferences
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.sadellie.themmo.MonetMode
import io.github.sadellie.themmo.ThemingMode
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ThemesViewModel @Inject constructor(
class DisplayViewModel @Inject constructor(
private val userPrefsRepository: UserPreferencesRepository
) : ViewModel() {
val systemFont = userPrefsRepository.themePrefs
.map { it.systemFont }
.stateIn(viewModelScope, false)
val prefs = userPrefsRepository.displayPrefs
.stateIn(viewModelScope, DisplayPreferences())
/**
* @see UserPreferencesRepository.updateThemingMode
@ -92,4 +91,8 @@ class ThemesViewModel @Inject constructor(
userPrefsRepository.updateSystemFont(enabled)
}
}
fun updateMiddleZero(enabled: Boolean) = viewModelScope.launch {
userPrefsRepository.updateMiddleZero(enabled)
}
}

View File

@ -0,0 +1,157 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2023 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.settings.language
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Translate
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.os.LocaleListCompat
import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.common.squashable
import com.sadellie.unitto.core.ui.openLink
private val languages = mapOf(
"" to R.string.auto_label,
"en" to R.string.locale_en,
"en_rGB" to R.string.locale_en_rGB,
"de" to R.string.locale_de,
"fr" to R.string.locale_fr,
"it" to R.string.locale_it,
"ru" to R.string.locale_ru,
)
@Composable
internal fun LanguageRoute(
navigateUp: () -> Unit,
) {
LanguageScreen(
navigateUp = navigateUp
)
}
@Composable
private fun LanguageScreen(
navigateUp: () -> Unit,
) {
val mContext = LocalContext.current
val currentLangKey = AppCompatDelegate.getApplicationLocales().toLanguageTags()
UnittoScreenWithLargeTopBar(
title = stringResource(R.string.language_setting),
navigationIcon = { NavigateUpButton(navigateUp) }
) { padding ->
LazyColumn(contentPadding = padding) {
item("translate") {
Box(Modifier.padding(16.dp, 8.dp)) {
Row(
modifier = Modifier
.squashable(
onClick = {
openLink(mContext, "https://poeditor.com/join/project/T4zjmoq8dx")
},
interactionSource = remember { MutableInteractionSource() },
cornerRadiusRange = 15..50
)
.background(MaterialTheme.colorScheme.secondaryContainer)
.padding(16.dp, 4.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.Translate,
contentDescription = stringResource(R.string.translate_app),
modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
Column(Modifier.weight(1f).padding(vertical = 8.dp)) {
Text(
text = stringResource(R.string.translate_app),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSecondaryContainer,
)
Text(
text = stringResource(R.string.translate_app_support),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSecondaryContainer,
)
}
}
}
}
languages.forEach { (key, res) ->
item(key) {
UnittoListItem(
modifier = Modifier.clickable { changeLanguage(key) },
headlineContent = {
Text(stringResource(res))
},
leadingContent = {
RadioButton(
selected = currentLangKey == key,
onClick = { changeLanguage(key) }
)
}
)
}
}
}
}
}
private fun changeLanguage(langKey: String) {
val selectedLocale = if (langKey == "") LocaleListCompat.getEmptyLocaleList()
else LocaleListCompat.forLanguageTags(langKey)
AppCompatDelegate.setApplicationLocales(selectedLocale)
}
@Preview
@Composable
fun LanguageScreenPreview() {
LanguageScreen(
navigateUp = {}
)
}

View File

@ -30,15 +30,17 @@ import com.sadellie.unitto.feature.settings.about.AboutScreen
import com.sadellie.unitto.feature.settings.calculator.CalculatorSettingsScreen
import com.sadellie.unitto.feature.settings.converter.ConverterSettingsScreen
import com.sadellie.unitto.feature.settings.formatting.FormattingRoute
import com.sadellie.unitto.feature.settings.language.LanguageRoute
import com.sadellie.unitto.feature.settings.startingscreen.StartingScreenRoute
import com.sadellie.unitto.feature.settings.themes.ThemesRoute
import com.sadellie.unitto.feature.settings.display.DisplayRoute
import com.sadellie.unitto.feature.settings.thirdparty.ThirdPartyLicensesScreen
import com.sadellie.unitto.feature.settings.unitgroups.UnitGroupsScreen
import io.github.sadellie.themmo.ThemmoController
private val graph = TopLevelDestinations.Settings.graph
private val start = TopLevelDestinations.Settings.start
internal const val themesRoute = "themes_route"
internal const val displayRoute = "display_route"
internal const val languageRoute = "language_route"
internal const val startingScreenRoute = "starting_screen_route"
internal const val unitsGroupRoute = "units_group_route"
internal const val thirdPartyRoute = "third_party_route"
@ -73,10 +75,17 @@ fun NavGraphBuilder.settingGraph(
)
}
unittoComposable(themesRoute) {
ThemesRoute(
navigateUpAction = navController::navigateUp,
unittoComposable(displayRoute) {
DisplayRoute(
navigateUp = navController::navigateUp,
themmoController = themmoController,
navigateToLanguages = { navController.navigate(languageRoute) }
)
}
unittoComposable(languageRoute) {
LanguageRoute(
navigateUp = navController::navigateUp,
)
}