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"