mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
Fix initial states, navigation, loading logic and transitions
closes #92
This commit is contained in:
parent
1279a8acad
commit
f3ba0bd06a
@ -44,7 +44,7 @@ internal class MainActivity : AppCompatActivity() {
|
||||
val prefs = userPrefsRepository.appPrefs
|
||||
.collectAsStateWithLifecycle(null).value
|
||||
|
||||
if (prefs != null) UnittoApp(prefs)
|
||||
UnittoApp(prefs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,23 +53,14 @@ import com.sadellie.unitto.core.ui.theme.TypographySystem
|
||||
import com.sadellie.unitto.core.ui.theme.TypographyUnitto
|
||||
import com.sadellie.unitto.data.userprefs.AppPreferences
|
||||
import io.github.sadellie.themmo.Themmo
|
||||
import io.github.sadellie.themmo.rememberThemmoController
|
||||
import io.github.sadellie.themmo.ThemmoController
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
internal fun UnittoApp(prefs: AppPreferences) {
|
||||
internal fun UnittoApp(prefs: AppPreferences?) {
|
||||
|
||||
val mContext = LocalContext.current
|
||||
val themmoController = rememberThemmoController(
|
||||
lightColorScheme = LightThemeColors,
|
||||
darkColorScheme = DarkThemeColors,
|
||||
themingMode = prefs.themingMode,
|
||||
dynamicThemeEnabled = prefs.enableDynamicTheme,
|
||||
amoledThemeEnabled = prefs.enableAmoledTheme,
|
||||
customColor = prefs.customColor,
|
||||
monetMode = prefs.monetMode
|
||||
)
|
||||
val navController = rememberNavController()
|
||||
val sysUiController = rememberSystemUiController()
|
||||
|
||||
@ -97,6 +88,19 @@ internal fun UnittoApp(prefs: AppPreferences) {
|
||||
}
|
||||
}
|
||||
|
||||
if (prefs != null) {
|
||||
val themmoController = remember(prefs) {
|
||||
ThemmoController(
|
||||
lightColorScheme = LightThemeColors,
|
||||
darkColorScheme = DarkThemeColors,
|
||||
themingMode = prefs.themingMode,
|
||||
dynamicThemeEnabled = prefs.enableDynamicTheme,
|
||||
amoledThemeEnabled = prefs.enableAmoledTheme,
|
||||
customColor = prefs.customColor,
|
||||
monetMode = prefs.monetMode
|
||||
)
|
||||
}
|
||||
|
||||
Themmo(
|
||||
themmoController = themmoController,
|
||||
typography = if (prefs.systemFont) TypographySystem else TypographyUnitto,
|
||||
@ -150,13 +154,14 @@ internal fun UnittoApp(prefs: AppPreferences) {
|
||||
}
|
||||
)
|
||||
|
||||
BackHandler(drawerState.isOpen) {
|
||||
drawerScope.launch { drawerState.close() }
|
||||
}
|
||||
|
||||
LaunchedEffect(useDarkIcons) {
|
||||
sysUiController.setNavigationBarColor(Color.Transparent, useDarkIcons)
|
||||
sysUiController.setStatusBarColor(Color.Transparent, useDarkIcons)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackHandler(drawerState.isOpen) {
|
||||
drawerScope.launch { drawerState.close() }
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,14 @@ import androidx.compose.animation.AnimatedContentScope
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.navigation.NamedNavArgument
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavDeepLink
|
||||
@ -40,16 +45,16 @@ fun NavGraphBuilder.unittoComposable(
|
||||
arguments: List<NamedNavArgument> = emptyList(),
|
||||
deepLinks: List<NavDeepLink> = emptyList(),
|
||||
enterTransition: (@JvmSuppressWildcards
|
||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? = { fadeIn() },
|
||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? = { unittoFadeIn() },
|
||||
exitTransition: (@JvmSuppressWildcards
|
||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? = { fadeOut() },
|
||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? = { unittoFadeOut() },
|
||||
popEnterTransition: (@JvmSuppressWildcards
|
||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? =
|
||||
enterTransition,
|
||||
popExitTransition: (@JvmSuppressWildcards
|
||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? =
|
||||
exitTransition,
|
||||
content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
|
||||
content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit,
|
||||
): Unit = composable(
|
||||
route = route,
|
||||
arguments = arguments,
|
||||
@ -61,6 +66,40 @@ fun NavGraphBuilder.unittoComposable(
|
||||
content = content,
|
||||
)
|
||||
|
||||
fun NavGraphBuilder.unittoStackedComposable(
|
||||
route: String,
|
||||
arguments: List<NamedNavArgument> = emptyList(),
|
||||
deepLinks: List<NavDeepLink> = emptyList(),
|
||||
content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit,
|
||||
) {
|
||||
composable(
|
||||
route = route,
|
||||
arguments = arguments,
|
||||
deepLinks = deepLinks,
|
||||
enterTransition = {
|
||||
slideInHorizontally(
|
||||
animationSpec = unittoEnterTween(),
|
||||
initialOffsetX = { (it * 0.2f).toInt() }) + unittoFadeIn()
|
||||
},
|
||||
exitTransition = {
|
||||
slideOutHorizontally(
|
||||
animationSpec = unittoExitTween(),
|
||||
targetOffsetX = { -(it * 0.2f).toInt() }) + unittoFadeOut()
|
||||
},
|
||||
popEnterTransition = {
|
||||
slideInHorizontally(
|
||||
animationSpec = unittoEnterTween(),
|
||||
initialOffsetX = { -(it * 0.2f).toInt() }) + unittoFadeIn()
|
||||
},
|
||||
popExitTransition = {
|
||||
slideOutHorizontally(
|
||||
animationSpec = unittoExitTween(),
|
||||
targetOffsetX = { (it * 0.2f).toInt() }) + unittoFadeOut()
|
||||
},
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see NavGraphBuilder.navigation
|
||||
*/
|
||||
@ -79,7 +118,7 @@ fun NavGraphBuilder.unittoNavigation(
|
||||
popExitTransition: (
|
||||
AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?
|
||||
)? = exitTransition,
|
||||
builder: NavGraphBuilder.() -> Unit
|
||||
builder: NavGraphBuilder.() -> Unit,
|
||||
): Unit = navigation(
|
||||
startDestination = startDestination,
|
||||
route = route,
|
||||
@ -91,3 +130,11 @@ fun NavGraphBuilder.unittoNavigation(
|
||||
popExitTransition = popExitTransition,
|
||||
builder = builder
|
||||
)
|
||||
|
||||
private const val ENTER_DURATION = 350
|
||||
private const val EXIT_DURATION = 200
|
||||
|
||||
private fun unittoFadeIn(): EnterTransition = fadeIn(tween(ENTER_DURATION))
|
||||
private fun unittoFadeOut(): ExitTransition = fadeOut(tween(EXIT_DURATION))
|
||||
private fun unittoEnterTween(): FiniteAnimationSpec<IntOffset> = tween(ENTER_DURATION)
|
||||
private fun unittoExitTween(): FiniteAnimationSpec<IntOffset> = tween(EXIT_DURATION)
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.ui.common
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun UnittoEmptyScreen() {
|
||||
Spacer(modifier = Modifier.fillMaxSize())
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.data.userprefs
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
import io.github.sadellie.themmo.MonetMode
|
||||
import io.github.sadellie.themmo.ThemingMode
|
||||
|
||||
data class AppPreferences(
|
||||
val themingMode: ThemingMode,
|
||||
val enableDynamicTheme: Boolean,
|
||||
val enableAmoledTheme: Boolean,
|
||||
val customColor: Color,
|
||||
val monetMode: MonetMode,
|
||||
val startingScreen: String,
|
||||
val enableToolsExperiment: Boolean,
|
||||
val systemFont: Boolean,
|
||||
)
|
||||
|
||||
data class GeneralPreferences(
|
||||
val enableVibrations: Boolean,
|
||||
)
|
||||
|
||||
data class CalculatorPreferences(
|
||||
val radianMode: Boolean,
|
||||
val enableVibrations: Boolean,
|
||||
val separator: Int,
|
||||
val middleZero: Boolean,
|
||||
val partialHistoryView: Boolean,
|
||||
val precision: Int,
|
||||
val outputFormat: Int,
|
||||
)
|
||||
|
||||
data class ConverterPreferences(
|
||||
val enableVibrations: Boolean,
|
||||
val separator: Int,
|
||||
val middleZero: Boolean,
|
||||
val precision: Int,
|
||||
val outputFormat: Int,
|
||||
val unitConverterFormatTime: Boolean,
|
||||
val unitConverterSorting: UnitsListSorting,
|
||||
val shownUnitGroups: List<UnitGroup>,
|
||||
val unitConverterFavoritesOnly: Boolean,
|
||||
val enableToolsExperiment: Boolean,
|
||||
val latestLeftSideUnit: String,
|
||||
val latestRightSideUnit: String,
|
||||
)
|
||||
|
||||
data class DisplayPreferences(
|
||||
val systemFont: Boolean,
|
||||
val middleZero: Boolean,
|
||||
)
|
||||
|
||||
data class FormattingPreferences(
|
||||
val digitsPrecision: Int,
|
||||
val separator: Int,
|
||||
val outputFormat: Int,
|
||||
)
|
||||
|
||||
data class UnitGroupsPreferences(
|
||||
val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS,
|
||||
)
|
||||
|
||||
data class AddSubtractPreferences(
|
||||
val separator: Int,
|
||||
val enableVibrations: Boolean,
|
||||
)
|
||||
|
||||
data class AboutPreferences(
|
||||
val enableToolsExperiment: Boolean,
|
||||
)
|
||||
|
||||
data class StartingScreenPreferences(
|
||||
val startingScreen: String,
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.data.userprefs
|
||||
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
|
||||
internal object PrefsKeys {
|
||||
val THEMING_MODE = stringPreferencesKey("THEMING_MODE_PREF_KEY")
|
||||
val ENABLE_DYNAMIC_THEME = booleanPreferencesKey("ENABLE_DYNAMIC_THEME_PREF_KEY")
|
||||
val ENABLE_AMOLED_THEME = booleanPreferencesKey("ENABLE_AMOLED_THEME_PREF_KEY")
|
||||
val CUSTOM_COLOR = longPreferencesKey("CUSTOM_COLOR_PREF_KEY")
|
||||
val MONET_MODE = stringPreferencesKey("MONET_MODE_PREF_KEY")
|
||||
val DIGITS_PRECISION = intPreferencesKey("DIGITS_PRECISION_PREF_KEY")
|
||||
val SEPARATOR = intPreferencesKey("SEPARATOR_PREF_KEY")
|
||||
val OUTPUT_FORMAT = intPreferencesKey("OUTPUT_FORMAT_PREF_KEY")
|
||||
val LATEST_LEFT_SIDE = stringPreferencesKey("LATEST_LEFT_SIDE_PREF_KEY")
|
||||
val LATEST_RIGHT_SIDE = stringPreferencesKey("LATEST_RIGHT_SIDE_PREF_KEY")
|
||||
val SHOWN_UNIT_GROUPS = stringPreferencesKey("SHOWN_UNIT_GROUPS_PREF_KEY")
|
||||
val ENABLE_VIBRATIONS = booleanPreferencesKey("ENABLE_VIBRATIONS_PREF_KEY")
|
||||
val ENABLE_TOOLS_EXPERIMENT = booleanPreferencesKey("ENABLE_TOOLS_EXPERIMENT_PREF_KEY")
|
||||
val STARTING_SCREEN = stringPreferencesKey("STARTING_SCREEN_PREF_KEY")
|
||||
val RADIAN_MODE = booleanPreferencesKey("RADIAN_MODE_PREF_KEY")
|
||||
val UNIT_CONVERTER_FAVORITES_ONLY =
|
||||
booleanPreferencesKey("UNIT_CONVERTER_FAVORITES_ONLY_PREF_KEY")
|
||||
val UNIT_CONVERTER_FORMAT_TIME = booleanPreferencesKey("UNIT_CONVERTER_FORMAT_TIME_PREF_KEY")
|
||||
val UNIT_CONVERTER_SORTING = stringPreferencesKey("UNIT_CONVERTER_SORTING_PREF_KEY")
|
||||
val MIDDLE_ZERO = booleanPreferencesKey("MIDDLE_ZERO_PREF_KEY")
|
||||
val SYSTEM_FONT = booleanPreferencesKey("SYSTEM_FONT_PREF_KEY")
|
||||
val PARTIAL_HISTORY_VIEW = booleanPreferencesKey("PARTIAL_HISTORY_VIEW_PREF_KEY")
|
||||
}
|
@ -21,12 +21,8 @@ package com.sadellie.unitto.data.userprefs
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import com.sadellie.unitto.core.base.OutputFormat
|
||||
import com.sadellie.unitto.core.base.Separator
|
||||
import com.sadellie.unitto.core.base.TopLevelDestinations
|
||||
@ -43,214 +39,107 @@ import kotlinx.coroutines.flow.map
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
private object PrefsKeys {
|
||||
val THEMING_MODE = stringPreferencesKey("THEMING_MODE_PREF_KEY")
|
||||
val ENABLE_DYNAMIC_THEME = booleanPreferencesKey("ENABLE_DYNAMIC_THEME_PREF_KEY")
|
||||
val ENABLE_AMOLED_THEME = booleanPreferencesKey("ENABLE_AMOLED_THEME_PREF_KEY")
|
||||
val CUSTOM_COLOR = longPreferencesKey("CUSTOM_COLOR_PREF_KEY")
|
||||
val MONET_MODE = stringPreferencesKey("MONET_MODE_PREF_KEY")
|
||||
val DIGITS_PRECISION = intPreferencesKey("DIGITS_PRECISION_PREF_KEY")
|
||||
val SEPARATOR = intPreferencesKey("SEPARATOR_PREF_KEY")
|
||||
val OUTPUT_FORMAT = intPreferencesKey("OUTPUT_FORMAT_PREF_KEY")
|
||||
val LATEST_LEFT_SIDE = stringPreferencesKey("LATEST_LEFT_SIDE_PREF_KEY")
|
||||
val LATEST_RIGHT_SIDE = stringPreferencesKey("LATEST_RIGHT_SIDE_PREF_KEY")
|
||||
val SHOWN_UNIT_GROUPS = stringPreferencesKey("SHOWN_UNIT_GROUPS_PREF_KEY")
|
||||
val ENABLE_VIBRATIONS = booleanPreferencesKey("ENABLE_VIBRATIONS_PREF_KEY")
|
||||
val ENABLE_TOOLS_EXPERIMENT = booleanPreferencesKey("ENABLE_TOOLS_EXPERIMENT_PREF_KEY")
|
||||
val STARTING_SCREEN = stringPreferencesKey("STARTING_SCREEN_PREF_KEY")
|
||||
val RADIAN_MODE = booleanPreferencesKey("RADIAN_MODE_PREF_KEY")
|
||||
val UNIT_CONVERTER_FAVORITES_ONLY =
|
||||
booleanPreferencesKey("UNIT_CONVERTER_FAVORITES_ONLY_PREF_KEY")
|
||||
val UNIT_CONVERTER_FORMAT_TIME = booleanPreferencesKey("UNIT_CONVERTER_FORMAT_TIME_PREF_KEY")
|
||||
val UNIT_CONVERTER_SORTING = stringPreferencesKey("UNIT_CONVERTER_SORTING_PREF_KEY")
|
||||
val MIDDLE_ZERO = booleanPreferencesKey("MIDDLE_ZERO_PREF_KEY")
|
||||
val SYSTEM_FONT = booleanPreferencesKey("SYSTEM_FONT_PREF_KEY")
|
||||
val PARTIAL_HISTORY_VIEW = booleanPreferencesKey("PARTIAL_HISTORY_VIEW_PREF_KEY")
|
||||
}
|
||||
|
||||
data class AppPreferences(
|
||||
val themingMode: ThemingMode = ThemingMode.AUTO,
|
||||
val enableDynamicTheme: Boolean = true,
|
||||
val enableAmoledTheme: Boolean = false,
|
||||
val customColor: Color = Color.Unspecified,
|
||||
val monetMode: MonetMode = MonetMode.TonalSpot,
|
||||
val startingScreen: String = TopLevelDestinations.Calculator.graph,
|
||||
val enableToolsExperiment: Boolean = false,
|
||||
val systemFont: Boolean = false,
|
||||
)
|
||||
|
||||
data class GeneralPreferences(
|
||||
val enableVibrations: Boolean = true,
|
||||
)
|
||||
|
||||
data class CalculatorPreferences(
|
||||
val radianMode: Boolean = true,
|
||||
val enableVibrations: Boolean = true,
|
||||
val separator: Int = Separator.SPACE,
|
||||
val middleZero: Boolean = false,
|
||||
val partialHistoryView: Boolean = true,
|
||||
val precision: Int = 3,
|
||||
val outputFormat: Int = OutputFormat.PLAIN,
|
||||
)
|
||||
|
||||
data class ConverterPreferences(
|
||||
val enableVibrations: Boolean = true,
|
||||
val separator: Int = Separator.SPACE,
|
||||
val middleZero: Boolean = false,
|
||||
val precision: Int = 3,
|
||||
val outputFormat: Int = OutputFormat.PLAIN,
|
||||
val unitConverterFormatTime: Boolean = false,
|
||||
val unitConverterSorting: UnitsListSorting = UnitsListSorting.USAGE,
|
||||
val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS,
|
||||
val unitConverterFavoritesOnly: Boolean = false,
|
||||
val enableToolsExperiment: Boolean = false,
|
||||
val latestLeftSideUnit: String = MyUnitIDS.kilometer,
|
||||
val latestRightSideUnit: String = MyUnitIDS.mile,
|
||||
)
|
||||
|
||||
data class DisplayPreferences(
|
||||
val systemFont: Boolean = false,
|
||||
val middleZero: Boolean = false,
|
||||
)
|
||||
|
||||
data class FormattingPreferences(
|
||||
val digitsPrecision: Int = 3,
|
||||
val separator: Int = Separator.SPACE,
|
||||
val outputFormat: Int = OutputFormat.PLAIN,
|
||||
)
|
||||
|
||||
data class UnitGroupsPreferences(
|
||||
val shownUnitGroups: List<UnitGroup> = ALL_UNIT_GROUPS,
|
||||
)
|
||||
|
||||
data class AddSubtractPreferences(
|
||||
val separator: Int = Separator.SPACE,
|
||||
val enableVibrations: Boolean = true,
|
||||
)
|
||||
|
||||
data class AboutPreferences(
|
||||
val enableToolsExperiment: Boolean = false,
|
||||
)
|
||||
|
||||
data class StartingScreenPreferences(
|
||||
val startingScreen: String = TopLevelDestinations.Calculator.graph,
|
||||
)
|
||||
|
||||
class UserPreferencesRepository @Inject constructor(private val dataStore: DataStore<Preferences>) {
|
||||
class UserPreferencesRepository @Inject constructor(
|
||||
private val dataStore: DataStore<Preferences>,
|
||||
) {
|
||||
private val data = dataStore.data
|
||||
.catch { if (it is IOException) emit(emptyPreferences()) else throw it }
|
||||
|
||||
val appPrefs: Flow<AppPreferences> = data
|
||||
.map { preferences ->
|
||||
AppPreferences(
|
||||
themingMode = preferences[PrefsKeys.THEMING_MODE]?.letTryOrNull {
|
||||
ThemingMode.valueOf(it)
|
||||
}
|
||||
?: ThemingMode.AUTO,
|
||||
enableDynamicTheme = preferences[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: true,
|
||||
enableAmoledTheme = preferences[PrefsKeys.ENABLE_AMOLED_THEME] ?: false,
|
||||
customColor = preferences[PrefsKeys.CUSTOM_COLOR]?.letTryOrNull { Color(it.toULong()) }
|
||||
?: Color.Unspecified,
|
||||
monetMode = preferences[PrefsKeys.MONET_MODE]?.letTryOrNull { MonetMode.valueOf(it) }
|
||||
?: MonetMode.TonalSpot,
|
||||
startingScreen = preferences[PrefsKeys.STARTING_SCREEN]
|
||||
?: TopLevelDestinations.Calculator.graph,
|
||||
enableToolsExperiment = preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false,
|
||||
systemFont = preferences[PrefsKeys.SYSTEM_FONT] ?: false
|
||||
themingMode = preferences.getThemingMode(),
|
||||
enableDynamicTheme = preferences.getEnableDynamicTheme(),
|
||||
enableAmoledTheme = preferences.getEnableAmoledTheme(),
|
||||
customColor = preferences.getCustomColor(),
|
||||
monetMode = preferences.getMonetMode(),
|
||||
startingScreen = preferences.getStartingScreen(),
|
||||
enableToolsExperiment = preferences.getEnableToolsExperiment(),
|
||||
systemFont = preferences.getSystemFont()
|
||||
)
|
||||
}
|
||||
|
||||
val generalPrefs: Flow<GeneralPreferences> = data
|
||||
.map { preferences ->
|
||||
GeneralPreferences(
|
||||
enableVibrations = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true,
|
||||
enableVibrations = preferences.getEnableVibrations(),
|
||||
)
|
||||
}
|
||||
|
||||
val calculatorPrefs: Flow<CalculatorPreferences> = data
|
||||
.map { preferences ->
|
||||
CalculatorPreferences(
|
||||
radianMode = preferences[PrefsKeys.RADIAN_MODE] ?: true,
|
||||
enableVibrations = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true,
|
||||
separator = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACE,
|
||||
middleZero = preferences[PrefsKeys.MIDDLE_ZERO] ?: false,
|
||||
partialHistoryView = preferences[PrefsKeys.PARTIAL_HISTORY_VIEW] ?: true,
|
||||
precision = preferences[PrefsKeys.DIGITS_PRECISION] ?: 3,
|
||||
outputFormat = preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN
|
||||
radianMode = preferences.getRadianMode(),
|
||||
enableVibrations = preferences.getEnableVibrations(),
|
||||
separator = preferences.getSeparator(),
|
||||
middleZero = preferences.getMiddleZero(),
|
||||
partialHistoryView = preferences.getPartialHistoryView(),
|
||||
precision = preferences.getDigitsPrecision(),
|
||||
outputFormat = preferences.getOutputFormat()
|
||||
)
|
||||
}
|
||||
|
||||
val converterPrefs: Flow<ConverterPreferences> = data
|
||||
.map { preferences ->
|
||||
ConverterPreferences(
|
||||
enableVibrations = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true,
|
||||
separator = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACE,
|
||||
middleZero = preferences[PrefsKeys.MIDDLE_ZERO] ?: false,
|
||||
precision = preferences[PrefsKeys.DIGITS_PRECISION] ?: 3,
|
||||
outputFormat = preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN,
|
||||
unitConverterFormatTime = preferences[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME]
|
||||
?: false,
|
||||
unitConverterSorting = preferences[PrefsKeys.UNIT_CONVERTER_SORTING]
|
||||
?.let { UnitsListSorting.valueOf(it) } ?: UnitsListSorting.USAGE,
|
||||
shownUnitGroups = preferences[PrefsKeys.SHOWN_UNIT_GROUPS]?.letTryOrNull { list ->
|
||||
list.ifEmpty { return@letTryOrNull listOf() }.split(",")
|
||||
.map { UnitGroup.valueOf(it) }
|
||||
} ?: ALL_UNIT_GROUPS,
|
||||
unitConverterFavoritesOnly = preferences[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY]
|
||||
?: false,
|
||||
enableToolsExperiment = preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false,
|
||||
latestLeftSideUnit = preferences[PrefsKeys.LATEST_LEFT_SIDE] ?: MyUnitIDS.kilometer,
|
||||
latestRightSideUnit = preferences[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile,
|
||||
enableVibrations = preferences.getEnableVibrations(),
|
||||
separator = preferences.getSeparator(),
|
||||
middleZero = preferences.getMiddleZero(),
|
||||
precision = preferences.getDigitsPrecision(),
|
||||
outputFormat = preferences.getOutputFormat(),
|
||||
unitConverterFormatTime = preferences.getUnitConverterFormatTime(),
|
||||
unitConverterSorting = preferences.getUnitConverterSorting(),
|
||||
shownUnitGroups = preferences.getShownUnitGroups(),
|
||||
unitConverterFavoritesOnly = preferences.getUnitConverterFavoritesOnly(),
|
||||
enableToolsExperiment = preferences.getEnableToolsExperiment(),
|
||||
latestLeftSideUnit = preferences.getLatestLeftSide(),
|
||||
latestRightSideUnit = preferences.getLatestRightSide(),
|
||||
)
|
||||
}
|
||||
|
||||
val displayPrefs: Flow<DisplayPreferences> = data
|
||||
.map { preferences ->
|
||||
DisplayPreferences(
|
||||
systemFont = preferences[PrefsKeys.SYSTEM_FONT] ?: false,
|
||||
middleZero = preferences[PrefsKeys.MIDDLE_ZERO] ?: false,
|
||||
systemFont = preferences.getSystemFont(),
|
||||
middleZero = preferences.getMiddleZero(),
|
||||
)
|
||||
}
|
||||
|
||||
val formattingPrefs: Flow<FormattingPreferences> = data
|
||||
.map { preferences ->
|
||||
FormattingPreferences(
|
||||
digitsPrecision = preferences[PrefsKeys.DIGITS_PRECISION] ?: 3,
|
||||
separator = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACE,
|
||||
outputFormat = preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN,
|
||||
digitsPrecision = preferences.getDigitsPrecision(),
|
||||
separator = preferences.getSeparator(),
|
||||
outputFormat = preferences.getOutputFormat(),
|
||||
)
|
||||
}
|
||||
|
||||
val unitGroupsPrefs: Flow<UnitGroupsPreferences> = data
|
||||
.map { preferences ->
|
||||
UnitGroupsPreferences(
|
||||
shownUnitGroups = preferences[PrefsKeys.SHOWN_UNIT_GROUPS]?.letTryOrNull { list ->
|
||||
list.ifEmpty { return@letTryOrNull listOf() }.split(",")
|
||||
.map { UnitGroup.valueOf(it) }
|
||||
} ?: ALL_UNIT_GROUPS,
|
||||
shownUnitGroups = preferences.getShownUnitGroups(),
|
||||
)
|
||||
}
|
||||
|
||||
val addSubtractPrefs: Flow<AddSubtractPreferences> = data
|
||||
.map { preferences ->
|
||||
AddSubtractPreferences(
|
||||
separator = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACE,
|
||||
enableVibrations = preferences[PrefsKeys.ENABLE_VIBRATIONS] ?: true,
|
||||
separator = preferences.getSeparator(),
|
||||
enableVibrations = preferences.getEnableVibrations(),
|
||||
)
|
||||
}
|
||||
|
||||
val aboutPrefs: Flow<AboutPreferences> = data
|
||||
.map { preferences ->
|
||||
AboutPreferences(
|
||||
enableToolsExperiment = preferences[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false
|
||||
enableToolsExperiment = preferences.getEnableToolsExperiment()
|
||||
)
|
||||
}
|
||||
|
||||
val startingScreenPrefs: Flow<StartingScreenPreferences> = data
|
||||
.map { preferences ->
|
||||
StartingScreenPreferences(
|
||||
startingScreen = preferences[PrefsKeys.STARTING_SCREEN]
|
||||
?: TopLevelDestinations.Calculator.graph,
|
||||
startingScreen = preferences.getStartingScreen(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -374,10 +263,104 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
preferences[PrefsKeys.PARTIAL_HISTORY_VIEW] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T, R> T.letTryOrNull(block: (T) -> R): R? = try {
|
||||
this?.let(block)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun Preferences.getEnableDynamicTheme(): Boolean {
|
||||
return this[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: true
|
||||
}
|
||||
|
||||
private fun Preferences.getThemingMode(): ThemingMode {
|
||||
return this[PrefsKeys.THEMING_MODE]
|
||||
?.letTryOrNull { ThemingMode.valueOf(it) }
|
||||
?: ThemingMode.AUTO
|
||||
}
|
||||
|
||||
private fun Preferences.getEnableAmoledTheme(): Boolean {
|
||||
return this[PrefsKeys.ENABLE_AMOLED_THEME] ?: false
|
||||
}
|
||||
|
||||
private fun Preferences.getCustomColor(): Color {
|
||||
return this[PrefsKeys.CUSTOM_COLOR]?.letTryOrNull { Color(it.toULong()) }
|
||||
?: Color.Unspecified
|
||||
}
|
||||
|
||||
private fun Preferences.getMonetMode(): MonetMode {
|
||||
return this[PrefsKeys.MONET_MODE]?.letTryOrNull { MonetMode.valueOf(it) }
|
||||
?: MonetMode.TonalSpot
|
||||
}
|
||||
|
||||
private fun Preferences.getStartingScreen(): String {
|
||||
return this[PrefsKeys.STARTING_SCREEN]
|
||||
?: TopLevelDestinations.Calculator.graph
|
||||
}
|
||||
|
||||
private fun Preferences.getEnableToolsExperiment(): Boolean {
|
||||
return this[PrefsKeys.ENABLE_TOOLS_EXPERIMENT] ?: false
|
||||
}
|
||||
|
||||
private fun Preferences.getSystemFont(): Boolean {
|
||||
return this[PrefsKeys.SYSTEM_FONT] ?: false
|
||||
}
|
||||
|
||||
private fun Preferences.getEnableVibrations(): Boolean {
|
||||
return this[PrefsKeys.ENABLE_VIBRATIONS] ?: true
|
||||
}
|
||||
|
||||
private fun Preferences.getRadianMode(): Boolean {
|
||||
return this[PrefsKeys.RADIAN_MODE] ?: true
|
||||
}
|
||||
|
||||
private fun Preferences.getSeparator(): Int {
|
||||
return this[PrefsKeys.SEPARATOR] ?: Separator.SPACE
|
||||
}
|
||||
|
||||
private fun Preferences.getMiddleZero(): Boolean {
|
||||
return this[PrefsKeys.MIDDLE_ZERO] ?: false
|
||||
}
|
||||
|
||||
private fun Preferences.getPartialHistoryView(): Boolean {
|
||||
return this[PrefsKeys.PARTIAL_HISTORY_VIEW] ?: true
|
||||
}
|
||||
|
||||
private fun Preferences.getDigitsPrecision(): Int {
|
||||
return this[PrefsKeys.DIGITS_PRECISION] ?: 3
|
||||
}
|
||||
|
||||
private fun Preferences.getOutputFormat(): Int {
|
||||
return this[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN
|
||||
}
|
||||
|
||||
private fun Preferences.getUnitConverterFormatTime(): Boolean {
|
||||
return this[PrefsKeys.UNIT_CONVERTER_FORMAT_TIME] ?: false
|
||||
}
|
||||
|
||||
private fun Preferences.getUnitConverterSorting(): UnitsListSorting {
|
||||
return this[PrefsKeys.UNIT_CONVERTER_SORTING]
|
||||
?.let { UnitsListSorting.valueOf(it) } ?: UnitsListSorting.USAGE
|
||||
}
|
||||
|
||||
private fun Preferences.getShownUnitGroups(): List<UnitGroup> {
|
||||
return this[PrefsKeys.SHOWN_UNIT_GROUPS]?.letTryOrNull { list ->
|
||||
list.ifEmpty { return@letTryOrNull listOf() }.split(",")
|
||||
.map { UnitGroup.valueOf(it) }
|
||||
} ?: ALL_UNIT_GROUPS
|
||||
}
|
||||
|
||||
private fun Preferences.getUnitConverterFavoritesOnly(): Boolean {
|
||||
return this[PrefsKeys.UNIT_CONVERTER_FAVORITES_ONLY]
|
||||
?: false
|
||||
}
|
||||
|
||||
private fun Preferences.getLatestLeftSide(): String {
|
||||
return this[PrefsKeys.LATEST_LEFT_SIDE] ?: MyUnitIDS.kilometer
|
||||
}
|
||||
|
||||
private fun Preferences.getLatestRightSide(): String {
|
||||
return this[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile
|
||||
}
|
||||
|
||||
private inline fun <T, R> T.letTryOrNull(block: (T) -> R): R? = try {
|
||||
this?.let(block)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
@ -18,24 +18,17 @@
|
||||
|
||||
package com.sadellie.unitto.feature.calculator
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.AnchoredDraggableState
|
||||
import androidx.compose.foundation.gestures.DraggableAnchors
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.anchoredDraggable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material3.AlertDialog
|
||||
@ -53,9 +46,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -70,11 +61,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.MenuButton
|
||||
import com.sadellie.unitto.core.ui.common.SettingsButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithTopBar
|
||||
import com.sadellie.unitto.core.ui.common.textfield.UnformattedTextField
|
||||
import com.sadellie.unitto.data.model.HistoryItem
|
||||
import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard
|
||||
import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboardLoading
|
||||
import com.sadellie.unitto.feature.calculator.components.HistoryItemHeight
|
||||
import com.sadellie.unitto.feature.calculator.components.HistoryList
|
||||
import com.sadellie.unitto.feature.calculator.components.TextBox
|
||||
@ -117,10 +107,7 @@ internal fun CalculatorScreen(
|
||||
clearHistory: () -> Unit
|
||||
) {
|
||||
when (uiState) {
|
||||
is CalculatorUIState.Loading -> Loading(
|
||||
navigateToMenu = navigateToMenu,
|
||||
navigateToSettings = navigateToSettings,
|
||||
)
|
||||
is CalculatorUIState.Loading -> UnittoEmptyScreen()
|
||||
is CalculatorUIState.Ready -> Ready(
|
||||
uiState = uiState,
|
||||
navigateToMenu = navigateToMenu,
|
||||
@ -314,81 +301,6 @@ private fun Ready(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun Loading(
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
) {
|
||||
UnittoScreenWithTopBar(
|
||||
title = { Text(stringResource(R.string.calculator_title)) },
|
||||
navigationIcon = { MenuButton { navigateToMenu() } },
|
||||
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceVariant),
|
||||
actions = { SettingsButton(navigateToSettings) }
|
||||
) { paddingValues ->
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
) {
|
||||
// Input
|
||||
Column(
|
||||
Modifier
|
||||
.height(maxHeight * 0.25f)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceVariant,
|
||||
RoundedCornerShape(
|
||||
topStartPercent = 0, topEndPercent = 0,
|
||||
bottomStartPercent = 20, bottomEndPercent = 20
|
||||
)
|
||||
)
|
||||
.padding(top = 12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
UnformattedTextField(
|
||||
modifier = Modifier
|
||||
.weight(2f)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp),
|
||||
value = TextFieldValue(),
|
||||
minRatio = 0.5f,
|
||||
onCursorChange = {},
|
||||
)
|
||||
if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
UnformattedTextField(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp),
|
||||
value = TextFieldValue(),
|
||||
minRatio = 1f,
|
||||
onCursorChange = {},
|
||||
readOnly = true,
|
||||
)
|
||||
}
|
||||
// Handle
|
||||
Box(
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
RoundedCornerShape(100)
|
||||
)
|
||||
.sizeIn(24.dp, 4.dp)
|
||||
)
|
||||
}
|
||||
|
||||
// Keyboard
|
||||
CalculatorKeyboardLoading(
|
||||
modifier = Modifier
|
||||
.semantics { testTag = "loading" }
|
||||
.offset(y = maxHeight * 0.25f)
|
||||
.height(maxHeight * 0.75f)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 432, heightDp = 1008, device = "spec:parent=pixel_5,orientation=portrait")
|
||||
@Preview(widthDp = 432, heightDp = 864, device = "spec:parent=pixel_5,orientation=portrait")
|
||||
@Preview(widthDp = 597, heightDp = 1393, device = "spec:parent=pixel_5,orientation=portrait")
|
||||
|
@ -22,6 +22,8 @@ import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.core.base.OutputFormat
|
||||
import com.sadellie.unitto.core.base.Separator
|
||||
import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
|
||||
import com.sadellie.unitto.core.ui.common.textfield.addTokens
|
||||
@ -58,7 +60,15 @@ internal class CalculatorViewModel @Inject constructor(
|
||||
userPrefsRepository.calculatorPrefs.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5000L),
|
||||
CalculatorPreferences()
|
||||
CalculatorPreferences(
|
||||
radianMode = false,
|
||||
enableVibrations = false,
|
||||
separator = Separator.SPACE,
|
||||
middleZero = false,
|
||||
partialHistoryView = true,
|
||||
precision = 3,
|
||||
outputFormat = OutputFormat.PLAIN
|
||||
)
|
||||
)
|
||||
|
||||
private val _input: MutableStateFlow<TextFieldValue> = MutableStateFlow(TextFieldValue())
|
||||
@ -79,7 +89,8 @@ internal class CalculatorViewModel @Inject constructor(
|
||||
middleZero = userPrefs.middleZero,
|
||||
partialHistoryView = userPrefs.partialHistoryView,
|
||||
)
|
||||
}.stateIn(
|
||||
}
|
||||
.stateIn(
|
||||
viewModelScope, SharingStarted.WhileSubscribed(5000L), CalculatorUIState.Loading
|
||||
)
|
||||
|
||||
|
@ -24,7 +24,6 @@ import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@ -35,7 +34,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ExpandMore
|
||||
import androidx.compose.material3.Icon
|
||||
@ -50,11 +48,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sadellie.unitto.core.base.Token
|
||||
import com.sadellie.unitto.core.ui.common.ColumnWithConstraints
|
||||
import com.sadellie.unitto.core.ui.common.KeyboardButtonAdditional
|
||||
@ -145,118 +141,6 @@ internal fun CalculatorKeyboard(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun CalculatorKeyboardLoading(
|
||||
modifier: Modifier
|
||||
) {
|
||||
if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
PortraitKeyboardLoading(modifier)
|
||||
} else {
|
||||
LandscapeKeyboardLoading(modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PortraitKeyboardLoading(
|
||||
modifier: Modifier
|
||||
) {
|
||||
ColumnWithConstraints(
|
||||
modifier = modifier
|
||||
) { constraints ->
|
||||
|
||||
val additionalButtonHeight by remember {
|
||||
mutableStateOf(constraints.maxHeight * 0.09f)
|
||||
}
|
||||
|
||||
val spacerHeight by remember {
|
||||
mutableStateOf(constraints.maxHeight * 0.025f)
|
||||
}
|
||||
|
||||
val additionalRowSpacedBy by remember {
|
||||
mutableStateOf(constraints.maxWidth * 0.03f)
|
||||
}
|
||||
|
||||
val weightModifier = Modifier.weight(1f)
|
||||
val additionalButtonModifier = Modifier
|
||||
.weight(1f)
|
||||
.height(additionalButtonHeight)
|
||||
|
||||
Spacer(modifier = Modifier.height(spacerHeight))
|
||||
|
||||
Row(
|
||||
modifier = Modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(additionalRowSpacedBy)
|
||||
) {
|
||||
// Additional buttons
|
||||
Box(weightModifier) {
|
||||
AdditionalButtonsPortrait(
|
||||
modifier = additionalButtonModifier,
|
||||
allowVibration = false,
|
||||
addSymbol = {},
|
||||
showAdditional = false,
|
||||
radianMode = false,
|
||||
toggleAngleMode = {},
|
||||
toggleInvMode = {}
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.size(additionalButtonHeight),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
// Expand/Collapse
|
||||
IconButton(
|
||||
onClick = { },
|
||||
colors = IconButtonDefaults.iconButtonColors(containerColor = MaterialTheme.colorScheme.inverseOnSurface)
|
||||
) {
|
||||
Icon(Icons.Default.ExpandMore, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(spacerHeight))
|
||||
|
||||
Box(
|
||||
modifier = weightModifier
|
||||
.clip(RoundedCornerShape(32.dp))
|
||||
.background(MaterialTheme.colorScheme.inverseOnSurface)
|
||||
.fillMaxSize()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(spacerHeight))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LandscapeKeyboardLoading(
|
||||
modifier: Modifier
|
||||
) {
|
||||
RowWithConstraints(modifier) { constraints ->
|
||||
val buttonModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.padding(constraints.maxWidth * 0.005f, constraints.maxHeight * 0.02f)
|
||||
|
||||
AdditionalButtonsLandscape(
|
||||
modifier = Modifier.weight(1f),
|
||||
buttonModifier = buttonModifier,
|
||||
allowVibration = false,
|
||||
radianMode = false,
|
||||
addSymbol = {},
|
||||
toggleAngleMode = {},
|
||||
toggleInvMode = {}
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(32.dp))
|
||||
.background(MaterialTheme.colorScheme.inverseOnSurface)
|
||||
.weight(5f)
|
||||
.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PortraitKeyboard(
|
||||
modifier: Modifier,
|
||||
|
@ -31,7 +31,7 @@ import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -64,7 +64,6 @@ import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.OutputFormat
|
||||
@ -74,6 +73,7 @@ import com.sadellie.unitto.core.ui.common.ColumnWithConstraints
|
||||
import com.sadellie.unitto.core.ui.common.MenuButton
|
||||
import com.sadellie.unitto.core.ui.common.PortraitLandscape
|
||||
import com.sadellie.unitto.core.ui.common.SettingsButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithTopBar
|
||||
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTextField
|
||||
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
|
||||
@ -125,23 +125,16 @@ private fun ConverterScreen(
|
||||
onCursorChange: (TextRange) -> Unit,
|
||||
onErrorClick: (AbstractUnit) -> Unit,
|
||||
) {
|
||||
UnittoScreenWithTopBar(
|
||||
title = { Text(stringResource(R.string.unit_converter_title)) },
|
||||
navigationIcon = { MenuButton { navigateToMenu() } },
|
||||
actions = {
|
||||
SettingsButton(navigateToSettings)
|
||||
},
|
||||
colors = TopAppBarDefaults
|
||||
.centerAlignedTopAppBarColors(containerColor = Color.Transparent),
|
||||
content = { padding ->
|
||||
when (uiState) {
|
||||
is UnitConverterUIState.Loading -> {
|
||||
ConverterLoading(modifier = Modifier.padding(padding))
|
||||
}
|
||||
UnitConverterUIState.Loading -> UnittoEmptyScreen()
|
||||
|
||||
is UnitConverterUIState.NumberBase -> {
|
||||
UnitConverterTopBar(
|
||||
navigateToMenu = navigateToMenu,
|
||||
navigateToSettings = navigateToSettings
|
||||
) {
|
||||
NumberBase(
|
||||
modifier = Modifier.padding(padding),
|
||||
modifier = Modifier.padding(it),
|
||||
uiState = uiState,
|
||||
onCursorChange = onCursorChange,
|
||||
processInput = processInput,
|
||||
@ -152,10 +145,15 @@ private fun ConverterScreen(
|
||||
clearInput = clearInput
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is UnitConverterUIState.Default -> {
|
||||
UnitConverterTopBar(
|
||||
navigateToMenu = navigateToMenu,
|
||||
navigateToSettings = navigateToSettings
|
||||
) {
|
||||
Default(
|
||||
modifier = Modifier.padding(padding),
|
||||
modifier = Modifier.padding(it),
|
||||
uiState = uiState,
|
||||
onCursorChange = onCursorChange,
|
||||
processInput = processInput,
|
||||
@ -169,45 +167,22 @@ private fun ConverterScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConverterLoading(modifier: Modifier) {
|
||||
PortraitLandscape(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
content1 = { contentModifier ->
|
||||
ColumnWithConstraints(modifier = contentModifier) {
|
||||
val textFieldModifier = Modifier.weight(2f)
|
||||
|
||||
UnformattedTextField(
|
||||
modifier = textFieldModifier,
|
||||
value = TextFieldValue(stringResource(R.string.loading_label)),
|
||||
onCursorChange = {},
|
||||
minRatio = 0.7f,
|
||||
readOnly = true
|
||||
)
|
||||
AnimatedUnitShortName()
|
||||
|
||||
ConverterResultTextField(
|
||||
modifier = textFieldModifier,
|
||||
result = ConverterResult.Loading
|
||||
)
|
||||
AnimatedUnitShortName()
|
||||
|
||||
Spacer(modifier = Modifier.height(it.maxHeight * 0.03f))
|
||||
|
||||
UnitSelectionButtons()
|
||||
}
|
||||
private fun UnitConverterTopBar(
|
||||
navigateToMenu: () -> Unit,
|
||||
navigateToSettings: () -> Unit,
|
||||
content: @Composable (PaddingValues) -> Unit
|
||||
) {
|
||||
UnittoScreenWithTopBar(
|
||||
title = { Text(stringResource(R.string.unit_converter_title)) },
|
||||
navigationIcon = { MenuButton { navigateToMenu() } },
|
||||
actions = {
|
||||
SettingsButton(navigateToSettings)
|
||||
},
|
||||
content2 = {
|
||||
Box(
|
||||
modifier = it
|
||||
.clip(RoundedCornerShape(32.dp))
|
||||
.background(MaterialTheme.colorScheme.inverseOnSurface)
|
||||
.fillMaxSize()
|
||||
)
|
||||
}
|
||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(containerColor = Color.Transparent),
|
||||
content = { content(it) }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.LinearOutSlowInEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -48,6 +47,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoSearchBar
|
||||
import com.sadellie.unitto.data.model.UnitGroup
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
@ -71,9 +71,7 @@ internal fun LeftSideRoute(
|
||||
when (
|
||||
val uiState = viewModel.leftSideUIState.collectAsStateWithLifecycle().value
|
||||
) {
|
||||
is LeftSideUIState.Loading -> {
|
||||
Box(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
is LeftSideUIState.Loading -> UnittoEmptyScreen()
|
||||
is LeftSideUIState.Ready -> LeftSideScreen(
|
||||
uiState = uiState,
|
||||
onQueryChange = viewModel::queryChangeLeft,
|
||||
|
@ -19,7 +19,6 @@
|
||||
package com.sadellie.unitto.feature.converter
|
||||
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@ -36,6 +35,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.OutputFormat
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoSearchBar
|
||||
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
|
||||
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
|
||||
@ -62,7 +62,7 @@ internal fun RightSideRoute(
|
||||
when (
|
||||
val uiState = viewModel.rightSideUIState.collectAsStateWithLifecycle().value
|
||||
) {
|
||||
is RightSideUIState.Loading -> Box(Modifier.fillMaxSize())
|
||||
is RightSideUIState.Loading -> UnittoEmptyScreen()
|
||||
is RightSideUIState.Ready ->
|
||||
RightSideScreen(
|
||||
uiState = uiState,
|
||||
|
@ -54,6 +54,7 @@ import com.sadellie.unitto.core.base.BuildConfig
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.Header
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.core.ui.openLink
|
||||
@ -72,17 +73,22 @@ internal fun SettingsRoute(
|
||||
navigateUp: () -> Unit,
|
||||
navControllerAction: (String) -> Unit,
|
||||
) {
|
||||
val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle()
|
||||
val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle().value
|
||||
val cachePercentage = viewModel.cachePercentage.collectAsStateWithLifecycle()
|
||||
|
||||
when (userPrefs) {
|
||||
null -> UnittoEmptyScreen()
|
||||
else -> {
|
||||
SettingsScreen(
|
||||
userPrefs = userPrefs.value,
|
||||
userPrefs = userPrefs,
|
||||
navigateUp = navigateUp,
|
||||
navControllerAction = navControllerAction,
|
||||
updateVibrations = viewModel::updateVibrations,
|
||||
cachePercentage = cachePercentage.value,
|
||||
clearCache = viewModel::clearCache,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -197,7 +203,9 @@ private fun PreviewSettingsScreen() {
|
||||
var cacheSize by remember { mutableFloatStateOf(0.9f) }
|
||||
|
||||
SettingsScreen(
|
||||
userPrefs = GeneralPreferences(),
|
||||
userPrefs = GeneralPreferences(
|
||||
enableVibrations = true
|
||||
),
|
||||
navigateUp = {},
|
||||
navControllerAction = {},
|
||||
updateVibrations = {},
|
||||
|
@ -22,7 +22,6 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.common.stateIn
|
||||
import com.sadellie.unitto.data.database.CurrencyRatesDao
|
||||
import com.sadellie.unitto.data.userprefs.GeneralPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -36,7 +35,7 @@ internal class SettingsViewModel @Inject constructor(
|
||||
private val currencyRatesDao: CurrencyRatesDao,
|
||||
) : ViewModel() {
|
||||
val userPrefs = userPrefsRepository.generalPrefs
|
||||
.stateIn(viewModelScope, GeneralPreferences())
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
val cachePercentage = currencyRatesDao.size()
|
||||
.map {
|
||||
|
@ -47,6 +47,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.BuildConfig
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.core.ui.openLink
|
||||
@ -59,14 +60,17 @@ internal fun AboutRoute(
|
||||
navigateUpAction: () -> Unit,
|
||||
navigateToThirdParty: () -> Unit,
|
||||
) {
|
||||
val prefs = viewModel.prefs.collectAsStateWithLifecycle()
|
||||
|
||||
when (val prefs = viewModel.prefs.collectAsStateWithLifecycle().value) {
|
||||
null -> UnittoEmptyScreen()
|
||||
else -> {
|
||||
AboutScreen(
|
||||
prefs = prefs.value,
|
||||
prefs = prefs,
|
||||
navigateUpAction = navigateUpAction,
|
||||
navigateToThirdParty = navigateToThirdParty,
|
||||
enableToolsExperiment = viewModel::enableToolsExperiment
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -196,7 +200,9 @@ private fun AboutScreen(
|
||||
@Composable
|
||||
fun PreviewAboutScreen() {
|
||||
AboutScreen(
|
||||
prefs = AboutPreferences(),
|
||||
prefs = AboutPreferences(
|
||||
enableToolsExperiment = false
|
||||
),
|
||||
navigateUpAction = {},
|
||||
navigateToThirdParty = {},
|
||||
enableToolsExperiment = {}
|
||||
|
@ -21,7 +21,6 @@ package com.sadellie.unitto.feature.settings.about
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.common.stateIn
|
||||
import com.sadellie.unitto.data.userprefs.AboutPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
@ -32,7 +31,7 @@ internal class AboutViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
) : ViewModel() {
|
||||
val prefs = userPrefsRepository.aboutPrefs
|
||||
.stateIn(viewModelScope, AboutPreferences())
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
fun enableToolsExperiment() = viewModelScope.launch {
|
||||
userPrefsRepository.updateToolsExperiment(true)
|
||||
|
@ -26,8 +26,11 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.OutputFormat
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.base.Separator
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.data.userprefs.CalculatorPreferences
|
||||
@ -37,13 +40,16 @@ internal fun CalculatorSettingsRoute(
|
||||
viewModel: CalculatorViewModel = hiltViewModel(),
|
||||
navigateUpAction: () -> Unit,
|
||||
) {
|
||||
val prefs = viewModel.prefs.collectAsStateWithLifecycle()
|
||||
|
||||
when (val prefs = viewModel.prefs.collectAsStateWithLifecycle().value) {
|
||||
null -> UnittoEmptyScreen()
|
||||
else -> {
|
||||
CalculatorSettingsScreen(
|
||||
prefs = prefs.value,
|
||||
prefs = prefs,
|
||||
navigateUpAction = navigateUpAction,
|
||||
updatePartialHistoryView = viewModel::updatePartialHistoryView
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -75,7 +81,15 @@ private fun CalculatorSettingsScreen(
|
||||
@Composable
|
||||
private fun PreviewCalculatorSettingsScreen() {
|
||||
CalculatorSettingsScreen(
|
||||
prefs = CalculatorPreferences(),
|
||||
prefs = CalculatorPreferences(
|
||||
radianMode = false,
|
||||
enableVibrations = false,
|
||||
separator = Separator.SPACE,
|
||||
middleZero = false,
|
||||
partialHistoryView = true,
|
||||
precision = 3,
|
||||
outputFormat = OutputFormat.PLAIN
|
||||
),
|
||||
navigateUpAction = {},
|
||||
updatePartialHistoryView = {}
|
||||
)
|
||||
|
@ -21,7 +21,6 @@ package com.sadellie.unitto.feature.settings.calculator
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.common.stateIn
|
||||
import com.sadellie.unitto.data.userprefs.CalculatorPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
@ -32,7 +31,7 @@ class CalculatorViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
) : ViewModel() {
|
||||
val prefs = userPrefsRepository.calculatorPrefs
|
||||
.stateIn(viewModelScope, CalculatorPreferences())
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
fun updatePartialHistoryView(enabled: Boolean) = viewModelScope.launch {
|
||||
userPrefsRepository.updatePartialHistoryView(enabled)
|
||||
|
@ -34,10 +34,14 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.sadellie.unitto.core.base.OutputFormat
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.base.Separator
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
import com.sadellie.unitto.data.userprefs.ConverterPreferences
|
||||
import com.sadellie.unitto.feature.settings.components.AlertDialogWithList
|
||||
@ -48,15 +52,18 @@ internal fun ConverterSettingsRoute(
|
||||
navigateUpAction: () -> Unit,
|
||||
navigateToUnitsGroup: () -> Unit,
|
||||
) {
|
||||
val prefs = viewModel.prefs.collectAsStateWithLifecycle()
|
||||
|
||||
when (val prefs = viewModel.prefs.collectAsStateWithLifecycle().value) {
|
||||
null -> UnittoEmptyScreen()
|
||||
else -> {
|
||||
ConverterSettingsScreen(
|
||||
prefs = prefs.value,
|
||||
prefs = prefs,
|
||||
navigateUpAction = navigateUpAction,
|
||||
navigateToUnitsGroup = navigateToUnitsGroup,
|
||||
updateUnitConverterFormatTime = viewModel::updateUnitConverterFormatTime,
|
||||
updateUnitConverterSorting = viewModel::updateUnitConverterSorting
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ -127,7 +134,20 @@ private fun ConverterSettingsScreen(
|
||||
@Composable
|
||||
private fun PreviewConverterSettingsScreen() {
|
||||
ConverterSettingsScreen(
|
||||
prefs = ConverterPreferences(),
|
||||
prefs = ConverterPreferences(
|
||||
enableVibrations = true,
|
||||
separator = Separator.SPACE,
|
||||
middleZero = false,
|
||||
precision = 3,
|
||||
outputFormat = OutputFormat.PLAIN,
|
||||
unitConverterFormatTime = false,
|
||||
unitConverterSorting = UnitsListSorting.USAGE,
|
||||
shownUnitGroups = ALL_UNIT_GROUPS,
|
||||
unitConverterFavoritesOnly = false,
|
||||
enableToolsExperiment = false,
|
||||
latestLeftSideUnit = "kilometer",
|
||||
latestRightSideUnit = "mile",
|
||||
),
|
||||
navigateUpAction = {},
|
||||
navigateToUnitsGroup = {},
|
||||
updateUnitConverterFormatTime = {},
|
||||
|
@ -22,7 +22,6 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.common.stateIn
|
||||
import com.sadellie.unitto.data.model.UnitsListSorting
|
||||
import com.sadellie.unitto.data.userprefs.ConverterPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
@ -33,7 +32,7 @@ internal class ConverterViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
) : ViewModel() {
|
||||
val prefs = userPrefsRepository.converterPrefs
|
||||
.stateIn(viewModelScope, ConverterPreferences())
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
fun updateUnitConverterFormatTime(enabled: Boolean) = viewModelScope.launch {
|
||||
userPrefsRepository.updateUnitConverterFormatTime(enabled)
|
||||
|
@ -59,6 +59,7 @@ import com.sadellie.unitto.core.ui.common.Header
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButton
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.feature.settings.components.ColorSelector
|
||||
@ -75,46 +76,49 @@ internal fun DisplayRoute(
|
||||
themmoController: ThemmoController,
|
||||
navigateToLanguages: () -> Unit,
|
||||
) {
|
||||
val prefs = viewModel.prefs.collectAsStateWithLifecycle()
|
||||
|
||||
when (val prefs = viewModel.prefs.collectAsStateWithLifecycle().value) {
|
||||
null -> UnittoEmptyScreen()
|
||||
else -> {
|
||||
DisplayScreen(
|
||||
navigateUp = navigateUp,
|
||||
currentThemingMode = themmoController.currentThemingMode,
|
||||
onThemeChange = {
|
||||
themmoController.setThemingMode(it)
|
||||
viewModel.updateThemingMode(it)
|
||||
onThemeChange = { newValue ->
|
||||
themmoController.setThemingMode(newValue)
|
||||
viewModel.updateThemingMode(newValue)
|
||||
},
|
||||
isDynamicThemeEnabled = themmoController.isDynamicThemeEnabled,
|
||||
onDynamicThemeChange = {
|
||||
onDynamicThemeChange = { newValue ->
|
||||
// Prevent old devices from using other monet modes when dynamic theming is on
|
||||
if (it) {
|
||||
if (newValue) {
|
||||
themmoController.setMonetMode(MonetMode.TonalSpot)
|
||||
viewModel.updateMonetMode(MonetMode.TonalSpot)
|
||||
}
|
||||
themmoController.enableDynamicTheme(it)
|
||||
viewModel.updateDynamicTheme(it)
|
||||
themmoController.enableDynamicTheme(newValue)
|
||||
viewModel.updateDynamicTheme(newValue)
|
||||
},
|
||||
isAmoledThemeEnabled = themmoController.isAmoledThemeEnabled,
|
||||
onAmoledThemeChange = {
|
||||
themmoController.enableAmoledTheme(it)
|
||||
viewModel.updateAmoledTheme(it)
|
||||
onAmoledThemeChange = { newValue ->
|
||||
themmoController.enableAmoledTheme(newValue)
|
||||
viewModel.updateAmoledTheme(newValue)
|
||||
},
|
||||
selectedColor = themmoController.currentCustomColor,
|
||||
onColorChange = {
|
||||
themmoController.setCustomColor(it)
|
||||
viewModel.updateCustomColor(it)
|
||||
onColorChange = { newValue ->
|
||||
themmoController.setCustomColor(newValue)
|
||||
viewModel.updateCustomColor(newValue)
|
||||
},
|
||||
monetMode = themmoController.currentMonetMode,
|
||||
onMonetModeChange = {
|
||||
themmoController.setMonetMode(it)
|
||||
viewModel.updateMonetMode(it)
|
||||
onMonetModeChange = { newValue ->
|
||||
themmoController.setMonetMode(newValue)
|
||||
viewModel.updateMonetMode(newValue)
|
||||
},
|
||||
systemFont = prefs.value.systemFont,
|
||||
systemFont = prefs.systemFont,
|
||||
updateSystemFont = viewModel::updateSystemFont,
|
||||
middleZero = prefs.value.middleZero,
|
||||
middleZero = prefs.middleZero,
|
||||
updateMiddleZero = viewModel::updateMiddleZero,
|
||||
navigateToLanguages = navigateToLanguages
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -22,7 +22,6 @@ 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
|
||||
@ -36,7 +35,7 @@ class DisplayViewModel @Inject constructor(
|
||||
) : ViewModel() {
|
||||
|
||||
val prefs = userPrefsRepository.displayPrefs
|
||||
.stateIn(viewModelScope, DisplayPreferences())
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateThemingMode
|
||||
|
@ -57,6 +57,7 @@ import com.sadellie.unitto.core.base.Separator
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButton
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.core.ui.common.UnittoSlider
|
||||
@ -70,16 +71,19 @@ fun FormattingRoute(
|
||||
viewModel: FormattingViewModel = hiltViewModel(),
|
||||
navigateUpAction: () -> Unit,
|
||||
) {
|
||||
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
when (val uiState = viewModel.uiState.collectAsStateWithLifecycle().value) {
|
||||
null -> UnittoEmptyScreen()
|
||||
else -> {
|
||||
FormattingScreen(
|
||||
navigateUpAction = navigateUpAction,
|
||||
uiState = uiState.value,
|
||||
uiState = uiState,
|
||||
onPrecisionChange = viewModel::updatePrecision,
|
||||
onSeparatorChange = viewModel::updateSeparator,
|
||||
onOutputFormatChange = viewModel::updateOutputFormat,
|
||||
togglePreview = viewModel::togglePreview
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -61,7 +61,7 @@ class FormattingViewModel @Inject constructor(
|
||||
formatterSymbols = formatterSymbols
|
||||
)
|
||||
}
|
||||
.stateIn(viewModelScope, FormattingUIState())
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
fun togglePreview() = _fractional.update { !it }
|
||||
|
||||
|
@ -23,8 +23,8 @@ import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.navDeepLink
|
||||
import com.sadellie.unitto.core.base.TopLevelDestinations
|
||||
import com.sadellie.unitto.core.ui.unittoComposable
|
||||
import com.sadellie.unitto.core.ui.unittoNavigation
|
||||
import com.sadellie.unitto.core.ui.unittoStackedComposable
|
||||
import com.sadellie.unitto.feature.settings.SettingsRoute
|
||||
import com.sadellie.unitto.feature.settings.about.AboutRoute
|
||||
import com.sadellie.unitto.feature.settings.calculator.CalculatorSettingsRoute
|
||||
@ -68,14 +68,14 @@ fun NavGraphBuilder.settingGraph(
|
||||
navDeepLink { uriPattern = "app://com.sadellie.unitto/$graph" }
|
||||
)
|
||||
) {
|
||||
unittoComposable(start) {
|
||||
unittoStackedComposable(start) {
|
||||
SettingsRoute(
|
||||
navigateUp = navController::navigateUp,
|
||||
navControllerAction = navController::navigate
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(displayRoute) {
|
||||
unittoStackedComposable(displayRoute) {
|
||||
DisplayRoute(
|
||||
navigateUp = navController::navigateUp,
|
||||
themmoController = themmoController,
|
||||
@ -83,51 +83,51 @@ fun NavGraphBuilder.settingGraph(
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(languageRoute) {
|
||||
unittoStackedComposable(languageRoute) {
|
||||
LanguageRoute(
|
||||
navigateUp = navController::navigateUp,
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(startingScreenRoute) {
|
||||
unittoStackedComposable(startingScreenRoute) {
|
||||
StartingScreenRoute(
|
||||
navigateUp = navController::navigateUp,
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(formattingRoute) {
|
||||
unittoStackedComposable(formattingRoute) {
|
||||
FormattingRoute(
|
||||
navigateUpAction = navController::navigateUp
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(calculatorSettingsRoute) {
|
||||
unittoStackedComposable(calculatorSettingsRoute) {
|
||||
CalculatorSettingsRoute(
|
||||
navigateUpAction = navController::navigateUp,
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(converterSettingsRoute) {
|
||||
unittoStackedComposable(converterSettingsRoute) {
|
||||
ConverterSettingsRoute(
|
||||
navigateUpAction = navController::navigateUp,
|
||||
navigateToUnitsGroup = { navController.navigate(unitsGroupRoute) }
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(unitsGroupRoute) {
|
||||
unittoStackedComposable(unitsGroupRoute) {
|
||||
UnitGroupsScreen(
|
||||
navigateUpAction = navController::navigateUp,
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(aboutRoute) {
|
||||
unittoStackedComposable(aboutRoute) {
|
||||
AboutRoute(
|
||||
navigateUpAction = navController::navigateUp,
|
||||
navigateToThirdParty = { navController.navigate(thirdPartyRoute) }
|
||||
)
|
||||
}
|
||||
|
||||
unittoComposable(thirdPartyRoute) {
|
||||
unittoStackedComposable(thirdPartyRoute) {
|
||||
ThirdPartyLicensesScreen(
|
||||
navigateUpAction = navController::navigateUp,
|
||||
)
|
||||
|
@ -40,6 +40,7 @@ import com.sadellie.unitto.core.base.TOP_LEVEL_DESTINATIONS
|
||||
import com.sadellie.unitto.core.base.TopLevelDestinations
|
||||
import com.sadellie.unitto.core.ui.addShortcut
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
|
||||
@ -48,13 +49,16 @@ internal fun StartingScreenRoute(
|
||||
viewModel: StartingScreenViewModel = hiltViewModel(),
|
||||
navigateUp: () -> Unit
|
||||
) {
|
||||
val prefs = viewModel.prefs.collectAsStateWithLifecycle()
|
||||
|
||||
when (val prefs = viewModel.prefs.collectAsStateWithLifecycle().value) {
|
||||
null -> UnittoEmptyScreen()
|
||||
else -> {
|
||||
StartingScreenScreen(
|
||||
startingScreen = prefs.value.startingScreen,
|
||||
startingScreen = prefs.startingScreen,
|
||||
updateStartingScreen = viewModel::updateStartingScreen,
|
||||
navigateUp = navigateUp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -21,7 +21,6 @@ package com.sadellie.unitto.feature.settings.startingscreen
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.data.common.stateIn
|
||||
import com.sadellie.unitto.data.userprefs.StartingScreenPreferences
|
||||
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
@ -32,7 +31,7 @@ internal class StartingScreenViewModel @Inject constructor(
|
||||
private val userPrefsRepository: UserPreferencesRepository,
|
||||
) : ViewModel() {
|
||||
val prefs = userPrefsRepository.startingScreenPrefs
|
||||
.stateIn(viewModelScope, StartingScreenPreferences())
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
fun updateStartingScreen(startingScreen: String) = viewModelScope.launch {
|
||||
userPrefsRepository.updateStartingScreen(startingScreen)
|
||||
|
Loading…
x
Reference in New Issue
Block a user