From efc1c9a84126b7f86a619d3c75250f09f8268fe2 Mon Sep 17 00:00:00 2001 From: Sad Ellie Date: Sun, 23 Apr 2023 17:23:28 +0300 Subject: [PATCH] Better color schemes --- .../java/com/sadellie/unitto/UnittoApp.kt | 5 +- core/base/src/main/res/values/strings.xml | 1 + .../unitto/data/userprefs/UserPreferences.kt | 22 ++- .../feature/settings/SettingsViewModel.kt | 10 ++ .../unitto/feature/settings/ThemesScreen.kt | 52 ++++++- .../settings/components/MonetCheckbox.kt | 145 ++++++++++++++++++ gradle/libs.versions.toml | 2 +- 7 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/MonetCheckbox.kt diff --git a/app/src/main/java/com/sadellie/unitto/UnittoApp.kt b/app/src/main/java/com/sadellie/unitto/UnittoApp.kt index 4bd03aff..e513a68a 100644 --- a/app/src/main/java/com/sadellie/unitto/UnittoApp.kt +++ b/app/src/main/java/com/sadellie/unitto/UnittoApp.kt @@ -64,7 +64,8 @@ internal fun UnittoApp() { themingMode = userPrefs.value.themingMode ?: return, dynamicThemeEnabled = userPrefs.value.enableDynamicTheme, amoledThemeEnabled = userPrefs.value.enableAmoledTheme, - customColor = userPrefs.value.customColor + customColor = userPrefs.value.customColor, + monetMode = userPrefs.value.monetMode ) val navController = rememberNavController() val sysUiController = rememberSystemUiController() @@ -100,7 +101,7 @@ internal fun UnittoApp() { Themmo( themmoController = themmoController, typography = AppTypography, - animationSpec = tween(150) + animationSpec = tween(450) ) { val statusBarColor = when (currentRoute) { // Match text field container color diff --git a/core/base/src/main/res/values/strings.xml b/core/base/src/main/res/values/strings.xml index 1665a142..b444c12a 100644 --- a/core/base/src/main/res/values/strings.xml +++ b/core/base/src/main/res/values/strings.xml @@ -1324,6 +1324,7 @@ Use colors from your wallpaper Color scheme Selected color + Selected style Loading… diff --git a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt index 2fdb1500..00cb4085 100644 --- a/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt +++ b/data/userprefs/src/main/java/com/sadellie/unitto/data/userprefs/UserPreferences.kt @@ -35,6 +35,7 @@ import com.sadellie.unitto.data.model.AbstractUnit import com.sadellie.unitto.data.model.UnitGroup import com.sadellie.unitto.data.model.UnitsListSorting import com.sadellie.unitto.data.units.MyUnitIDS +import io.github.sadellie.themmo.MonetMode import io.github.sadellie.themmo.ThemingMode import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch @@ -68,6 +69,7 @@ data class UserPreferences( val enableDynamicTheme: Boolean = false, val enableAmoledTheme: Boolean = false, val customColor: Color = Color.Unspecified, + val monetMode: MonetMode = MonetMode.TONAL_SPOT, val digitsPrecision: Int = 3, val separator: Int = Separator.SPACES, val outputFormat: Int = OutputFormat.PLAIN, @@ -95,6 +97,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS 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") @@ -119,12 +122,13 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS } } .map { preferences -> - val themingMode: ThemingMode = - preferences[PrefsKeys.THEMING_MODE]?.let { ThemingMode.valueOf(it) } - ?: ThemingMode.AUTO + val themingMode: ThemingMode = preferences[PrefsKeys.THEMING_MODE]?.let { ThemingMode.valueOf(it) } + ?: ThemingMode.AUTO val enableDynamicTheme: Boolean = preferences[PrefsKeys.ENABLE_DYNAMIC_THEME] ?: false val enableAmoledTheme: Boolean = preferences[PrefsKeys.ENABLE_AMOLED_THEME] ?: false val customColor: Color = preferences[PrefsKeys.CUSTOM_COLOR]?.let { Color(it.toULong()) } ?: Color.Unspecified + val monetMode: MonetMode = preferences[PrefsKeys.MONET_MODE]?.let { MonetMode.valueOf(it) } + ?: MonetMode.TONAL_SPOT val digitsPrecision: Int = preferences[PrefsKeys.DIGITS_PRECISION] ?: 3 val separator: Int = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACES val outputFormat: Int = preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN @@ -156,6 +160,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS enableDynamicTheme = enableDynamicTheme, enableAmoledTheme = enableAmoledTheme, customColor = customColor, + monetMode = monetMode, digitsPrecision = digitsPrecision, separator = separator, outputFormat = outputFormat, @@ -263,6 +268,17 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS } } + /** + * Update [MonetMode]. Saves value as a string. + * + * @param monetMode [MonetMode] to save. + */ + suspend fun updateMonetMode(monetMode: MonetMode) { + dataStore.edit { preferences -> + preferences[PrefsKeys.MONET_MODE] = monetMode.name + } + } + /** * Update preference on starting screen route. * diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt index ac7242f4..0b6a0598 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/SettingsViewModel.kt @@ -28,6 +28,7 @@ import com.sadellie.unitto.data.unitgroups.UnitGroupsRepository import com.sadellie.unitto.data.userprefs.UserPreferences import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import dagger.hilt.android.lifecycle.HiltViewModel +import io.github.sadellie.themmo.MonetMode import io.github.sadellie.themmo.ThemingMode import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.first @@ -86,6 +87,15 @@ class SettingsViewModel @Inject constructor( } } + /** + * @see UserPreferencesRepository.updateMonetMode + */ + fun updateMonetMode(monetMode: MonetMode) { + viewModelScope.launch { + userPrefsRepository.updateMonetMode(monetMode) + } + } + /** * @see UserPreferencesRepository.updateDigitsPrecision */ diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt index af65a848..23bab4df 100644 --- a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/ThemesScreen.kt @@ -50,18 +50,23 @@ import com.sadellie.unitto.core.ui.common.SegmentedButtonRow import com.sadellie.unitto.core.ui.common.UnittoListItem import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.feature.settings.components.ColorSelector +import com.sadellie.unitto.feature.settings.components.MonetModeSelector +import io.github.sadellie.themmo.MonetMode import io.github.sadellie.themmo.ThemingMode import io.github.sadellie.themmo.ThemmoController private val colorSchemes: List by lazy { listOf( - Color(0xFF8A3B31), - Color(0xFFA5744A), - Color(0xFF6C8B48), - Color(0xFF27B089), - Color(0xFF5C7BAA), - Color(0xFF544F80), - Color(0xFF9A2A9E), + Color(0xFFF6A1BC), + Color(0xFFFDA387), + Color(0xFFEAAF60), + Color(0xFFC2BD64), + Color(0xFF94C78A), + Color(0xFF73C9B5), + Color(0xFF72C6DA), + Color(0xFF8FBEF2), + Color(0xFFB6B3F6), + Color(0xFFDCA8E4), ) } @@ -93,6 +98,11 @@ internal fun ThemesRoute( themmoController.setCustomColor(it) viewModel.updateCustomColor(it) }, + monetMode = themmoController.currentMonetMode, + onMonetModeChange = { + themmoController.setMonetMode(it) + viewModel.updateMonetMode(it) + } ) } @@ -107,6 +117,8 @@ private fun ThemesScreen( onAmoledThemeChange: (Boolean) -> Unit, selectedColor: Color, onColorChange: (Color) -> Unit, + monetMode: MonetMode, + onMonetModeChange: (MonetMode) -> Unit ) { val themingModes by remember { mutableStateOf( @@ -212,6 +224,30 @@ private fun ThemesScreen( ) } } + + item { + AnimatedVisibility( + visible = (!isDynamicThemeEnabled) and (selectedColor != Color.Unspecified), + enter = expandVertically() + fadeIn(), + exit = shrinkVertically() + fadeOut(), + ) { + ListItem( + headlineContent = { Text(stringResource(R.string.monet_mode)) }, + supportingContent = { + MonetModeSelector( + modifier = Modifier.padding(top = 12.dp), + selected = monetMode, + onItemClick = onMonetModeChange, + monetModes = remember { MonetMode.values().toList() }, + customColor = selectedColor, + themingMode = currentThemingMode, + amoledThemeEnabled = isAmoledThemeEnabled, + ) + }, + modifier = Modifier.padding(start = 40.dp) + ) + } + } } } } @@ -229,5 +265,7 @@ private fun Preview() { onAmoledThemeChange = {}, selectedColor = Color.Unspecified, onColorChange = {}, + monetMode = MonetMode.TONAL_SPOT, + onMonetModeChange = {} ) } diff --git a/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/MonetCheckbox.kt b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/MonetCheckbox.kt new file mode 100644 index 00000000..4e530eab --- /dev/null +++ b/feature/settings/src/main/java/com/sadellie/unitto/feature/settings/components/MonetCheckbox.kt @@ -0,0 +1,145 @@ +/* + * 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 . + */ + +package com.sadellie.unitto.feature.settings.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.material3.surfaceColorAtElevation +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import io.github.sadellie.themmo.MonetMode +import io.github.sadellie.themmo.ThemingMode +import io.github.sadellie.themmo.Themmo +import io.github.sadellie.themmo.ThemmoController + +@Composable +internal fun MonetModeSelector( + modifier: Modifier = Modifier, + selected: MonetMode, + onItemClick: (MonetMode) -> Unit, + monetModes: List, + customColor: Color, + themingMode: ThemingMode, + amoledThemeEnabled: Boolean, +) { + LazyRow( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(monetModes) { monetMode -> + Themmo( + themmoController = remember(customColor) { + ThemmoController( + lightColorScheme = lightColorScheme(), + darkColorScheme = darkColorScheme(), + themingMode = themingMode, + dynamicThemeEnabled = false, + amoledThemeEnabled = false, + customColor = customColor, + monetMode = monetMode + ) + } + ) { + MonetModeCheckbox( + selected = monetMode == selected, + onClick = { onItemClick(monetMode) } + ) + } + } + } +} + +@Composable +private fun MonetModeCheckbox( + selected: Boolean, + onClick: () -> Unit +) { + Box( + modifier = Modifier + .width(72.dp) + .clip(RoundedCornerShape(25)) + .clickable(onClick = onClick) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)), + contentAlignment = Alignment.Center + ) { + Box( + modifier = Modifier + .fillMaxSize() + .aspectRatio(1f) + .padding(8.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.secondary) + .border(1.dp, Color.Black.copy(0.5f), CircleShape), + ) { + // Is this bad? Yes. Does it work? Also yes. + Box(modifier = Modifier + .fillMaxHeight(0.5f) + .fillMaxWidth() + .background(MaterialTheme.colorScheme.primary)) + Box(modifier = Modifier + .fillMaxHeight(0.5f) + .fillMaxWidth(0.5f) + .background(MaterialTheme.colorScheme.secondaryContainer)) + } + AnimatedVisibility( + visible = selected, + enter = fadeIn(tween(250)) + scaleIn(tween(150)), + exit = fadeOut(tween(250)) + scaleOut(tween(150)), + ) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = null, + tint = MaterialTheme.colorScheme.inverseOnSurface, + modifier = Modifier + .background(MaterialTheme.colorScheme.inverseSurface, CircleShape) + .padding(4.dp) + ) + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f8662b68..28a8b33b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ comGoogleAccompanist = "0.30.1" androidxRoom = "2.5.1" comSquareupMoshi = "1.14.0" comSquareupRetrofit2 = "2.9.0" -comGithubSadellieThemmo = "90842e93f4" +comGithubSadellieThemmo = "ed4063f70f" orgBurnoutcrewComposereorderable = "0.9.6" comGithubSadellieExprk = "e55cba8f41" mxParser = "5.2.1"