Custom color schemes v2 - part 3
Store preferences and apply color schemes
This commit is contained in:
parent
f128469f68
commit
1a86aa018e
@ -26,8 +26,6 @@ import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.colorscheme.ColorSchemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.colorscheme.CustomColorSchemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.colorscheme.ThemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.colorscheme.ThemesSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.crashreporter.CrashReportScreen
|
||||
@ -98,12 +96,6 @@ class SettingsActivity : BaseActivity() {
|
||||
composable("settings/icons") {
|
||||
IconsSettingsScreen()
|
||||
}
|
||||
composable("settings/appearance/colorscheme") {
|
||||
ColorSchemeSettingsScreen()
|
||||
}
|
||||
composable("settings/appearance/colorscheme/custom") {
|
||||
CustomColorSchemeSettingsScreen()
|
||||
}
|
||||
composable("settings/appearance/themes") {
|
||||
ThemesSettingsScreen()
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
|
||||
@ -25,6 +26,7 @@ fun AppearanceSettingsScreen() {
|
||||
val viewModel: AppearanceSettingsScreenVM = viewModel()
|
||||
val context = LocalContext.current
|
||||
val navController = LocalNavController.current
|
||||
val themeName by viewModel.colorSchemeName.collectAsStateWithLifecycle(null)
|
||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
@ -42,27 +44,9 @@ fun AppearanceSettingsScreen() {
|
||||
viewModel.setTheme(newValue)
|
||||
}
|
||||
)
|
||||
val colorScheme by viewModel.colorScheme.collectAsState()
|
||||
Preference(
|
||||
title = stringResource(id = R.string.preference_screen_colors),
|
||||
summary = when (colorScheme) {
|
||||
ColorScheme.Default -> stringResource(R.string.preference_colors_default)
|
||||
ColorScheme.BlackAndWhite -> stringResource(R.string.preference_colors_bw)
|
||||
ColorScheme.Custom -> stringResource(R.string.preference_colors_custom)
|
||||
else -> null
|
||||
},
|
||||
onClick = {
|
||||
navController?.navigate("settings/appearance/colorscheme")
|
||||
}
|
||||
)
|
||||
Preference(
|
||||
title = stringResource(id = R.string.preference_screen_colors),
|
||||
summary = when (colorScheme) {
|
||||
ColorScheme.Default -> stringResource(R.string.preference_colors_default)
|
||||
ColorScheme.BlackAndWhite -> stringResource(R.string.preference_colors_bw)
|
||||
ColorScheme.Custom -> stringResource(R.string.preference_colors_custom)
|
||||
else -> null
|
||||
},
|
||||
summary = themeName,
|
||||
onClick = {
|
||||
navController?.navigate("settings/appearance/themes")
|
||||
}
|
||||
|
||||
@ -4,24 +4,27 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Font
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import java.util.UUID
|
||||
|
||||
class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
private val iconService: IconService by inject()
|
||||
private val themeRepository: ThemeRepository by inject()
|
||||
|
||||
val theme = dataStore.data.map { it.appearance.theme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setTheme(theme: Theme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -32,20 +35,22 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val colorScheme = dataStore.data.map { it.appearance.colorScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setColorScheme(colorScheme: ColorScheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(it.appearance.toBuilder().setColorScheme(colorScheme))
|
||||
.build()
|
||||
}
|
||||
val colorSchemeName = dataStore.data.map {
|
||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
||||
UUID.fromString(it)
|
||||
}
|
||||
}
|
||||
.flatMapLatest {
|
||||
themeRepository.getThemeOrDefault(it)
|
||||
}.map {
|
||||
it.name
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
|
||||
val font = dataStore.data.map { it.appearance.font }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setFont(font: Font) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -1,122 +0,0 @@
|
||||
package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.RadioButtonChecked
|
||||
import androidx.compose.material.icons.rounded.RadioButtonUnchecked
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import de.mm20.launcher2.ui.BuildConfig
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||
import de.mm20.launcher2.ui.theme.colorSchemeAsState
|
||||
|
||||
@Composable
|
||||
fun ColorSchemeSettingsScreen() {
|
||||
val viewModel: ColorSchemeSettingsScreenVM = viewModel()
|
||||
val navController = LocalNavController.current
|
||||
|
||||
PreferenceScreen(title = stringResource(R.string.preference_screen_colors)) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val colorScheme by viewModel.colorScheme.collectAsState()
|
||||
|
||||
val items = mutableListOf(
|
||||
AppearanceSettings.ColorScheme.Default to stringResource(R.string.preference_colors_default),
|
||||
AppearanceSettings.ColorScheme.BlackAndWhite to stringResource(R.string.preference_colors_bw),
|
||||
AppearanceSettings.ColorScheme.Custom to stringResource(R.string.preference_colors_custom),
|
||||
)
|
||||
|
||||
if (BuildConfig.DEBUG && isAtLeastApiLevel(27)) {
|
||||
items.add(AppearanceSettings.ColorScheme.DebugMaterialYouCompat to "Material You Compat")
|
||||
}
|
||||
|
||||
for (cs in items) {
|
||||
val scheme by colorSchemeAsState(cs.first, LocalDarkTheme.current)
|
||||
Preference(
|
||||
title = cs.second,
|
||||
icon = if (colorScheme == cs.first) Icons.Rounded.RadioButtonChecked else Icons.Rounded.RadioButtonUnchecked,
|
||||
onClick = {
|
||||
viewModel.setColorScheme(cs.first)
|
||||
if (cs.first == AppearanceSettings.ColorScheme.Custom) {
|
||||
navController?.navigate("settings/appearance/colorscheme/custom")
|
||||
}
|
||||
},
|
||||
controls = {
|
||||
ColorSchemePreview(scheme)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ColorSchemePreview(colorScheme: ColorScheme) {
|
||||
MaterialTheme(colorScheme = colorScheme) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 12.dp)
|
||||
.width(72.dp)
|
||||
.height(36.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Surface(
|
||||
tonalElevation = 1.dp,
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
) {}
|
||||
Surface(
|
||||
tonalElevation = 1.dp,
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
) {}
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Surface(
|
||||
tonalElevation = 1.dp,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
) {}
|
||||
Surface(
|
||||
tonalElevation = 1.dp,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.size(16.dp)
|
||||
) {}
|
||||
Surface(
|
||||
tonalElevation = 1.dp,
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class ColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val theme = dataStore.data.map { it.appearance.theme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val colorScheme = dataStore.data.map { it.appearance.colorScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setColorScheme(colorScheme: AppearanceSettings.ColorScheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setColorScheme(colorScheme)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,148 +0,0 @@
|
||||
package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.CustomColors
|
||||
import de.mm20.launcher2.preferences.ktx.toSettingsColorsScheme
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import palettes.CorePalette
|
||||
import palettes.TonalPalette
|
||||
import scheme.Scheme
|
||||
|
||||
class CustomColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val advancedMode = dataStore.data.map { it.appearance.customColors.advancedMode }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setAdvancedMode(advancedMode: Boolean) {
|
||||
viewModelScope.launch {
|
||||
val lightScheme = dataStore.updateData {
|
||||
val customColors = it.appearance.customColors.toBuilder()
|
||||
.setAdvancedMode(advancedMode)
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setCustomColors(customColors)
|
||||
)
|
||||
.build()
|
||||
}.appearance.customColors.lightScheme
|
||||
|
||||
if (!advancedMode) {
|
||||
setBaseColors(CustomColors.BaseColors
|
||||
.newBuilder()
|
||||
.setAccent1(lightScheme.primary)
|
||||
.setAccent2(lightScheme.secondary)
|
||||
.setAccent3(lightScheme.tertiary)
|
||||
.setNeutral1(lightScheme.surface)
|
||||
.setNeutral2(lightScheme.surface)
|
||||
.setError(lightScheme.error)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun generateFromPrimaryColor() {
|
||||
viewModelScope.launch {
|
||||
val primary = dataStore.data.map { it.appearance.customColors.baseColors.accent1 }.first()
|
||||
val scheme = Scheme.light(primary)
|
||||
setBaseColors(
|
||||
CustomColors.BaseColors.newBuilder()
|
||||
.setAccent1(scheme.primary)
|
||||
.setAccent2(scheme.secondary)
|
||||
.setAccent3(scheme.tertiary)
|
||||
.setNeutral1(scheme.surface)
|
||||
.setNeutral2(scheme.outline)
|
||||
.setError(scheme.error)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val baseColors = dataStore.data.map { it.appearance.customColors.baseColors }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setBaseColors(baseColors: CustomColors.BaseColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setCustomColors(
|
||||
it.appearance.customColors.toBuilder()
|
||||
.setBaseColors(baseColors)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
setDarkScheme(baseColorsToDarkScheme(baseColors))
|
||||
setLightScheme(baseColorsToLightScheme(baseColors))
|
||||
}
|
||||
}
|
||||
|
||||
val darkScheme = dataStore.data.map { it.appearance.customColors.darkScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setDarkScheme(darkScheme: CustomColors.Scheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setCustomColors(
|
||||
it.appearance.customColors.toBuilder()
|
||||
.setDarkScheme(darkScheme)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val lightScheme = dataStore.data.map { it.appearance.customColors.lightScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLightScheme(lightScheme: CustomColors.Scheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setCustomColors(
|
||||
it.appearance.customColors.toBuilder()
|
||||
.setLightScheme(lightScheme)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun baseColorsToDarkScheme(baseColors: CustomColors.BaseColors): CustomColors.Scheme {
|
||||
val a1 = TonalPalette.fromInt(baseColors.accent1)
|
||||
val a2 = TonalPalette.fromInt(baseColors.accent2)
|
||||
val a3 = TonalPalette.fromInt(baseColors.accent3)
|
||||
val n1 = TonalPalette.fromInt(baseColors.neutral1)
|
||||
val n2 = TonalPalette.fromInt(baseColors.neutral2)
|
||||
val error = TonalPalette.fromInt(baseColors.error)
|
||||
|
||||
val scheme = Scheme.darkFromCorePalette(CorePalette(a1, a2, a3, n1, n2, error))
|
||||
return scheme.toSettingsColorsScheme()
|
||||
}
|
||||
|
||||
private fun baseColorsToLightScheme(baseColors: CustomColors.BaseColors): CustomColors.Scheme {
|
||||
val a1 = TonalPalette.fromInt(baseColors.accent1)
|
||||
val a2 = TonalPalette.fromInt(baseColors.accent2)
|
||||
val a3 = TonalPalette.fromInt(baseColors.accent3)
|
||||
val n1 = TonalPalette.fromInt(baseColors.neutral1)
|
||||
val n2 = TonalPalette.fromInt(baseColors.neutral2)
|
||||
val error = TonalPalette.fromInt(baseColors.error)
|
||||
|
||||
val scheme = Scheme.lightFromCorePalette(CorePalette(a1, a2, a3, n1, n2, error))
|
||||
return scheme.toSettingsColorsScheme()
|
||||
}
|
||||
}
|
||||
@ -77,6 +77,9 @@ fun ThemesSettingsScreen() {
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
viewModel.selectTheme(theme)
|
||||
}
|
||||
)
|
||||
Row(
|
||||
|
||||
@ -2,20 +2,31 @@ package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.protobuf.ByteString
|
||||
import de.mm20.launcher2.ktx.toBytes
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.themes.DefaultThemeId
|
||||
import de.mm20.launcher2.themes.Theme
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import java.util.UUID
|
||||
|
||||
class ThemesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
class ThemesSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val themeRepository: ThemeRepository by inject()
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val selectedTheme: Flow<UUID?> = flowOf(DefaultThemeId)
|
||||
val selectedTheme: Flow<UUID?> = dataStore.data.map {
|
||||
it.appearance.themeId?.takeIf { it.isNotEmpty() }?.let {
|
||||
UUID.fromString(it)
|
||||
} ?: DefaultThemeId
|
||||
}
|
||||
val themes: Flow<List<Theme>> = themeRepository.getThemes()
|
||||
|
||||
fun getTheme(id: UUID): Flow<Theme?> {
|
||||
@ -23,7 +34,19 @@ class ThemesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun updateTheme(theme: Theme) {
|
||||
Log.d("MM20", "updateTheme: $theme")
|
||||
themeRepository.updateTheme(theme)
|
||||
}
|
||||
|
||||
fun selectTheme(theme: Theme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setAppearance(
|
||||
it.appearance.toBuilder()
|
||||
.setThemeId(theme.id.toString())
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,12 +18,15 @@ import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import de.mm20.launcher2.themes.DefaultThemeId
|
||||
import de.mm20.launcher2.themes.Theme
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.theme.colorscheme.*
|
||||
import de.mm20.launcher2.ui.theme.typography.DefaultTypography
|
||||
import de.mm20.launcher2.ui.theme.typography.getDeviceDefaultTypography
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koin.androidx.compose.inject
|
||||
import java.util.UUID
|
||||
|
||||
|
||||
@Composable
|
||||
@ -33,15 +36,17 @@ fun LauncherTheme(
|
||||
|
||||
val context = LocalContext.current
|
||||
val dataStore: LauncherDataStore by inject()
|
||||
val themeRepository: ThemeRepository by inject()
|
||||
|
||||
val colorSchemePreference by remember {
|
||||
val theme by remember {
|
||||
dataStore.data.map {
|
||||
if (it.easterEgg) Settings.AppearanceSettings.ColorScheme.EasterEgg
|
||||
else it.appearance.colorScheme
|
||||
it.appearance.themeId.takeIf { it.isNotEmpty() }?.let {
|
||||
UUID.fromString(it)
|
||||
}
|
||||
}.flatMapLatest {
|
||||
themeRepository.getThemeOrDefault(it)
|
||||
}
|
||||
}.collectAsState(
|
||||
AppearanceSettings.ColorScheme.Default
|
||||
)
|
||||
}.collectAsState(themeRepository.getDefaultTheme())
|
||||
|
||||
val themePreference by remember { dataStore.data.map { it.appearance.theme } }.collectAsState(
|
||||
AppearanceSettings.Theme.System
|
||||
@ -62,7 +67,11 @@ fun LauncherTheme(
|
||||
}
|
||||
}.collectAsState(RoundedCornerShape(0f))
|
||||
|
||||
val colorScheme by colorSchemeAsState(colorSchemePreference, darkTheme)
|
||||
val colorScheme = if (darkTheme) {
|
||||
darkColorSchemeOf(theme)
|
||||
} else {
|
||||
lightColorSchemeOf(theme)
|
||||
}
|
||||
|
||||
val font by remember { dataStore.data.map { it.appearance.font } }.collectAsState(
|
||||
AppearanceSettings.Font.Outfit
|
||||
@ -90,54 +99,6 @@ fun LauncherTheme(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun colorSchemeAsState(
|
||||
colorScheme: AppearanceSettings.ColorScheme,
|
||||
darkTheme: Boolean
|
||||
): MutableState<ColorScheme> {
|
||||
val dataStore: LauncherDataStore by inject()
|
||||
|
||||
when (colorScheme) {
|
||||
AppearanceSettings.ColorScheme.BlackAndWhite -> {
|
||||
return remember(darkTheme) {
|
||||
mutableStateOf(
|
||||
if (darkTheme) DarkBlackAndWhiteColorScheme else LightBlackAndWhiteColorScheme
|
||||
)
|
||||
}
|
||||
}
|
||||
AppearanceSettings.ColorScheme.EasterEgg -> {
|
||||
return remember(darkTheme) {
|
||||
mutableStateOf(
|
||||
if (darkTheme) DarkEasterEggColorScheme else LightEasterEggColorScheme
|
||||
)
|
||||
}
|
||||
}
|
||||
AppearanceSettings.ColorScheme.Custom -> {
|
||||
val colors by remember(darkTheme) {
|
||||
dataStore.data.map { if (darkTheme) it.appearance.customColors.darkScheme else it.appearance.customColors.lightScheme }
|
||||
}.collectAsState(null)
|
||||
val state = remember(colors, darkTheme) {
|
||||
mutableStateOf(
|
||||
colors?.let { CustomColorScheme(it) }
|
||||
?: if (darkTheme) DarkDefaultColorScheme else LightDefaultColorScheme
|
||||
)
|
||||
}
|
||||
return state
|
||||
}
|
||||
else -> {
|
||||
val scheme = if (darkTheme) {
|
||||
darkColorSchemeOf(Theme(DefaultThemeId, name = ""))
|
||||
} else {
|
||||
lightColorSchemeOf(Theme(DefaultThemeId, name = ""))
|
||||
}
|
||||
return remember(scheme, darkTheme) {
|
||||
mutableStateOf(scheme)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun getTypography(context: Context, font: AppearanceSettings.Font?): Typography {
|
||||
return when (font) {
|
||||
AppearanceSettings.Font.SystemDefault -> getDeviceDefaultTypography(context)
|
||||
|
||||
@ -22,7 +22,7 @@ internal val Context.dataStore: LauncherDataStore by dataStore(
|
||||
}
|
||||
)
|
||||
|
||||
internal const val SchemaVersion = 16
|
||||
internal const val SchemaVersion = 17
|
||||
|
||||
internal fun getMigrations(context: Context): List<DataMigration<Settings>> {
|
||||
return listOf(
|
||||
@ -42,5 +42,6 @@ internal fun getMigrations(context: Context): List<DataMigration<Settings>> {
|
||||
Migration_13_14(),
|
||||
Migration_14_15(),
|
||||
Migration_15_16(),
|
||||
Migration_16_17(),
|
||||
)
|
||||
}
|
||||
@ -5,6 +5,7 @@ import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
|
||||
import de.mm20.launcher2.preferences.ktx.toSettingsColorsScheme
|
||||
import scheme.Scheme
|
||||
import java.util.UUID
|
||||
|
||||
fun createFactorySettings(context: Context): Settings {
|
||||
return Settings.newBuilder()
|
||||
@ -12,16 +13,9 @@ fun createFactorySettings(context: Context): Settings {
|
||||
Settings.AppearanceSettings
|
||||
.newBuilder()
|
||||
.setTheme(Settings.AppearanceSettings.Theme.System)
|
||||
.setColorScheme(Settings.AppearanceSettings.ColorScheme.Default)
|
||||
.setDimWallpaper(false)
|
||||
.setBlurWallpaper(true)
|
||||
.setCustomColors(
|
||||
Settings.AppearanceSettings.CustomColors.newBuilder()
|
||||
.setAdvancedMode(false)
|
||||
.setBaseColors(DefaultCustomColorsBase)
|
||||
.setLightScheme(DefaultLightCustomColorScheme)
|
||||
.setDarkScheme(DefaultDarkCustomColorScheme)
|
||||
)
|
||||
.setThemeId(UUID(0L, 0L).toString())
|
||||
.setFont(Settings.AppearanceSettings.Font.Outfit)
|
||||
.build()
|
||||
)
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package de.mm20.launcher2.preferences.migrations
|
||||
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import java.util.UUID
|
||||
|
||||
class Migration_16_17: VersionedMigration(16, 17) {
|
||||
override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder {
|
||||
return builder.setAppearance(
|
||||
builder.appearance.toBuilder()
|
||||
.setThemeId(
|
||||
when(builder.appearance.colorScheme) {
|
||||
Settings.AppearanceSettings.ColorScheme.BlackAndWhite -> UUID(0L, 1L)
|
||||
Settings.AppearanceSettings.ColorScheme.Custom -> UUID(1L, 1L)
|
||||
else -> UUID(0L, 0L)
|
||||
}.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ message Settings {
|
||||
Custom = 3;
|
||||
EasterEgg = 4;
|
||||
}
|
||||
ColorScheme color_scheme = 6;
|
||||
ColorScheme color_scheme = 6 [deprecated = true];
|
||||
message CustomColors {
|
||||
bool advanced_mode = 1;
|
||||
message BaseColors {
|
||||
@ -72,7 +72,7 @@ message Settings {
|
||||
Scheme light_scheme = 3;
|
||||
Scheme dark_scheme = 4;
|
||||
}
|
||||
CustomColors custom_colors = 8;
|
||||
CustomColors custom_colors = 8 [deprecated = true];
|
||||
bool dim_wallpaper = 7;
|
||||
|
||||
/**
|
||||
@ -87,6 +87,8 @@ message Settings {
|
||||
Font font = 10;
|
||||
|
||||
bool blur_wallpaper = 11;
|
||||
// UUID of the selected theme
|
||||
string theme_id = 12;
|
||||
}
|
||||
AppearanceSettings appearance = 2;
|
||||
|
||||
|
||||
@ -44,7 +44,8 @@ class ThemeRepository(
|
||||
}
|
||||
}
|
||||
|
||||
fun getThemeOrDefault(id: UUID): Flow<Theme> {
|
||||
fun getThemeOrDefault(id: UUID?): Flow<Theme> {
|
||||
if (id == null) return flowOf(getDefaultTheme())
|
||||
return getTheme(id).map { it ?: getDefaultTheme() }
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user