diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 97b16574..c17c9056 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -387,6 +387,18 @@ Color scheme Default Black and White + Custom + Primary + Secondary + Tertiary + Neutral + Neutral Variant + Error + Advanced mode + Simple mode + Generate from primary color + Light color scheme + Dark color scheme About Version Links diff --git a/preferences/build.gradle.kts b/preferences/build.gradle.kts index 957b4f8b..ae306e77 100644 --- a/preferences/build.gradle.kts +++ b/preferences/build.gradle.kts @@ -67,5 +67,6 @@ dependencies { implementation(project(":i18n")) implementation(project(":base")) implementation(project(":crashreporter")) + implementation(project(":material-color-utilities")) } \ No newline at end of file diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt index 2a5d7bee..ec65bbb6 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/DataStore.kt @@ -20,6 +20,7 @@ internal val Context.dataStore: LauncherDataStore by dataStore( Migration_2_3(), Migration_3_4(), Migration_4_5(), + Migration_5_6(), ) }, corruptionHandler = ReplaceFileCorruptionHandler { @@ -29,4 +30,4 @@ internal val Context.dataStore: LauncherDataStore by dataStore( } ) -internal const val SchemaVersion = 5 \ No newline at end of file +internal const val SchemaVersion = 6 \ No newline at end of file diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt index fc1f6eb8..05fbb045 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt @@ -1,6 +1,7 @@ package de.mm20.launcher2.preferences import android.content.Context +import scheme.Scheme fun createFactorySettings(context: Context): Settings { return Settings.newBuilder() @@ -10,6 +11,12 @@ fun createFactorySettings(context: Context): Settings { .setTheme(Settings.AppearanceSettings.Theme.System) .setColorScheme(Settings.AppearanceSettings.ColorScheme.Default) .setDimWallpaper(false) + .setCustomColors(Settings.AppearanceSettings.CustomColors.newBuilder() + .setAdvancedMode(false) + .setBaseColors(DefaultCustomColorsBase) + .setLightScheme(DefaultLightCustomColorScheme) + .setDarkScheme(DefaultDarkCustomColorScheme) + ) .build() ) .setWeather( @@ -70,7 +77,7 @@ fun createFactorySettings(context: Context): Settings { Settings.AppShortcutSearchSettings .newBuilder() .setEnabled(true) - ) + ) .setCalculatorSearch( Settings.CalculatorSearchSettings .newBuilder() @@ -140,4 +147,83 @@ fun createFactorySettings(context: Context): Settings { .setOpacity(1f) ) .build() -} \ No newline at end of file +} + +internal val DefaultCustomColorsBase: Settings.AppearanceSettings.CustomColors.BaseColors +get() { + val scheme = Scheme.light(0xFFACE330.toInt()) + return Settings.AppearanceSettings.CustomColors.BaseColors.newBuilder() + .setAccent1(scheme.primary) + .setAccent2(scheme.secondary) + .setAccent3(scheme.tertiary) + .setNeutral1(scheme.surface) + .setNeutral2(scheme.surfaceVariant) + .setError(scheme.error) + .build() +} + +internal val DefaultLightCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme + get() { + val scheme = Scheme.light(0xFFACE330.toInt()) + return Settings.AppearanceSettings.CustomColors.Scheme.newBuilder() + .setPrimary(scheme.primary) + .setOnPrimary(scheme.onPrimary) + .setPrimaryContainer(scheme.primaryContainer) + .setOnPrimaryContainer(scheme.onPrimaryContainer) + .setSecondary(scheme.secondary) + .setOnSecondary(scheme.onSecondary) + .setSecondaryContainer(scheme.secondaryContainer) + .setOnSecondaryContainer(scheme.onSecondaryContainer) + .setTertiary(scheme.tertiary) + .setOnTertiary(scheme.onTertiary) + .setTertiaryContainer(scheme.tertiaryContainer) + .setOnTertiaryContainer(scheme.onTertiaryContainer) + .setBackground(scheme.background) + .setOnBackground(scheme.onBackground) + .setSurface(scheme.surface) + .setOnSurface(scheme.onSurface) + .setSurfaceVariant(scheme.surfaceVariant) + .setOnSurfaceVariant(scheme.onSurfaceVariant) + .setError(scheme.error) + .setOnError(scheme.onError) + .setErrorContainer(scheme.errorContainer) + .setOnErrorContainer(scheme.onErrorContainer) + .setInverseSurface(scheme.inverseSurface) + .setInverseOnSurface(scheme.inverseOnSurface) + .setInversePrimary(scheme.inversePrimary) + .setOutline(scheme.outline) + .build() + } + +internal val DefaultDarkCustomColorScheme: Settings.AppearanceSettings.CustomColors.Scheme + get() { + val scheme = Scheme.dark(0xFFACE330.toInt()) + return Settings.AppearanceSettings.CustomColors.Scheme.newBuilder() + .setPrimary(scheme.primary) + .setOnPrimary(scheme.onPrimary) + .setPrimaryContainer(scheme.primaryContainer) + .setOnPrimaryContainer(scheme.onPrimaryContainer) + .setSecondary(scheme.secondary) + .setOnSecondary(scheme.onSecondary) + .setSecondaryContainer(scheme.secondaryContainer) + .setOnSecondaryContainer(scheme.onSecondaryContainer) + .setTertiary(scheme.tertiary) + .setOnTertiary(scheme.onTertiary) + .setTertiaryContainer(scheme.tertiaryContainer) + .setOnTertiaryContainer(scheme.onTertiaryContainer) + .setBackground(scheme.background) + .setOnBackground(scheme.onBackground) + .setSurface(scheme.surface) + .setOnSurface(scheme.onSurface) + .setSurfaceVariant(scheme.surfaceVariant) + .setOnSurfaceVariant(scheme.onSurfaceVariant) + .setError(scheme.error) + .setOnError(scheme.onError) + .setErrorContainer(scheme.errorContainer) + .setOnErrorContainer(scheme.onErrorContainer) + .setInverseSurface(scheme.inverseSurface) + .setInverseOnSurface(scheme.inverseOnSurface) + .setInversePrimary(scheme.inversePrimary) + .setOutline(scheme.outline) + .build() + } \ No newline at end of file diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_5_6.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_5_6.kt new file mode 100644 index 00000000..5d73cd05 --- /dev/null +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_5_6.kt @@ -0,0 +1,20 @@ +package de.mm20.launcher2.preferences.migrations + +import de.mm20.launcher2.preferences.DefaultCustomColorsBase +import de.mm20.launcher2.preferences.DefaultDarkCustomColorScheme +import de.mm20.launcher2.preferences.DefaultLightCustomColorScheme +import de.mm20.launcher2.preferences.Settings + +class Migration_5_6: VersionedMigration(5, 6) { + override suspend fun applyMigrations(builder: Settings.Builder): Settings.Builder { + return builder.setAppearance( + builder.appearance.toBuilder() + .setCustomColors(Settings.AppearanceSettings.CustomColors.newBuilder() + .setAdvancedMode(false) + .setBaseColors(DefaultCustomColorsBase) + .setLightScheme(DefaultLightCustomColorScheme) + .setDarkScheme(DefaultDarkCustomColorScheme) + ) + ) + } +} \ No newline at end of file diff --git a/preferences/src/main/proto/settings.proto b/preferences/src/main/proto/settings.proto index 0fde3f60..f7240e02 100644 --- a/preferences/src/main/proto/settings.proto +++ b/preferences/src/main/proto/settings.proto @@ -16,8 +16,52 @@ message Settings { Default = 0; BlackAndWhite = 1; DebugMaterialYouCompat = 2; + Custom = 3; } ColorScheme color_scheme = 6; + message CustomColors { + bool advanced_mode = 1; + message BaseColors { + uint32 accent1 = 1; + uint32 accent2 = 2; + uint32 accent3 = 3; + uint32 neutral1 = 4; + uint32 neutral2 = 5; + uint32 error = 6; + } + BaseColors base_colors = 2; + message Scheme { + uint32 primary = 1; + uint32 on_primary = 2; + uint32 primary_container = 3; + uint32 on_primary_container = 4; + uint32 secondary = 5; + uint32 on_secondary = 6; + uint32 secondary_container = 7; + uint32 on_secondary_container = 8; + uint32 tertiary = 9; + uint32 on_tertiary = 10; + uint32 tertiary_container = 11; + uint32 on_tertiary_container = 12; + uint32 background = 13; + uint32 on_background = 14; + uint32 surface = 15; + uint32 on_surface = 16; + uint32 surface_variant = 17; + uint32 on_surface_variant = 18; + uint32 outline = 19; + uint32 inverse_surface = 20; + uint32 inverse_on_surface = 21; + uint32 inverse_primary = 22; + uint32 error = 23; + uint32 on_error = 24; + uint32 error_container = 25; + uint32 on_error_container = 26; + } + Scheme light_scheme = 3; + Scheme dark_scheme = 4; + } + CustomColors custom_colors = 8; bool dim_wallpaper = 7; } AppearanceSettings appearance = 2; diff --git a/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/ColorPreference.kt b/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/ColorPreference.kt new file mode 100644 index 00000000..d20db0de --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/ColorPreference.kt @@ -0,0 +1,95 @@ +package de.mm20.launcher2.ui.component.preferences + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.godaddy.android.colorpicker.ClassicColorPicker +import de.mm20.launcher2.ui.ktx.toHexString + +@Composable +fun ColorPreference( + title: String, + summary: String? = null, + value: Color?, + onValueChanged: (Color?) -> Unit = {} +) { + var showDialog by remember { mutableStateOf(false) } + Preference( + title = title, + summary = summary, + controls = { + value?.let { + Surface( + color = it, + shape = CircleShape, + modifier = Modifier + .padding(vertical = 12.dp) + .size(36.dp) + ) {} + } + }, + onClick = { + showDialog = true + } + ) + if (showDialog) { + var color by remember(value) { mutableStateOf(value) } + AlertDialog( + onDismissRequest = { showDialog = false }, + title = { + Text( + text = title, + style = MaterialTheme.typography.titleLarge + ) + }, + text = { + Column( + modifier = Modifier.fillMaxWidth() + ) { + + ClassicColorPicker( + color = value ?: Color.Black, + onColorChanged = { + color = it.toColor() + }, + showAlphaBar = false, + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + ) + + var hexValue by remember(color) { + mutableStateOf( + color?.toHexString() ?: "#000000" + ) + } + + TextField( + modifier = Modifier.padding(top = 16.dp), + value = hexValue, + onValueChange = { + hexValue = it + if (Regex("#[0-9a-fA-F]{6}").matches(it)) { + val hex = it.substring(1).toIntOrNull(16) ?: return@TextField + color = Color(hex).copy(alpha = 1f) + } + } + ) + } + }, + confirmButton = { + TextButton(onClick = { + onValueChanged(color) + showDialog = false + }) { + Text(stringResource(android.R.string.ok)) + } + } + ) + } +} \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt index 08866267..2c824331 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt @@ -28,6 +28,7 @@ import de.mm20.launcher2.ui.settings.calendarwidget.CalendarWidgetSettingsScreen 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.crashreporter.CrashReportScreen import de.mm20.launcher2.ui.settings.crashreporter.CrashReporterScreen import de.mm20.launcher2.ui.settings.debug.DebugSettingsScreen @@ -88,6 +89,9 @@ class SettingsActivity : BaseActivity() { composable("settings/appearance/colorscheme") { ColorSchemeSettingsScreen() } + composable("settings/appearance/colorscheme/custom") { + CustomColorSchemeSettingsScreen() + } composable("settings/appearance/cards") { CardsSettingsScreen() } diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt index 7a6b160a..89c03d70 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt @@ -71,6 +71,7 @@ fun AppearanceSettingsScreen() { 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 = { diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt index 7a01c823..57afdbde 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt @@ -22,11 +22,13 @@ 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.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 { @@ -36,6 +38,7 @@ fun ColorSchemeSettingsScreen() { 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)) { @@ -47,7 +50,12 @@ fun ColorSchemeSettingsScreen() { Preference( title = cs.second, icon = if (colorScheme == cs.first) Icons.Rounded.RadioButtonChecked else Icons.Rounded.RadioButtonUnchecked, - onClick = { viewModel.setColorScheme(cs.first) }, + onClick = { + viewModel.setColorScheme(cs.first) + if (cs.first == AppearanceSettings.ColorScheme.Custom) { + navController?.navigate("settings/appearance/colorscheme/custom") + } + }, controls = { ColorSchemePreview(scheme) } diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreen.kt new file mode 100644 index 00000000..2e6e26dd --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreen.kt @@ -0,0 +1,852 @@ +package de.mm20.launcher2.ui.settings.colorscheme + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.MoreVert +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.viewmodel.compose.viewModel +import de.mm20.launcher2.ui.R +import de.mm20.launcher2.ui.component.preferences.ColorPreference +import de.mm20.launcher2.ui.component.preferences.PreferenceCategory +import de.mm20.launcher2.ui.component.preferences.PreferenceScreen + +@Composable +fun CustomColorSchemeSettingsScreen() { + val viewModel: CustomColorSchemeSettingsScreenVM = viewModel() + + val advancedMode by viewModel.advancedMode.observeAsState() + + PreferenceScreen( + title = stringResource(R.string.preference_screen_colors), + topBarActions = { + var showOverflowMenu by remember { mutableStateOf(false) } + IconButton(onClick = { showOverflowMenu = true }) { + Icon(imageVector = Icons.Rounded.MoreVert, contentDescription = null) + } + DropdownMenu( + expanded = showOverflowMenu, + onDismissRequest = { showOverflowMenu = false }) { + if (advancedMode == false) { + DropdownMenuItem( + text = { Text("Generate from primary color") }, + onClick = { + viewModel.generateFromPrimaryColor() + showOverflowMenu = false + } + ) + } + DropdownMenuItem( + text = { + Text( + stringResource( + if (advancedMode == true) { + R.string.preference_custom_colors_simple_mode + } else { + R.string.preference_custom_colors_advanced_mode + } + ) + + ) + }, + onClick = { + viewModel.setAdvancedMode(advancedMode?.not() ?: true) + showOverflowMenu = false + } + ) + } + } + ) { + if (advancedMode == false) { + item { + PreferenceCategory { + val baseColors by viewModel.baseColors.observeAsState() + ColorPreference( + title = stringResource(R.string.preference_custom_colors_a1), + value = baseColors?.let { Color(it.accent1) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = baseColors ?: return@ColorPreference + viewModel.setBaseColors( + colors.toBuilder() + .setAccent1(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = stringResource(R.string.preference_custom_colors_a2), + value = baseColors?.let { Color(it.accent2) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = baseColors ?: return@ColorPreference + viewModel.setBaseColors( + colors.toBuilder() + .setAccent2(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = stringResource(R.string.preference_custom_colors_a3), + value = baseColors?.let { Color(it.accent3) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = baseColors ?: return@ColorPreference + viewModel.setBaseColors( + colors.toBuilder() + .setAccent3(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = stringResource(R.string.preference_custom_colors_n1), + value = baseColors?.let { Color(it.neutral1) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = baseColors ?: return@ColorPreference + viewModel.setBaseColors( + colors.toBuilder() + .setNeutral1(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = stringResource(R.string.preference_custom_colors_n2), + value = baseColors?.let { Color(it.neutral2) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = baseColors ?: return@ColorPreference + viewModel.setBaseColors( + colors.toBuilder() + .setNeutral2(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = stringResource(R.string.preference_custom_colors_error), + value = baseColors?.let { Color(it.error) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = baseColors ?: return@ColorPreference + viewModel.setBaseColors( + colors.toBuilder() + .setError(it.toArgb()) + .build() + ) + } + ) + } + } + } + if (advancedMode == true) { + item { + PreferenceCategory(stringResource(R.string.preference_category_custom_colors_light)) { + val lightScheme by viewModel.lightScheme.observeAsState() + ColorPreference( + title = "Primary", + value = lightScheme?.let { Color(it.primary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setPrimary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Primary", + value = lightScheme?.let { Color(it.onPrimary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnPrimary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Primary Container", + value = lightScheme?.let { Color(it.primaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setPrimaryContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Primary Container", + value = lightScheme?.let { Color(it.onPrimaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnPrimaryContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Secondary", + value = lightScheme?.let { Color(it.secondary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setSecondary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Secondary", + value = lightScheme?.let { Color(it.onSecondary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnSecondary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Secondary Container", + value = lightScheme?.let { Color(it.secondaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setSecondaryContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Secondary Container", + value = lightScheme?.let { Color(it.onSecondaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnSecondaryContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Tertiary", + value = lightScheme?.let { Color(it.tertiary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setTertiary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Tertiary", + value = lightScheme?.let { Color(it.onTertiary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnTertiary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Tertiary Container", + value = lightScheme?.let { Color(it.tertiaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setTertiaryContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Tertiary Container", + value = lightScheme?.let { Color(it.onTertiaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnTertiaryContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Background", + value = lightScheme?.let { Color(it.background) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setBackground(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Background", + value = lightScheme?.let { Color(it.onBackground) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnBackground(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Surface", + value = lightScheme?.let { Color(it.surface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setSurface(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Surface", + value = lightScheme?.let { Color(it.onSurface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnSurface(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Surface Variant", + value = lightScheme?.let { Color(it.surfaceVariant) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setSurfaceVariant(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Surface Variant", + value = lightScheme?.let { Color(it.onSurfaceVariant) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnSurfaceVariant(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Error", + value = lightScheme?.let { Color(it.error) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setError(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Error", + value = lightScheme?.let { Color(it.onError) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnError(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Error Container", + value = lightScheme?.let { Color(it.errorContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setErrorContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Error Container", + value = lightScheme?.let { Color(it.onErrorContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOnErrorContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Inverse Primary", + value = lightScheme?.let { Color(it.inversePrimary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setInversePrimary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Inverse Surface", + value = lightScheme?.let { Color(it.inverseSurface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setInverseSurface(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Inverse On Surface", + value = lightScheme?.let { Color(it.inverseOnSurface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setInverseOnSurface(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Outline", + value = lightScheme?.let { Color(it.outline) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = lightScheme ?: return@ColorPreference + viewModel.setLightScheme( + colors.toBuilder() + .setOutline(it.toArgb()) + .build() + ) + } + ) + } + + PreferenceCategory(stringResource(R.string.preference_category_custom_colors_light)) { + val darkScheme by viewModel.darkScheme.observeAsState() + ColorPreference( + title = "Primary", + value = darkScheme?.let { Color(it.primary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setPrimary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Primary", + value = darkScheme?.let { Color(it.onPrimary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnPrimary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Primary Container", + value = darkScheme?.let { Color(it.primaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setPrimaryContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Primary Container", + value = darkScheme?.let { Color(it.onPrimaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnPrimaryContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Secondary", + value = darkScheme?.let { Color(it.secondary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setSecondary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Secondary", + value = darkScheme?.let { Color(it.onSecondary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnSecondary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Secondary Container", + value = darkScheme?.let { Color(it.secondaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setSecondaryContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Secondary Container", + value = darkScheme?.let { Color(it.onSecondaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnSecondaryContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Tertiary", + value = darkScheme?.let { Color(it.tertiary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setTertiary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Tertiary", + value = darkScheme?.let { Color(it.onTertiary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnTertiary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Tertiary Container", + value = darkScheme?.let { Color(it.tertiaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setTertiaryContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Tertiary Container", + value = darkScheme?.let { Color(it.onTertiaryContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnTertiaryContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Background", + value = darkScheme?.let { Color(it.background) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setBackground(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Background", + value = darkScheme?.let { Color(it.onBackground) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnBackground(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Surface", + value = darkScheme?.let { Color(it.surface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setSurface(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Surface", + value = darkScheme?.let { Color(it.onSurface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnSurface(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Surface Variant", + value = darkScheme?.let { Color(it.surfaceVariant) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setSurfaceVariant(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Surface Variant", + value = darkScheme?.let { Color(it.onSurfaceVariant) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnSurfaceVariant(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Error", + value = darkScheme?.let { Color(it.error) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setError(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Error", + value = darkScheme?.let { Color(it.onError) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnError(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Error Container", + value = darkScheme?.let { Color(it.errorContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setErrorContainer(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "On Error Container", + value = darkScheme?.let { Color(it.onErrorContainer) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOnErrorContainer(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Inverse Primary", + value = darkScheme?.let { Color(it.inversePrimary) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setInversePrimary(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Inverse Surface", + value = darkScheme?.let { Color(it.inverseSurface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setInverseSurface(it.toArgb()) + .build() + ) + } + ) + ColorPreference( + title = "Inverse On Surface", + value = darkScheme?.let { Color(it.inverseOnSurface) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setInverseOnSurface(it.toArgb()) + .build() + ) + } + ) + + ColorPreference( + title = "Outline", + value = darkScheme?.let { Color(it.outline) }, + onValueChanged = { + if (it == null) return@ColorPreference + val colors = darkScheme ?: return@ColorPreference + viewModel.setDarkScheme( + colors.toBuilder() + .setOutline(it.toArgb()) + .build() + ) + } + ) + } + } + } + } +} \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreenVM.kt new file mode 100644 index 00000000..8a984669 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreenVM.kt @@ -0,0 +1,194 @@ +package de.mm20.launcher2.ui.settings.colorscheme + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope +import de.mm20.launcher2.preferences.LauncherDataStore +import de.mm20.launcher2.preferences.Settings +import de.mm20.launcher2.preferences.Settings.AppearanceSettings.CustomColors +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +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 }.asLiveData() + 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.surfaceVariant) + .setError(scheme.error) + .build() + ) + } + } + + val baseColors = dataStore.data.map { it.appearance.customColors.baseColors }.asLiveData() + 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 }.asLiveData() + 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 }.asLiveData() + 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) + + return CustomColors.Scheme.newBuilder() + .setPrimary(a1.tone(80)) + .setOnPrimary(a1.tone(20)) + .setPrimaryContainer(a1.tone(30)) + .setOnPrimaryContainer(a1.tone(90)) + .setSecondary(a2.tone(80)) + .setOnSecondary(a2.tone(20)) + .setSecondaryContainer(a2.tone(30)) + .setOnSecondaryContainer(a2.tone(90)) + .setTertiary(a3.tone(80)) + .setOnTertiary(a3.tone(20)) + .setTertiaryContainer(a3.tone(30)) + .setOnTertiaryContainer(a3.tone(90)) + .setError(error.tone(80)) + .setOnError(error.tone(20)) + .setErrorContainer(error.tone(30)) + .setOnErrorContainer(error.tone(80)) + .setBackground(n1.tone(10)) + .setOnBackground(n1.tone(90)) + .setSurface(n1.tone(10)) + .setOnSurface(n1.tone(90)) + .setSurfaceVariant(n2.tone(30)) + .setOnSurfaceVariant(n2.tone(80)) + .setOutline(n2.tone(60)) + .setInverseSurface(n1.tone(90)) + .setInverseOnSurface(n1.tone(20)) + .setInversePrimary(a1.tone(40)) + .build() + } + + 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) + + return CustomColors.Scheme.newBuilder() + .setPrimary(a1.tone(40)) + .setOnPrimary(a1.tone(100)) + .setPrimaryContainer(a1.tone(90)) + .setOnPrimaryContainer(a1.tone(10)) + .setSecondary(a2.tone(40)) + .setOnSecondary(a2.tone(100)) + .setSecondaryContainer(a2.tone(90)) + .setOnSecondaryContainer(a2.tone(10)) + .setTertiary(a3.tone(40)) + .setOnTertiary(a3.tone(100)) + .setTertiaryContainer(a3.tone(90)) + .setOnTertiaryContainer(a3.tone(10)) + .setError(error.tone(40)) + .setOnError(error.tone(100)) + .setErrorContainer(error.tone(90)) + .setOnErrorContainer(error.tone(10)) + .setBackground(n1.tone(99)) + .setOnBackground(n1.tone(10)) + .setSurface(n1.tone(99)) + .setOnSurface(n1.tone(10)) + .setSurfaceVariant(n2.tone(90)) + .setOnSurfaceVariant(n2.tone(30)) + .setOutline(n2.tone(50)) + .setInverseSurface(n1.tone(20)) + .setInverseOnSurface(n1.tone(95)) + .setInversePrimary(a1.tone(80)) + .build() + } +} \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt b/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt index 43e79d02..a2d004dc 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt @@ -57,6 +57,18 @@ fun colorSchemeAsState(colorScheme: AppearanceSettings.ColorScheme): MutableStat ) } } + 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 -> { if (Build.VERSION.SDK_INT >= 27 && (Build.VERSION.SDK_INT < 31 || colorScheme == AppearanceSettings.ColorScheme.DebugMaterialYouCompat)) { val wallpaperColors by wallpaperColorsAsState() @@ -71,7 +83,9 @@ fun colorSchemeAsState(colorScheme: AppearanceSettings.ColorScheme): MutableStat if (Build.VERSION.SDK_INT >= 31) { return remember(darkTheme) { mutableStateOf( - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme( + context + ) ) } } diff --git a/ui/src/main/java/de/mm20/launcher2/ui/theme/colorscheme/Custom.kt b/ui/src/main/java/de/mm20/launcher2/ui/theme/colorscheme/Custom.kt new file mode 100644 index 00000000..c55f4e90 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/theme/colorscheme/Custom.kt @@ -0,0 +1,37 @@ +package de.mm20.launcher2.ui.theme.colorscheme + +import androidx.compose.material3.ColorScheme +import androidx.compose.ui.graphics.Color +import de.mm20.launcher2.preferences.Settings + +fun CustomColorScheme(colors: Settings.AppearanceSettings.CustomColors.Scheme) : ColorScheme { + return ColorScheme( + primary = Color(colors.primary), + onPrimary = Color(colors.onPrimary), + primaryContainer = Color(colors.primaryContainer), + onPrimaryContainer = Color(colors.onPrimaryContainer), + secondary = Color(colors.secondary), + onSecondary = Color(colors.onSecondary), + secondaryContainer = Color(colors.secondaryContainer), + onSecondaryContainer = Color(colors.onSecondaryContainer), + tertiary = Color(colors.tertiary), + onTertiary = Color(colors.onTertiary), + tertiaryContainer = Color(colors.tertiaryContainer), + onTertiaryContainer = Color(colors.onTertiaryContainer), + background = Color(colors.background), + onBackground = Color(colors.onBackground), + surface = Color(colors.surface), + onSurface = Color(colors.onSurface), + surfaceVariant = Color(colors.surfaceVariant), + onSurfaceVariant = Color(colors.onSurfaceVariant), + outline = Color(colors.outline), + inverseSurface = Color(colors.inverseSurface), + inverseOnSurface = Color(colors.inverseOnSurface), + inversePrimary = Color(colors.inversePrimary), + surfaceTint = Color(colors.primary), + error = Color(colors.error), + onError = Color(colors.onError), + errorContainer = Color(colors.errorContainer), + onErrorContainer = Color(colors.onErrorContainer), + ) +} \ No newline at end of file