Start screen option

This commit is contained in:
Sad Ellie 2023-02-22 10:19:06 +04:00
parent 30b97ef821
commit f92488f336
12 changed files with 123 additions and 25 deletions

View File

@ -45,7 +45,7 @@ fun UnittoApp() {
val themmoController = rememberThemmoController( val themmoController = rememberThemmoController(
lightColorScheme = LightThemeColors, lightColorScheme = LightThemeColors,
darkColorScheme = DarkThemeColors, darkColorScheme = DarkThemeColors,
// Anything below will not called if theming mode is still loading from DataStore // Anything below will not be called if theming mode is still loading from DataStore
themingMode = userPrefs.value.themingMode ?: return, themingMode = userPrefs.value.themingMode ?: return,
dynamicThemeEnabled = userPrefs.value.enableDynamicTheme, dynamicThemeEnabled = userPrefs.value.enableDynamicTheme,
amoledThemeEnabled = userPrefs.value.enableAmoledTheme amoledThemeEnabled = userPrefs.value.enableAmoledTheme
@ -65,7 +65,8 @@ fun UnittoApp() {
converterViewModel = converterViewModel, converterViewModel = converterViewModel,
secondViewModel = secondViewModel, secondViewModel = secondViewModel,
settingsViewModel = settingsViewModel, settingsViewModel = settingsViewModel,
themmoController = it themmoController = it,
startDestination = userPrefs.value.startingScreen
) )
SideEffect { sysUiController.setSystemBarsColor(backgroundColor) } SideEffect { sysUiController.setSystemBarsColor(backgroundColor) }

View File

@ -26,7 +26,6 @@ import androidx.navigation.compose.NavHost
import com.sadellie.unitto.feature.calculator.navigation.calculatorScreen import com.sadellie.unitto.feature.calculator.navigation.calculatorScreen
import com.sadellie.unitto.feature.calculator.navigation.navigateToCalculator import com.sadellie.unitto.feature.calculator.navigation.navigateToCalculator
import com.sadellie.unitto.feature.converter.ConverterViewModel import com.sadellie.unitto.feature.converter.ConverterViewModel
import com.sadellie.unitto.feature.converter.navigation.converterRoute
import com.sadellie.unitto.feature.converter.navigation.converterScreen import com.sadellie.unitto.feature.converter.navigation.converterScreen
import com.sadellie.unitto.feature.converter.navigation.navigateToConverter import com.sadellie.unitto.feature.converter.navigation.navigateToConverter
import com.sadellie.unitto.feature.epoch.navigation.epochScreen import com.sadellie.unitto.feature.epoch.navigation.epochScreen
@ -50,11 +49,12 @@ fun UnittoNavigation(
converterViewModel: ConverterViewModel, converterViewModel: ConverterViewModel,
secondViewModel: SecondViewModel, secondViewModel: SecondViewModel,
settingsViewModel: SettingsViewModel, settingsViewModel: SettingsViewModel,
themmoController: ThemmoController themmoController: ThemmoController,
startDestination: String
) { ) {
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = converterRoute startDestination = startDestination
) { ) {
converterScreen( converterScreen(
navigateToLeftScreen = navController::navigateToLeftSide, navigateToLeftScreen = navController::navigateToLeftSide,

View File

@ -0,0 +1,32 @@
/*
* 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.core.base
object TopLevelDestinations {
const val CONVERTER = "converter_route"
const val CALCULATOR = "calculator_route"
const val EPOCH = "epoch_route"
}
val TOP_LEVEL_DESTINATIONS: Map<String, Int> by lazy {
mapOf(
TopLevelDestinations.CONVERTER to R.string.unit_converter,
TopLevelDestinations.CALCULATOR to R.string.calculator,
)
}

View File

@ -999,6 +999,8 @@
<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="starting_screen_setting">Starting screen</string>
<string name="starting_screen_setting_support">Choose which screen is shown when you launch the app</string>
<string name="unit_groups_setting">Unit groups</string> <string name="unit_groups_setting">Unit groups</string>
<string name="enable_vibrations">Vibrations</string> <string name="enable_vibrations">Vibrations</string>
<string name="enable_vibrations_support">Haptic feedback when clicking keyboard buttons</string> <string name="enable_vibrations_support">Haptic feedback when clicking keyboard buttons</string>

View File

@ -27,6 +27,7 @@ import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey
import com.sadellie.unitto.core.base.OutputFormat import com.sadellie.unitto.core.base.OutputFormat
import com.sadellie.unitto.core.base.Separator import com.sadellie.unitto.core.base.Separator
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
import com.sadellie.unitto.data.model.AbstractUnit import com.sadellie.unitto.data.model.AbstractUnit
import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitGroup
@ -65,7 +66,8 @@ data class UserPreferences(
val latestRightSideUnit: String = MyUnitIDS.mile, val latestRightSideUnit: String = MyUnitIDS.mile,
val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS, val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS,
val enableVibrations: Boolean = true, val enableVibrations: Boolean = true,
val enableToolsExperiment: Boolean = false val enableToolsExperiment: Boolean = false,
val startingScreen: String = TopLevelDestinations.CONVERTER
) )
/** /**
@ -87,6 +89,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
val SHOWN_UNIT_GROUPS = stringPreferencesKey("SHOWN_UNIT_GROUPS_PREF_KEY") val SHOWN_UNIT_GROUPS = stringPreferencesKey("SHOWN_UNIT_GROUPS_PREF_KEY")
val ENABLE_VIBRATIONS = booleanPreferencesKey("ENABLE_VIBRATIONS_PREF_KEY") val ENABLE_VIBRATIONS = booleanPreferencesKey("ENABLE_VIBRATIONS_PREF_KEY")
val ENABLE_TOOLS_EXPERIMENT = booleanPreferencesKey("ENABLE_TOOLS_EXPERIMENT_PREF_KEY") val ENABLE_TOOLS_EXPERIMENT = booleanPreferencesKey("ENABLE_TOOLS_EXPERIMENT_PREF_KEY")
val STARTING_SCREEN = stringPreferencesKey("STARTING_SCREEN_PREF_KEY")
} }
val userPreferencesFlow: Flow<UserPreferences> = dataStore.data val userPreferencesFlow: Flow<UserPreferences> = dataStore.data
@ -130,6 +133,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
} ?: ALL_UNIT_GROUPS } ?: ALL_UNIT_GROUPS
val enableVibrations: Boolean = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true val enableVibrations: Boolean = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true
val enableToolsExperiment: Boolean = preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false val enableToolsExperiment: Boolean = preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false
val startingScreen: String = preferences[PrefsKeys.STARTING_SCREEN] ?: TopLevelDestinations.CONVERTER
UserPreferences( UserPreferences(
themingMode = themingMode, themingMode = themingMode,
@ -142,7 +146,8 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
latestRightSideUnit = latestRightSideUnit, latestRightSideUnit = latestRightSideUnit,
shownUnitGroups = shownUnitGroups, shownUnitGroups = shownUnitGroups,
enableVibrations = enableVibrations, enableVibrations = enableVibrations,
enableToolsExperiment = enableToolsExperiment enableToolsExperiment = enableToolsExperiment,
startingScreen = startingScreen
) )
} }
@ -226,6 +231,17 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
} }
} }
/**
* Update preference on starting screen route.
*
* @param startingScreen Route from [TopLevelDestinations].
*/
suspend fun updateStartingScreen(startingScreen: String) {
dataStore.edit { preferences ->
preferences[PrefsKeys.STARTING_SCREEN] = startingScreen
}
}
suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>) { suspend fun updateShownUnitGroups(shownUnitGroups: List<UnitGroup>) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[PrefsKeys.SHOWN_UNIT_GROUPS] = shownUnitGroups.joinToString(",") preferences[PrefsKeys.SHOWN_UNIT_GROUPS] = shownUnitGroups.joinToString(",")

View File

@ -23,9 +23,10 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink import androidx.navigation.navDeepLink
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.feature.calculator.CalculatorRoute import com.sadellie.unitto.feature.calculator.CalculatorRoute
private const val calculatorRoute = "calculator_route" private const val calculatorRoute = TopLevelDestinations.CALCULATOR
fun NavController.navigateToCalculator(navOptions: NavOptions) { fun NavController.navigateToCalculator(navOptions: NavOptions) {
navigate(calculatorRoute, navOptions) navigate(calculatorRoute, navOptions)

View File

@ -22,10 +22,11 @@ import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.feature.converter.ConverterRoute import com.sadellie.unitto.feature.converter.ConverterRoute
import com.sadellie.unitto.feature.converter.ConverterViewModel import com.sadellie.unitto.feature.converter.ConverterViewModel
const val converterRoute = "converter_route" const val converterRoute = TopLevelDestinations.CONVERTER
fun NavController.navigateToConverter(navOptions: NavOptions) { fun NavController.navigateToConverter(navOptions: NavOptions) {
navigate(converterRoute, navOptions) navigate(converterRoute, navOptions)

View File

@ -23,9 +23,10 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink import androidx.navigation.navDeepLink
import com.sadellie.unitto.core.base.TopLevelDestinations
import com.sadellie.unitto.feature.epoch.EpochRoute import com.sadellie.unitto.feature.epoch.EpochRoute
private const val epochRoute = "epoch_route" private const val epochRoute = TopLevelDestinations.EPOCH
fun NavController.navigateToEpoch(navOptions: NavOptions) { fun NavController.navigateToEpoch(navOptions: NavOptions) {
navigate(epochRoute, navOptions) navigate(epochRoute, navOptions)

View File

@ -30,9 +30,11 @@ import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Policy import androidx.compose.material.icons.filled.Policy
import androidx.compose.material.icons.filled.PrivacyTip import androidx.compose.material.icons.filled.PrivacyTip
import androidx.compose.material.icons.filled.Translate import androidx.compose.material.icons.filled.Translate
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -46,7 +48,6 @@ import com.sadellie.unitto.core.base.BuildConfig
import com.sadellie.unitto.core.ui.R import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
import com.sadellie.unitto.core.ui.openLink import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.feature.settings.components.AlertDialogWithList
@Composable @Composable
internal fun AboutScreen( internal fun AboutScreen(
@ -198,11 +199,19 @@ internal fun AboutScreen(
} }
if (showDialog) { if (showDialog) {
AlertDialogWithList( AlertDialog(
title = stringResource(R.string.currency_rates_note_title), title = {
dismissAction = { showDialog = false }, Text(stringResource(R.string.currency_rates_note_title))
supportText = stringResource(R.string.currency_rates_note_text), },
dismissButtonLabel = stringResource(R.string.ok_label) text = {
Text(stringResource(R.string.currency_rates_note_text))
},
confirmButton = {
TextButton(onClick = { showDialog = false }) {
Text(stringResource(R.string.ok_label))
}
},
onDismissRequest = { showDialog = false }
) )
} }
} }

View File

@ -22,6 +22,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Palette import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.RateReview import androidx.compose.material.icons.filled.RateReview
@ -45,6 +46,7 @@ import com.sadellie.unitto.core.base.BuildConfig
import com.sadellie.unitto.core.base.OUTPUT_FORMAT import com.sadellie.unitto.core.base.OUTPUT_FORMAT
import com.sadellie.unitto.core.base.PRECISIONS import com.sadellie.unitto.core.base.PRECISIONS
import com.sadellie.unitto.core.base.SEPARATORS import com.sadellie.unitto.core.base.SEPARATORS
import com.sadellie.unitto.core.base.TOP_LEVEL_DESTINATIONS
import com.sadellie.unitto.core.ui.R import com.sadellie.unitto.core.ui.R
import com.sadellie.unitto.core.ui.common.Header import com.sadellie.unitto.core.ui.common.Header
import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar import com.sadellie.unitto.core.ui.common.UnittoLargeTopAppBar
@ -103,6 +105,21 @@ internal fun SettingsScreen(
) )
} }
// START SCREEN
item {
ListItem(
leadingContent = {
Icon(
Icons.Default.Home,
stringResource(R.string.starting_screen_setting),
)
},
headlineText = { Text(stringResource(R.string.starting_screen_setting)) },
supportingText = { Text(stringResource(R.string.starting_screen_setting_support)) },
modifier = Modifier.clickable { dialogState = DialogState.START_SCREEN }
)
}
// GENERAL GROUP // GENERAL GROUP
item { Header(stringResource(R.string.formatting_settings_group)) } item { Header(stringResource(R.string.formatting_settings_group)) }
@ -209,7 +226,7 @@ internal fun SettingsScreen(
title = stringResource(R.string.precision_setting), title = stringResource(R.string.precision_setting),
listItems = PRECISIONS, listItems = PRECISIONS,
selectedItemIndex = userPrefs.value.digitsPrecision, selectedItemIndex = userPrefs.value.digitsPrecision,
selectAction = { viewModel.updatePrecision(it) }, selectAction = viewModel::updatePrecision,
dismissAction = { resetDialog() }, dismissAction = { resetDialog() },
supportText = stringResource(R.string.precision_setting_info) supportText = stringResource(R.string.precision_setting_info)
) )
@ -219,7 +236,7 @@ internal fun SettingsScreen(
title = stringResource(R.string.separator_setting), title = stringResource(R.string.separator_setting),
listItems = SEPARATORS, listItems = SEPARATORS,
selectedItemIndex = userPrefs.value.separator, selectedItemIndex = userPrefs.value.separator,
selectAction = { viewModel.updateSeparator(it) }, selectAction = viewModel::updateSeparator,
dismissAction = { resetDialog() } dismissAction = { resetDialog() }
) )
} }
@ -228,11 +245,20 @@ internal fun SettingsScreen(
title = stringResource(R.string.output_format_setting), title = stringResource(R.string.output_format_setting),
listItems = OUTPUT_FORMAT, listItems = OUTPUT_FORMAT,
selectedItemIndex = userPrefs.value.outputFormat, selectedItemIndex = userPrefs.value.outputFormat,
selectAction = { viewModel.updateOutputFormat(it) }, selectAction = viewModel::updateOutputFormat,
dismissAction = { resetDialog() }, dismissAction = { resetDialog() },
supportText = stringResource(R.string.output_format_setting_info) supportText = stringResource(R.string.output_format_setting_info)
) )
} }
DialogState.START_SCREEN -> {
AlertDialogWithList(
title = stringResource(R.string.starting_screen_setting),
selectedItemIndex = userPrefs.value.startingScreen,
listItems = TOP_LEVEL_DESTINATIONS,
selectAction = viewModel::updateStartingScreen,
dismissAction = { resetDialog() }
)
}
// Dismissing alert dialog // Dismissing alert dialog
else -> {} else -> {}
} }
@ -242,5 +268,5 @@ internal fun SettingsScreen(
* All possible states for alert dialog that opens when user clicks on settings. * All possible states for alert dialog that opens when user clicks on settings.
*/ */
private enum class DialogState { private enum class DialogState {
NONE, PRECISION, SEPARATOR, OUTPUT_FORMAT, NONE, PRECISION, SEPARATOR, OUTPUT_FORMAT, START_SCREEN
} }

View File

@ -110,6 +110,15 @@ class SettingsViewModel @Inject constructor(
} }
} }
/**
* @see UserPreferencesRepository.updateStartingScreen
*/
fun updateStartingScreen(startingScreen: String) {
viewModelScope.launch {
userPrefsRepository.updateStartingScreen(startingScreen)
}
}
/** /**
* @see UnitGroupsRepository.markUnitGroupAsHidden * @see UnitGroupsRepository.markUnitGroupAsHidden
* @see UserPreferencesRepository.updateShownUnitGroups * @see UserPreferencesRepository.updateShownUnitGroups

View File

@ -44,18 +44,18 @@ import com.sadellie.unitto.feature.settings.R
* Alert dialog that has a list of options in it * Alert dialog that has a list of options in it
* *
* @param title Dialog title * @param title Dialog title
* @param listItems List of options * @param listItems List of options. Map, where key is an option and value is a string (option name)
* @param selectedItemIndex Currently selected item index * @param selectedItemIndex Currently selected item index
* @param selectAction Action to perform when clicking an option * @param selectAction Action to perform when clicking an option
* @param dismissAction Action to perform when clicking "cancel" * @param dismissAction Action to perform when clicking "cancel"
* @param supportText Text above list of options * @param supportText Text above list of options
*/ */
@Composable @Composable
internal fun AlertDialogWithList( internal fun <T> AlertDialogWithList(
title: String, title: String,
listItems: Map<Int, Int> = emptyMap(), listItems: Map<T, Int>,
selectedItemIndex: Int = 0, selectedItemIndex: T,
selectAction: (Int) -> Unit = {}, selectAction: (T) -> Unit,
dismissAction: () -> Unit, dismissAction: () -> Unit,
supportText: String? = null, supportText: String? = null,
dismissButtonLabel: String = stringResource(R.string.cancel_label) dismissButtonLabel: String = stringResource(R.string.cancel_label)