mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-18 16:25:27 +02:00
Better theming options:
- Improved UI/UX - Added ability to pick color scheme
This commit is contained in:
parent
ede1ffe2cd
commit
b7127e75a9
@ -63,7 +63,8 @@ internal fun UnittoApp() {
|
||||
// Anything below will not be called if theming mode is still loading from DataStore
|
||||
themingMode = userPrefs.value.themingMode ?: return,
|
||||
dynamicThemeEnabled = userPrefs.value.enableDynamicTheme,
|
||||
amoledThemeEnabled = userPrefs.value.enableAmoledTheme
|
||||
amoledThemeEnabled = userPrefs.value.enableAmoledTheme,
|
||||
customColor = userPrefs.value.customColor
|
||||
)
|
||||
val navController = rememberNavController()
|
||||
val sysUiController = rememberSystemUiController()
|
||||
|
@ -1064,9 +1064,9 @@
|
||||
<string name="ton_force_short">tf</string>
|
||||
<string name="millinewton">Millinewton</string>
|
||||
<string name="millinewton_short">mN</string>
|
||||
<string name="attonewton">attonewton</string>
|
||||
<string name="attonewton">Attonewton</string>
|
||||
<string name="attonewton_short">aN</string>
|
||||
<string name="dyne">dyne</string>
|
||||
<string name="dyne">Dyne</string>
|
||||
<string name="dyne_short">dyn</string>
|
||||
<string name="joule_per_meter">Joule/meter</string>
|
||||
<string name="joule_per_meter_short">J/m</string>
|
||||
@ -1317,10 +1317,13 @@
|
||||
<string name="force_light_mode">Light</string>
|
||||
<string name="force_dark_mode">Dark</string>
|
||||
<string name="color_theme">Color theme</string>
|
||||
<string name="color_theme_support">Pick a theming mode</string>
|
||||
<string name="force_amoled_mode">AMOLED Dark</string>
|
||||
<string name="force_amoled_mode_support">Use black background for dark themes</string>
|
||||
<string name="enable_dynamic_colors">Dynamic colors</string>
|
||||
<string name="enable_dynamic_colors_support">Use colors from your wallpaper</string>
|
||||
<string name="color_scheme">Color scheme</string>
|
||||
<string name="selected_color">Selected color</string>
|
||||
|
||||
<!--MISC.-->
|
||||
<string name="loading_label">Loading…</string>
|
||||
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
private val GroupRowContainerHeight = 40.dp
|
||||
private val GroupRowItemMinWidth = 58.dp
|
||||
|
||||
@Composable
|
||||
fun SegmentedButtonRow(
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable RowScope.() -> Unit
|
||||
) {
|
||||
OutlinedCard(
|
||||
modifier = modifier,
|
||||
shape = CircleShape
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(GroupRowContainerHeight)
|
||||
.widthIn(min = GroupRowItemMinWidth),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RowScope.SegmentedButton(
|
||||
onClick: () -> Unit,
|
||||
selected: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val containerColor =
|
||||
if (selected)
|
||||
MaterialTheme.colorScheme.secondaryContainer
|
||||
else
|
||||
MaterialTheme.colorScheme.surface
|
||||
OutlinedButton(
|
||||
modifier = modifier.weight(1f),
|
||||
onClick = onClick,
|
||||
shape = RectangleShape,
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColorFor(containerColor)
|
||||
),
|
||||
enabled = enabled,
|
||||
contentPadding = PaddingValues(horizontal = 12.dp)
|
||||
) {
|
||||
AnimatedVisibility(visible = selected) {
|
||||
Row {
|
||||
Icon(
|
||||
modifier = Modifier.size(18.dp),
|
||||
imageVector = Icons.Default.Check,
|
||||
contentDescription = null
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
}
|
||||
}
|
||||
content()
|
||||
}
|
||||
}
|
@ -18,12 +18,14 @@
|
||||
|
||||
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
|
||||
@ -47,6 +49,7 @@ import javax.inject.Inject
|
||||
* still loading.
|
||||
* @property enableDynamicTheme Use dynamic color scheme
|
||||
* @property enableAmoledTheme Use amoled color scheme
|
||||
* @property customColor Generate custom color scheme from this color.
|
||||
* @property digitsPrecision Current [PRECISIONS]. Number of digits in fractional part
|
||||
* @property separator Current [Separator] that used to separate thousands
|
||||
* @property outputFormat Current [OutputFormat] that is applied to converted value (not input)
|
||||
@ -64,6 +67,7 @@ data class UserPreferences(
|
||||
val themingMode: ThemingMode? = null,
|
||||
val enableDynamicTheme: Boolean = false,
|
||||
val enableAmoledTheme: Boolean = false,
|
||||
val customColor: Color = Color.Unspecified,
|
||||
val digitsPrecision: Int = 3,
|
||||
val separator: Int = Separator.SPACES,
|
||||
val outputFormat: Int = OutputFormat.PLAIN,
|
||||
@ -90,6 +94,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
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 DIGITS_PRECISION = intPreferencesKey("DIGITS_PRECISION_PREF_KEY")
|
||||
val SEPARATOR = intPreferencesKey("SEPARATOR_PREF_KEY")
|
||||
val OUTPUT_FORMAT = intPreferencesKey("OUTPUT_FORMAT_PREF_KEY")
|
||||
@ -117,20 +122,14 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
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 digitsPrecision: Int =
|
||||
preferences[PrefsKeys.DIGITS_PRECISION] ?: 3
|
||||
val separator: Int =
|
||||
preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACES
|
||||
val outputFormat: Int =
|
||||
preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN
|
||||
val latestLeftSideUnit: String =
|
||||
preferences[PrefsKeys.LATEST_LEFT_SIDE] ?: MyUnitIDS.kilometer
|
||||
val latestRightSideUnit: String =
|
||||
preferences[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile
|
||||
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 digitsPrecision: Int = preferences[PrefsKeys.DIGITS_PRECISION] ?: 3
|
||||
val separator: Int = preferences[PrefsKeys.SEPARATOR] ?: Separator.SPACES
|
||||
val outputFormat: Int = preferences[PrefsKeys.OUTPUT_FORMAT] ?: OutputFormat.PLAIN
|
||||
val latestLeftSideUnit: String = preferences[PrefsKeys.LATEST_LEFT_SIDE] ?: MyUnitIDS.kilometer
|
||||
val latestRightSideUnit: String = preferences[PrefsKeys.LATEST_RIGHT_SIDE] ?: MyUnitIDS.mile
|
||||
val shownUnitGroups: List<UnitGroup> =
|
||||
preferences[PrefsKeys.SHOWN_UNIT_GROUPS]?.let { list ->
|
||||
// Everything is in hidden (nothing in shown)
|
||||
@ -157,6 +156,7 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
themingMode = themingMode,
|
||||
enableDynamicTheme = enableDynamicTheme,
|
||||
enableAmoledTheme = enableAmoledTheme,
|
||||
customColor = customColor,
|
||||
digitsPrecision = digitsPrecision,
|
||||
separator = separator,
|
||||
outputFormat = outputFormat,
|
||||
@ -253,6 +253,17 @@ class UserPreferencesRepository @Inject constructor(private val dataStore: DataS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update preference on custom color scheme.
|
||||
*
|
||||
* @param color New custom color value.
|
||||
*/
|
||||
suspend fun updateCustomColor(color: Color) {
|
||||
dataStore.edit { preferences ->
|
||||
preferences[PrefsKeys.CUSTOM_COLOR] = color.value.toLong()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update preference on starting screen route.
|
||||
*
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.sadellie.unitto.feature.settings
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.core.ui.Formatter
|
||||
@ -75,6 +76,15 @@ class SettingsViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateCustomColor
|
||||
*/
|
||||
fun updateCustomColor(color: Color) {
|
||||
viewModelScope.launch {
|
||||
userPrefsRepository.updateCustomColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateDigitsPrecision
|
||||
*/
|
||||
|
@ -24,77 +24,123 @@ import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Colorize
|
||||
import androidx.compose.material.icons.filled.DarkMode
|
||||
import androidx.compose.material.icons.filled.Palette
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sadellie.unitto.core.ui.R
|
||||
import com.sadellie.unitto.core.ui.common.Header
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.feature.settings.components.ColorSelector
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButton
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButtonRow
|
||||
import io.github.sadellie.themmo.ThemingMode
|
||||
import io.github.sadellie.themmo.ThemmoController
|
||||
|
||||
@Composable
|
||||
internal fun ThemesScreen(
|
||||
internal fun ThemesRoute(
|
||||
navigateUpAction: () -> Unit = {},
|
||||
themmoController: ThemmoController,
|
||||
viewModel: SettingsViewModel
|
||||
) {
|
||||
ThemesScreen(
|
||||
navigateUpAction = navigateUpAction,
|
||||
currentThemingMode = themmoController.currentThemingMode,
|
||||
onThemeChange = {
|
||||
themmoController.setThemingMode(it)
|
||||
viewModel.updateThemingMode(it)
|
||||
},
|
||||
isDynamicThemeEnabled = themmoController.isDynamicThemeEnabled,
|
||||
onDynamicThemeChange = {
|
||||
themmoController.enableDynamicTheme(it)
|
||||
viewModel.updateDynamicTheme(it)
|
||||
},
|
||||
isAmoledThemeEnabled = themmoController.isAmoledThemeEnabled,
|
||||
onAmoledThemeChange = {
|
||||
themmoController.enableAmoledTheme(it)
|
||||
viewModel.updateAmoledTheme(it)
|
||||
},
|
||||
selectedColor = themmoController.currentCustomColor,
|
||||
onColorChange = {
|
||||
themmoController.setCustomColor(it)
|
||||
viewModel.updateCustomColor(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ThemesScreen(
|
||||
navigateUpAction: () -> Unit,
|
||||
currentThemingMode: ThemingMode,
|
||||
onThemeChange: (ThemingMode) -> Unit,
|
||||
isDynamicThemeEnabled: Boolean,
|
||||
onDynamicThemeChange: (Boolean) -> Unit,
|
||||
isAmoledThemeEnabled: Boolean,
|
||||
onAmoledThemeChange: (Boolean) -> Unit,
|
||||
selectedColor: Color,
|
||||
onColorChange: (Color) -> Unit,
|
||||
) {
|
||||
val themingModes by remember {
|
||||
mutableStateOf(
|
||||
mapOf(
|
||||
ThemingMode.AUTO to R.string.force_auto_mode,
|
||||
ThemingMode.FORCE_LIGHT to R.string.force_light_mode,
|
||||
ThemingMode.FORCE_DARK to R.string.force_dark_mode
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
UnittoScreenWithLargeTopBar(
|
||||
title = stringResource(R.string.theme_setting),
|
||||
navigationIcon = { NavigateUpButton(navigateUpAction) }
|
||||
) { paddingValues ->
|
||||
LazyColumn(contentPadding = paddingValues) {
|
||||
item {
|
||||
UnittoListItem(
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Default.Palette,
|
||||
stringResource(R.string.color_theme),
|
||||
)
|
||||
},
|
||||
label = stringResource(R.string.color_theme),
|
||||
allOptions = mapOf(
|
||||
ThemingMode.AUTO to stringResource(R.string.force_auto_mode),
|
||||
ThemingMode.FORCE_LIGHT to stringResource(R.string.force_light_mode),
|
||||
ThemingMode.FORCE_DARK to stringResource(R.string.force_dark_mode)
|
||||
),
|
||||
selected = themmoController.currentThemingMode,
|
||||
onSelectedChange = {
|
||||
themmoController.setThemingMode(it)
|
||||
viewModel.updateThemingMode(it)
|
||||
}
|
||||
headlineContent = { Text(stringResource(R.string.color_theme)) },
|
||||
supportingContent = { Text(stringResource(R.string.color_theme_support)) },
|
||||
)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
item {
|
||||
UnittoListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Default.Colorize,
|
||||
stringResource(R.string.enable_dynamic_colors),
|
||||
)
|
||||
},
|
||||
label = stringResource(R.string.enable_dynamic_colors),
|
||||
supportContent = stringResource(R.string.enable_dynamic_colors_support),
|
||||
switchState = themmoController.isDynamicThemeEnabled,
|
||||
onSwitchChange = {
|
||||
themmoController.enableDynamicTheme(it)
|
||||
viewModel.updateDynamicTheme(it)
|
||||
}
|
||||
)
|
||||
item {
|
||||
SegmentedButtonRow(
|
||||
modifier = Modifier.padding(56.dp, 8.dp, 24.dp, 2.dp)
|
||||
) {
|
||||
themingModes.forEach { (mode, stringRes) ->
|
||||
SegmentedButton(
|
||||
onClick = { onThemeChange(mode) },
|
||||
selected = currentThemingMode == mode,
|
||||
content = { Text(stringResource(stringRes)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
AnimatedVisibility(
|
||||
visible = (themmoController.currentThemingMode != ThemingMode.FORCE_LIGHT),
|
||||
visible = currentThemingMode != ThemingMode.FORCE_LIGHT,
|
||||
enter = expandVertically() + fadeIn(),
|
||||
exit = shrinkVertically() + fadeOut(),
|
||||
) {
|
||||
@ -107,14 +153,66 @@ internal fun ThemesScreen(
|
||||
},
|
||||
label = stringResource(R.string.force_amoled_mode),
|
||||
supportContent = stringResource(R.string.force_amoled_mode_support),
|
||||
switchState = themmoController.isAmoledThemeEnabled,
|
||||
onSwitchChange = {
|
||||
themmoController.enableAmoledTheme(it)
|
||||
viewModel.updateAmoledTheme(it)
|
||||
}
|
||||
switchState = isAmoledThemeEnabled,
|
||||
onSwitchChange = onAmoledThemeChange
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item { Header(stringResource(R.string.color_scheme)) }
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
item {
|
||||
UnittoListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Default.Colorize,
|
||||
stringResource(R.string.enable_dynamic_colors),
|
||||
)
|
||||
},
|
||||
label = stringResource(R.string.enable_dynamic_colors),
|
||||
supportContent = stringResource(R.string.enable_dynamic_colors_support),
|
||||
switchState = isDynamicThemeEnabled,
|
||||
onSwitchChange = onDynamicThemeChange
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
AnimatedVisibility(
|
||||
visible = !isDynamicThemeEnabled,
|
||||
enter = expandVertically() + fadeIn(),
|
||||
exit = shrinkVertically() + fadeOut(),
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(R.string.selected_color)) },
|
||||
supportingContent = {
|
||||
ColorSelector(
|
||||
modifier = Modifier.padding(top = 12.dp),
|
||||
selected = selectedColor,
|
||||
onItemClick = onColorChange
|
||||
)
|
||||
},
|
||||
modifier = Modifier.padding(start = 40.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
ThemesScreen(
|
||||
navigateUpAction = {},
|
||||
currentThemingMode = ThemingMode.AUTO,
|
||||
onThemeChange = {},
|
||||
isDynamicThemeEnabled = false,
|
||||
onDynamicThemeChange = {},
|
||||
isAmoledThemeEnabled = false,
|
||||
onAmoledThemeChange = {},
|
||||
selectedColor = Color.Unspecified,
|
||||
onColorChange = {}
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.feature.settings.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.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
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.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
internal fun ColorSelector(
|
||||
modifier: Modifier = Modifier,
|
||||
selected: Color,
|
||||
onItemClick: (Color) -> Unit,
|
||||
) {
|
||||
val colorSchemes: List<Color> by remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
Color(0xFFE91E63),
|
||||
Color(0xFFFF9800),
|
||||
Color(0xFF4CAF50),
|
||||
Color(0xFF2196F3),
|
||||
Color(0xFF9C27B0),
|
||||
Color(0xFF5C76AA),
|
||||
Color(0xFF756FAA),
|
||||
Color(0xFF9E6C2A),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
LazyRow(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
// Default, Unitto colors
|
||||
item {
|
||||
ColorCheckbox(
|
||||
color = Color(0xFF186c31),
|
||||
selected = Color.Unspecified == selected,
|
||||
onClick = { onItemClick(Color.Unspecified) }
|
||||
)
|
||||
}
|
||||
colorSchemes.forEach {
|
||||
item {
|
||||
ColorCheckbox(
|
||||
color = it,
|
||||
selected = it == selected,
|
||||
onClick = { onItemClick(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ColorCheckbox(
|
||||
color: Color,
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp),
|
||||
RoundedCornerShape(25)
|
||||
)
|
||||
.width(72.dp)
|
||||
.aspectRatio(1f),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(color, CircleShape)
|
||||
.size(54.dp)
|
||||
.border(1.dp, Color.Black.copy(0.5f), CircleShape)
|
||||
)
|
||||
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 = if (color.luminance() > 0.5) Color.Black else Color.White,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ import com.sadellie.unitto.core.base.TopLevelDestinations
|
||||
import com.sadellie.unitto.feature.settings.AboutScreen
|
||||
import com.sadellie.unitto.feature.settings.SettingsScreen
|
||||
import com.sadellie.unitto.feature.settings.SettingsViewModel
|
||||
import com.sadellie.unitto.feature.settings.ThemesScreen
|
||||
import com.sadellie.unitto.feature.settings.ThemesRoute
|
||||
import com.sadellie.unitto.feature.settings.ThirdPartyLicensesScreen
|
||||
import com.sadellie.unitto.feature.settings.UnitGroupsScreen
|
||||
import io.github.sadellie.themmo.ThemmoController
|
||||
@ -63,7 +63,7 @@ fun NavGraphBuilder.settingGraph(
|
||||
}
|
||||
|
||||
composable(themesRoute) {
|
||||
ThemesScreen(
|
||||
ThemesRoute(
|
||||
navigateUpAction = { navController.navigateUp() },
|
||||
themmoController = themmoController,
|
||||
viewModel = settingsViewModel
|
||||
|
Loading…
x
Reference in New Issue
Block a user