Add wallpaper color scheme

This commit is contained in:
MM20
2022-04-12 18:28:08 +02:00
parent 408a23563e
commit 8bb3737460
25 changed files with 2414 additions and 88 deletions
+2
View File
@@ -104,6 +104,8 @@ dependencies {
implementation(libs.coil.core)
implementation(libs.coil.compose)
implementation(project(":material-color-utilities"))
implementation(project(":base"))
implementation(project(":i18n"))
implementation(project(":compat"))
@@ -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.Wallpaper -> stringResource(R.string.preference_colors_wallpaper)
else -> null
},
onClick = {
@@ -1,5 +1,6 @@
package de.mm20.launcher2.ui.settings.colorscheme
import android.os.Build
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.*
@@ -7,6 +8,7 @@ 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.getValue
@@ -17,44 +19,42 @@ import androidx.compose.ui.platform.LocalContext
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.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.theme.getColorScheme
import de.mm20.launcher2.ui.theme.colorSchemeAsState
@Composable
fun ColorSchemeSettingsScreen() {
val viewModel: ColorSchemeSettingsScreenVM = viewModel()
val context = LocalContext.current
PreferenceScreen(title = stringResource(R.string.preference_screen_colors)) {
item {
PreferenceCategory {
val theme by viewModel.theme.observeAsState()
val darkTheme =
theme == AppearanceSettings.Theme.Dark || theme == AppearanceSettings.Theme.System && isSystemInDarkTheme()
val colorScheme by viewModel.colorScheme.observeAsState()
val items = listOf(
val items = mutableListOf(
AppearanceSettings.ColorScheme.Default to R.string.preference_colors_default,
AppearanceSettings.ColorScheme.BlackAndWhite to R.string.preference_colors_bw
AppearanceSettings.ColorScheme.BlackAndWhite to R.string.preference_colors_bw,
)
if (isAtLeastApiLevel(Build.VERSION_CODES.O_MR1)) {
items.add(
AppearanceSettings.ColorScheme.Wallpaper to R.string.preference_colors_wallpaper
)
}
for (cs in items) {
val scheme by colorSchemeAsState(cs.first)
Preference(
title = stringResource(cs.second),
icon = if (colorScheme == cs.first) Icons.Rounded.RadioButtonChecked else Icons.Rounded.RadioButtonUnchecked,
onClick = { viewModel.setColorScheme(cs.first) },
controls = {
ColorSchemePreview(
getColorScheme(
LocalContext.current,
cs.first,
darkTheme,
)
)
ColorSchemePreview(scheme)
}
)
}
@@ -65,51 +65,54 @@ fun ColorSchemeSettingsScreen() {
@Composable
fun ColorSchemePreview(colorScheme: ColorScheme) {
Box(
modifier = Modifier
.padding(vertical = 12.dp)
.width(72.dp)
.height(36.dp),
contentAlignment = Alignment.Center
) {
Row(
verticalAlignment = Alignment.CenterVertically
MaterialTheme(colorScheme = colorScheme) {
Box(
modifier = Modifier
.padding(vertical = 12.dp)
.width(72.dp)
.height(36.dp),
contentAlignment = Alignment.Center
) {
Surface(
tonalElevation = 1.dp,
color = colorScheme.surface,
modifier = Modifier
.size(36.dp)
) {}
Surface(
tonalElevation = 1.dp,
color = colorScheme.surfaceVariant,
modifier = Modifier
.size(36.dp)
) {}
}
Row(
verticalAlignment = Alignment.CenterVertically
) {
Surface(
tonalElevation = 1.dp,
color = colorScheme.primary,
modifier = Modifier
.size(16.dp)
) {}
Surface(
tonalElevation = 1.dp,
color = colorScheme.secondary,
modifier = Modifier
.padding(horizontal = 8.dp)
.size(16.dp)
) {}
Surface(
tonalElevation = 1.dp,
color = colorScheme.tertiary,
modifier = Modifier
.size(16.dp)
) {}
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,24 +1,18 @@
package de.mm20.launcher2.ui.theme
import android.content.Context
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
import de.mm20.launcher2.ui.theme.colorscheme.DarkBlackAndWhiteColorScheme
import de.mm20.launcher2.ui.theme.colorscheme.DarkPre31DefaultColorScheme
import de.mm20.launcher2.ui.theme.colorscheme.LightBlackAndWhiteColorScheme
import de.mm20.launcher2.ui.theme.colorscheme.LightPre31DefaultColorScheme
import de.mm20.launcher2.ui.theme.colorscheme.*
import de.mm20.launcher2.ui.theme.typography.DefaultTypography
import kotlinx.coroutines.flow.map
import org.koin.androidx.compose.inject
@@ -34,34 +28,52 @@ fun LauncherTheme(
val colorSchemePreference by remember { dataStore.data.map { it.appearance.colorScheme } }.collectAsState(
AppearanceSettings.ColorScheme.Default
)
val themePreference by remember { dataStore.data.map { it.appearance.theme } }.collectAsState(
Theme.System
)
val darkTheme =
themePreference == Theme.Dark || themePreference == Theme.System && isSystemInDarkTheme()
val colorScheme by colorSchemeAsState(colorSchemePreference)
MaterialTheme(
colorScheme = getColorScheme(LocalContext.current, colorSchemePreference, darkTheme),
colorScheme = colorScheme,
typography = DefaultTypography,
content = content
)
}
fun getColorScheme(context: Context, colorScheme: AppearanceSettings.ColorScheme, darkTheme: Boolean): ColorScheme {
return when (colorScheme) {
AppearanceSettings.ColorScheme.BlackAndWhite -> {
if (darkTheme) DarkBlackAndWhiteColorScheme
else LightBlackAndWhiteColorScheme
}
else -> {
if (darkTheme) {
if (isAtLeastApiLevel(31)) dynamicDarkColorScheme(context)
else DarkPre31DefaultColorScheme
} else {
if (isAtLeastApiLevel(31)) dynamicLightColorScheme(context)
else LightPre31DefaultColorScheme
@Composable
fun colorSchemeAsState(colorScheme: AppearanceSettings.ColorScheme): MutableState<ColorScheme> {
val context = LocalContext.current
val dataStore: LauncherDataStore by inject()
val themePreference by remember { dataStore.data.map { it.appearance.theme } }.collectAsState(
Theme.System
)
val darkTheme =
themePreference == Theme.Dark || themePreference == Theme.System && isSystemInDarkTheme()
val state = remember(colorScheme, darkTheme) {
mutableStateOf(
when (colorScheme) {
AppearanceSettings.ColorScheme.BlackAndWhite -> {
if (darkTheme) DarkBlackAndWhiteColorScheme else LightBlackAndWhiteColorScheme
}
else -> {
if (darkTheme) {
if (isAtLeastApiLevel(31)) dynamicDarkColorScheme(context)
else DarkPre31DefaultColorScheme
} else {
if (isAtLeastApiLevel(31)) dynamicLightColorScheme(context)
else LightPre31DefaultColorScheme
}
}
}
)
}
if (colorScheme == AppearanceSettings.ColorScheme.Wallpaper && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
val wallpaperColors by wallpaperColorsAsState()
LaunchedEffect(wallpaperColors, darkTheme) {
state.value = WallpaperColorScheme(wallpaperColors, darkTheme)
}
}
}
return state
}
@@ -4,6 +4,7 @@ import android.app.WallpaperManager
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
@@ -0,0 +1,69 @@
package de.mm20.launcher2.ui.theme.colorscheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import de.mm20.launcher2.ui.theme.WallpaperColors
import palettes.TonalPalette
fun WallpaperColorScheme(wallpaperColors: WallpaperColors, darkTheme: Boolean): ColorScheme {
val primary = TonalPalette.fromInt(wallpaperColors.primary.toArgb())
val secondary = TonalPalette.fromInt((wallpaperColors.secondary ?: wallpaperColors.primary).toArgb())
val tertiary = TonalPalette.fromInt((wallpaperColors.tertiary ?: wallpaperColors.primary).toArgb())
val neutral1 = TonalPalette.fromInt(Color.Black.toArgb())
val neutral2 = TonalPalette.fromInt(Color.Black.toArgb())
return if(darkTheme) {
darkColorScheme(
primary = Color(primary.tone(80)),
onPrimary = Color(primary.tone(20)),
primaryContainer = Color(primary.tone(30)),
onPrimaryContainer = Color(primary.tone(90)),
secondary = Color(secondary.tone(80)),
onSecondary = Color(secondary.tone(20)),
secondaryContainer = Color(secondary.tone(30)),
onSecondaryContainer = Color(secondary.tone(90)),
tertiary = Color(tertiary.tone(80)),
onTertiary = Color(tertiary.tone(20)),
tertiaryContainer = Color(tertiary.tone(30)),
onTertiaryContainer = Color(tertiary.tone(90)),
background = Color(neutral1.tone(10)),
onBackground = Color(neutral1.tone(90)),
surface = Color(neutral1.tone(10)),
onSurface = Color(neutral1.tone(90)),
surfaceVariant = Color(neutral2.tone(30)),
onSurfaceVariant = Color(neutral2.tone(80)),
outline = Color(neutral2.tone(60)),
inverseSurface = Color(neutral1.tone(90)),
inverseOnSurface = Color(neutral1.tone(20)),
inversePrimary = Color(primary.tone(40)),
)
} else {
lightColorScheme(
primary = Color(primary.tone(40)),
onPrimary = Color(primary.tone(100)),
primaryContainer = Color(primary.tone(90)),
onPrimaryContainer = Color(primary.tone(10)),
secondary = Color(secondary.tone(40)),
onSecondary = Color(secondary.tone(100)),
secondaryContainer = Color(secondary.tone(90)),
onSecondaryContainer = Color(secondary.tone(10)),
tertiary = Color(tertiary.tone(40)),
onTertiary = Color(tertiary.tone(100)),
tertiaryContainer = Color(tertiary.tone(90)),
onTertiaryContainer = Color(tertiary.tone(10)),
background = Color(neutral1.tone(99)),
onBackground = Color(neutral1.tone(10)),
surface = Color(neutral1.tone(99)),
onSurface = Color(neutral1.tone(10)),
surfaceVariant = Color(neutral2.tone(90)),
onSurfaceVariant = Color(neutral2.tone(30)),
outline = Color(neutral2.tone(50)),
inverseSurface = Color(neutral1.tone(20)),
inverseOnSurface = Color(neutral1.tone(95)),
inversePrimary = Color(primary.tone(80)),)
}
}