Use dependency injection to access dataStore, not the context.dataStore extension
This commit is contained in:
parent
9d6ca3d613
commit
11e6a3ceb3
@ -10,7 +10,7 @@ import de.mm20.launcher2.preferences.migrations.FactorySettingsMigration
|
|||||||
|
|
||||||
typealias LauncherDataStore = DataStore<Settings>
|
typealias LauncherDataStore = DataStore<Settings>
|
||||||
|
|
||||||
val Context.dataStore: LauncherDataStore by dataStore(
|
internal val Context.dataStore: LauncherDataStore by dataStore(
|
||||||
fileName = "settings.pb",
|
fileName = "settings.pb",
|
||||||
serializer = SettingsSerializer,
|
serializer = SettingsSerializer,
|
||||||
produceMigrations = {
|
produceMigrations = {
|
||||||
|
|||||||
@ -3,14 +3,9 @@ package de.mm20.launcher2.ui
|
|||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.material.darkColors
|
import androidx.compose.material.darkColors
|
||||||
import androidx.compose.material.lightColors
|
import androidx.compose.material.lightColors
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Typography
|
import androidx.compose.material3.Typography
|
||||||
import androidx.compose.material3.lightColorScheme
|
|
||||||
import androidx.compose.material3.*
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.Font
|
import androidx.compose.ui.text.font.Font
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
@ -18,11 +13,9 @@ import androidx.compose.ui.text.font.FontStyle
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import de.mm20.launcher2.ui.locals.LocalColorScheme
|
import de.mm20.launcher2.ui.locals.LocalColorScheme
|
||||||
import de.mm20.launcher2.ui.theme.colors.toDarkColorScheme
|
import de.mm20.launcher2.ui.theme.colors.toDarkColorScheme
|
||||||
import de.mm20.launcher2.ui.theme.colors.toLightColorScheme
|
import de.mm20.launcher2.ui.theme.colors.toLightColorScheme
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
val Poppins = FontFamily(
|
val Poppins = FontFamily(
|
||||||
Font(R.font.poppins100, FontWeight.Thin, FontStyle.Normal),
|
Font(R.font.poppins100, FontWeight.Thin, FontStyle.Normal),
|
||||||
@ -124,11 +117,7 @@ val typography = Typography(
|
|||||||
@Composable
|
@Composable
|
||||||
fun LauncherTheme(content: @Composable () -> Unit) {
|
fun LauncherTheme(content: @Composable () -> Unit) {
|
||||||
|
|
||||||
val dataStore = LocalContext.current.dataStore
|
val theme = Theme.System
|
||||||
|
|
||||||
val theme by remember {
|
|
||||||
dataStore.data.map { it.appearance.theme }
|
|
||||||
}.collectAsState(initial = Theme.System)
|
|
||||||
|
|
||||||
val darkTheme = theme == Theme.Dark || theme == Theme.System && isSystemInDarkTheme()
|
val darkTheme = theme == Theme.Dark || theme == Theme.System && isSystemInDarkTheme()
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import com.google.accompanist.navigation.animation.composable
|
|||||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||||
import de.mm20.launcher2.preferences.Settings
|
import de.mm20.launcher2.preferences.Settings
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import de.mm20.launcher2.ui.LauncherTheme
|
import de.mm20.launcher2.ui.LauncherTheme
|
||||||
import de.mm20.launcher2.ui.locals.LocalAppWidgetHost
|
import de.mm20.launcher2.ui.locals.LocalAppWidgetHost
|
||||||
import de.mm20.launcher2.ui.locals.LocalColorScheme
|
import de.mm20.launcher2.ui.locals.LocalColorScheme
|
||||||
@ -28,6 +27,7 @@ import de.mm20.launcher2.ui.locals.LocalNavController
|
|||||||
import de.mm20.launcher2.ui.locals.LocalWindowSize
|
import de.mm20.launcher2.ui.locals.LocalWindowSize
|
||||||
import de.mm20.launcher2.ui.screens.LauncherMainScreen
|
import de.mm20.launcher2.ui.screens.LauncherMainScreen
|
||||||
import de.mm20.launcher2.ui.screens.settings.*
|
import de.mm20.launcher2.ui.screens.settings.*
|
||||||
|
import de.mm20.launcher2.ui.settings.appearance.AppearanceScreen
|
||||||
import de.mm20.launcher2.ui.theme.colors.*
|
import de.mm20.launcher2.ui.theme.colors.*
|
||||||
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
|
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@ -55,8 +55,7 @@ class ComposeActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
if (windowSize.height <= 0 || windowSize.width <= 0) return@setContent
|
if (windowSize.height <= 0 || windowSize.width <= 0) return@setContent
|
||||||
|
|
||||||
val colorSchemePreference by remember { dataStore.data.map { it.appearance.colorScheme } }
|
val colorSchemePreference = Settings.AppearanceSettings.ColorScheme.Default
|
||||||
.collectAsState(initial = Settings.AppearanceSettings.ColorScheme.Default)
|
|
||||||
|
|
||||||
val colorScheme = when (colorSchemePreference) {
|
val colorScheme = when (colorSchemePreference) {
|
||||||
Settings.AppearanceSettings.ColorScheme.MM20 -> MM20ColorPalette()
|
Settings.AppearanceSettings.ColorScheme.MM20 -> MM20ColorPalette()
|
||||||
@ -72,10 +71,6 @@ class ComposeActivity : AppCompatActivity() {
|
|||||||
} else DefaultColorPalette()
|
} else DefaultColorPalette()
|
||||||
}
|
}
|
||||||
Settings.AppearanceSettings.ColorScheme.BlackAndWhite -> BlackWhiteColorPalette()
|
Settings.AppearanceSettings.ColorScheme.BlackAndWhite -> BlackWhiteColorPalette()
|
||||||
Settings.AppearanceSettings.ColorScheme.Custom -> {
|
|
||||||
val customColors by customColorsAsState()
|
|
||||||
CustomColorPalette(customColors)
|
|
||||||
}
|
|
||||||
else -> DefaultColorPalette()
|
else -> DefaultColorPalette()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,13 +108,7 @@ class ComposeActivity : AppCompatActivity() {
|
|||||||
SettingsAccountScreen()
|
SettingsAccountScreen()
|
||||||
}
|
}
|
||||||
composable("settings/appearance") {
|
composable("settings/appearance") {
|
||||||
SettingsAppearanceScreen()
|
AppearanceScreen()
|
||||||
}
|
|
||||||
composable("settings/appearance/colors") {
|
|
||||||
SettingsColorsScreen()
|
|
||||||
}
|
|
||||||
composable("settings/appearance/clock") {
|
|
||||||
SettingsClockScreen()
|
|
||||||
}
|
}
|
||||||
composable(
|
composable(
|
||||||
"settings/license?library={libraryName}",
|
"settings/license?library={libraryName}",
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.google.accompanist.insets.LocalWindowInsets
|
import com.google.accompanist.insets.LocalWindowInsets
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ClockStyle
|
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ClockStyle
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import de.mm20.launcher2.ui.component.AnalogClock
|
import de.mm20.launcher2.ui.component.AnalogClock
|
||||||
import de.mm20.launcher2.ui.component.BinaryClock
|
import de.mm20.launcher2.ui.component.BinaryClock
|
||||||
import de.mm20.launcher2.ui.component.DigitalClock
|
import de.mm20.launcher2.ui.component.DigitalClock
|
||||||
@ -55,10 +54,7 @@ fun ClockWidget(
|
|||||||
fun Clock() {
|
fun Clock() {
|
||||||
var time by remember { mutableStateOf(System.currentTimeMillis()) }
|
var time by remember { mutableStateOf(System.currentTimeMillis()) }
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val dataStore = context.dataStore
|
val clockStyle = ClockStyle.Digital
|
||||||
val clockStyle by remember { dataStore.data.map { it.appearance.clockStyle } }.collectAsState(
|
|
||||||
initial = ClockStyle.Digital
|
|
||||||
)
|
|
||||||
|
|
||||||
DisposableEffect(null) {
|
DisposableEffect(null) {
|
||||||
val receiver = object : BroadcastReceiver() {
|
val receiver = object : BroadcastReceiver() {
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
package de.mm20.launcher2.ui.screens.settings
|
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import de.mm20.launcher2.ui.R
|
|
||||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
|
||||||
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 kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsAppearanceScreen() {
|
|
||||||
val context = LocalContext.current
|
|
||||||
val dataStore = context.dataStore
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val theme by remember {
|
|
||||||
dataStore.data.map { it.appearance.theme }
|
|
||||||
}.collectAsState(initial = Settings.AppearanceSettings.Theme.System)
|
|
||||||
ListPreference(
|
|
||||||
title = stringResource(id = R.string.preference_theme),
|
|
||||||
items = listOf(
|
|
||||||
stringResource(id = R.string.preference_theme_system) to Settings.AppearanceSettings.Theme.System,
|
|
||||||
stringResource(id = R.string.preference_theme_light) to Settings.AppearanceSettings.Theme.Light,
|
|
||||||
stringResource(id = R.string.preference_theme_dark) to Settings.AppearanceSettings.Theme.Dark,
|
|
||||||
),
|
|
||||||
value = theme,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(it.appearance.toBuilder().setTheme(newValue))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Preference(
|
|
||||||
title = stringResource(id = R.string.preference_screen_colors),
|
|
||||||
onClick = {
|
|
||||||
navController?.navigate("settings/appearance/colors")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
PreferenceCategory(title = stringResource(id = R.string.preference_category_clock_widget)) {
|
|
||||||
Preference(
|
|
||||||
title = stringResource(id = R.string.preference_clock_widget_style),
|
|
||||||
onClick = {
|
|
||||||
navController?.navigate("settings/appearance/clock")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,102 +1,17 @@
|
|||||||
package de.mm20.launcher2.ui.screens.settings
|
package de.mm20.launcher2.ui.screens.settings
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
|
||||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsBadgesScreen() {
|
fun SettingsBadgesScreen() {
|
||||||
val dataStore = LocalContext.current.dataStore
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
PreferenceScreen(
|
PreferenceScreen(
|
||||||
title = stringResource(id = R.string.preference_screen_badges)
|
title = stringResource(id = R.string.preference_screen_badges)
|
||||||
) {
|
) {
|
||||||
item {
|
|
||||||
PreferenceCategory {
|
|
||||||
val notificationBadges by remember {
|
|
||||||
dataStore.data.map { it.badges.notificationBadges }
|
|
||||||
}.collectAsState(initial = false)
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(id = R.string.preference_notification_badges),
|
|
||||||
summary = stringResource(id = R.string.preference_notification_badges_summary),
|
|
||||||
value = notificationBadges,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setBadges(
|
|
||||||
it.badges.toBuilder().setNotificationBadges(newValue)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val suspendedBadges by remember {
|
|
||||||
dataStore.data.map { it.badges.suspendBadges }
|
|
||||||
}.collectAsState(initial = false)
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(id = R.string.preference_suspended_badges),
|
|
||||||
summary = stringResource(id = R.string.preference_suspended_badges_summary),
|
|
||||||
value = suspendedBadges,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setBadges(
|
|
||||||
it.badges.toBuilder().setSuspendBadges(newValue)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val cloudBadges by remember {
|
|
||||||
dataStore.data.map { it.badges.cloudBadges }
|
|
||||||
}.collectAsState(initial = false)
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(id = R.string.preference_cloud_badges),
|
|
||||||
summary = stringResource(id = R.string.preference_cloud_badges_summary),
|
|
||||||
value = cloudBadges,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setBadges(
|
|
||||||
it.badges.toBuilder().setCloudBadges(newValue)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val shortcutBadges by remember {
|
|
||||||
dataStore.data.map { it.badges.shortcutBadges }
|
|
||||||
}.collectAsState(initial = false)
|
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(id = R.string.preference_shortcut_badges),
|
|
||||||
summary = stringResource(id = R.string.preference_shortcut_badges_summary),
|
|
||||||
value = shortcutBadges,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setBadges(
|
|
||||||
it.badges.toBuilder().setShortcutBadges(newValue)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,97 +0,0 @@
|
|||||||
package de.mm20.launcher2.ui.screens.settings
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.RadioButtonChecked
|
|
||||||
import androidx.compose.material.icons.rounded.RadioButtonUnchecked
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.datastore.core.DataStore
|
|
||||||
import de.mm20.launcher2.preferences.Settings
|
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ClockStyle
|
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import de.mm20.launcher2.ui.R
|
|
||||||
import de.mm20.launcher2.ui.component.AnalogClock
|
|
||||||
import de.mm20.launcher2.ui.component.BinaryClock
|
|
||||||
import de.mm20.launcher2.ui.component.DigitalClock
|
|
||||||
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 kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsClockScreen() {
|
|
||||||
val dataStore = LocalContext.current.dataStore
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val selectedClock by remember { dataStore.data.map { it.appearance.clockStyle } }.collectAsState(
|
|
||||||
initial = ClockStyle.Digital
|
|
||||||
)
|
|
||||||
val time = System.currentTimeMillis()
|
|
||||||
PreferenceScreen(title = stringResource(id = R.string.preference_clock_widget_style)) {
|
|
||||||
item {
|
|
||||||
ClockPreview(selected = selectedClock == ClockStyle.Digital, onClick = {
|
|
||||||
scope.launch {
|
|
||||||
updateClock(dataStore, ClockStyle.Digital)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
DigitalClock(time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
ClockPreview(selected = selectedClock == ClockStyle.Analog, onClick = {
|
|
||||||
scope.launch {
|
|
||||||
updateClock(dataStore, ClockStyle.Analog)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
AnalogClock(time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
ClockPreview(selected = selectedClock == ClockStyle.Binary, onClick = {
|
|
||||||
scope.launch {
|
|
||||||
updateClock(dataStore, ClockStyle.Binary)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
BinaryClock(time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun updateClock(dataStore: DataStore<Settings>, clockStyle: ClockStyle) {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(it.appearance.toBuilder().setClockStyle(clockStyle))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ClockPreview(
|
|
||||||
selected: Boolean,
|
|
||||||
onClick: () -> Unit,
|
|
||||||
clock: @Composable () -> Unit
|
|
||||||
) {
|
|
||||||
PreferenceCategory {
|
|
||||||
Preference(
|
|
||||||
title = "",
|
|
||||||
icon = if (selected) Icons.Rounded.RadioButtonChecked else Icons.Rounded.RadioButtonUnchecked,
|
|
||||||
controls = {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
clock()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick = onClick
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,255 +0,0 @@
|
|||||||
package de.mm20.launcher2.ui.screens.settings
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.RadioButtonChecked
|
|
||||||
import androidx.compose.material.icons.rounded.RadioButtonUnchecked
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.toArgb
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import de.mm20.launcher2.ui.R
|
|
||||||
import de.mm20.launcher2.ui.component.preferences.ColorPreference
|
|
||||||
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.colors.*
|
|
||||||
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme as ColorSchemeOption
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsColorsScreen() {
|
|
||||||
val context = LocalContext.current
|
|
||||||
val dataStore = context.dataStore
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val customColors by customColorsAsState()
|
|
||||||
val colorScheme by remember {
|
|
||||||
dataStore.data.map {
|
|
||||||
it.appearance.colorScheme
|
|
||||||
}
|
|
||||||
}.collectAsState(initial = ColorSchemeOption.Default)
|
|
||||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_colors)) {
|
|
||||||
item {
|
|
||||||
val schemes = mutableListOf(
|
|
||||||
ColorSchemeItem(
|
|
||||||
ColorSchemeOption.Default,
|
|
||||||
DefaultColorPalette(),
|
|
||||||
stringResource(id = R.string.preference_colors_default)
|
|
||||||
),
|
|
||||||
ColorSchemeItem(
|
|
||||||
ColorSchemeOption.MM20,
|
|
||||||
MM20ColorPalette(),
|
|
||||||
stringResource(id = R.string.preference_colors_mm20)
|
|
||||||
),
|
|
||||||
ColorSchemeItem(
|
|
||||||
ColorSchemeOption.BlackAndWhite,
|
|
||||||
BlackWhiteColorPalette(),
|
|
||||||
stringResource(id = R.string.preference_colors_bw)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (isAtLeastApiLevel(Build.VERSION_CODES.S)) {
|
|
||||||
schemes.add(
|
|
||||||
ColorSchemeItem(
|
|
||||||
ColorSchemeOption.MaterialYou,
|
|
||||||
SystemColorPalette(context),
|
|
||||||
stringResource(id = R.string.preference_colors_mdyou)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (isAtLeastApiLevel(Build.VERSION_CODES.O_MR1)) {
|
|
||||||
val wallpaperColors by wallpaperColorsAsState()
|
|
||||||
schemes.add(
|
|
||||||
ColorSchemeItem(
|
|
||||||
ColorSchemeOption.Wallpaper,
|
|
||||||
WallpaperColorPalette(wallpaperColors),
|
|
||||||
stringResource(id = R.string.preference_colors_wallpaper)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
schemes.add(
|
|
||||||
ColorSchemeItem(
|
|
||||||
ColorSchemeOption.Custom,
|
|
||||||
CustomColorPalette(customColors),
|
|
||||||
stringResource(id = R.string.preference_colors_custom)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
PreferenceCategory {
|
|
||||||
for (scheme in schemes) {
|
|
||||||
Preference(
|
|
||||||
title = scheme.label,
|
|
||||||
icon = if (colorScheme == scheme.value) Icons.Rounded.RadioButtonChecked else Icons.Rounded.RadioButtonUnchecked,
|
|
||||||
controls = {
|
|
||||||
ColorSchemePreview(scheme.colorPalette)
|
|
||||||
},
|
|
||||||
onClick = {
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder()
|
|
||||||
.setAppearance(
|
|
||||||
it.appearance.toBuilder().setColorScheme(scheme.value)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (colorScheme == ColorSchemeOption.Custom) {
|
|
||||||
item {
|
|
||||||
PreferenceCategory(title = stringResource(R.string.preference_category_custom_colors)) {
|
|
||||||
ColorPreference(
|
|
||||||
title = "Neutral1",
|
|
||||||
value = customColors.neutral1,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setAppearance(
|
|
||||||
it.appearance.toBuilder().setCustomColors(
|
|
||||||
it.appearance.customColors.toBuilder()
|
|
||||||
.setNeutral1(newValue.toArgb())
|
|
||||||
)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
ColorPreference(
|
|
||||||
title = "Neutral2",
|
|
||||||
value = customColors.neutral2,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setAppearance(
|
|
||||||
it.appearance.toBuilder().setCustomColors(
|
|
||||||
it.appearance.customColors.toBuilder()
|
|
||||||
.setNeutral2(newValue.toArgb())
|
|
||||||
)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
ColorPreference(
|
|
||||||
title = "Accent1",
|
|
||||||
value = customColors.accent1,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setAppearance(
|
|
||||||
it.appearance.toBuilder().setCustomColors(
|
|
||||||
it.appearance.customColors.toBuilder()
|
|
||||||
.setAccent1(newValue.toArgb())
|
|
||||||
)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
ColorPreference(
|
|
||||||
title = "Accent2",
|
|
||||||
value = customColors.accent2,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setAppearance(
|
|
||||||
it.appearance.toBuilder().setCustomColors(
|
|
||||||
it.appearance.customColors.toBuilder()
|
|
||||||
.setAccent2(newValue.toArgb())
|
|
||||||
)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
ColorPreference(
|
|
||||||
title = "Accent3",
|
|
||||||
value = customColors.accent3,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
scope.launch {
|
|
||||||
dataStore.updateData {
|
|
||||||
it.toBuilder().setAppearance(
|
|
||||||
it.appearance.toBuilder().setCustomColors(
|
|
||||||
it.appearance.customColors.toBuilder()
|
|
||||||
.setAccent3(newValue.toArgb())
|
|
||||||
)
|
|
||||||
).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ColorSchemePreview(colorPalette: ColorPalette) {
|
|
||||||
val isDark = !androidx.compose.material.MaterialTheme.colors.isLight
|
|
||||||
val neutral1 = if (isDark) colorPalette.neutral.shade20 else colorPalette.neutral.shade90
|
|
||||||
val neutral2 = if (isDark) colorPalette.neutralVariant.shade20 else colorPalette.neutralVariant.shade90
|
|
||||||
val accent1 = if (isDark) colorPalette.primary.shade70 else colorPalette.primary.shade50
|
|
||||||
val accent2 = if (isDark) colorPalette.secondary.shade70 else colorPalette.secondary.shade50
|
|
||||||
val accent3 = if (isDark) colorPalette.tertiary.shade70 else colorPalette.tertiary.shade50
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.height(48.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxHeight()
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.width(48.dp)
|
|
||||||
.background(neutral1)
|
|
||||||
)
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.width(48.dp)
|
|
||||||
.background(neutral2)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.height(16.dp)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(16.dp)
|
|
||||||
.background(accent1)
|
|
||||||
)
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
.size(16.dp)
|
|
||||||
.background(accent2)
|
|
||||||
)
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(16.dp)
|
|
||||||
.background(accent3)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class ColorSchemeItem(
|
|
||||||
val value: ColorSchemeOption,
|
|
||||||
val colorPalette: ColorPalette,
|
|
||||||
val label: String,
|
|
||||||
)
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
package de.mm20.launcher2.ui.theme.colors
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.State
|
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import de.mm20.launcher2.preferences.dataStore
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
class CustomColorPalette(val colors: CustomColors) : ColorPalette() {
|
|
||||||
override val neutral: ColorSwatch
|
|
||||||
get() = colorSwatch(colors.neutral1)
|
|
||||||
override val neutralVariant: ColorSwatch
|
|
||||||
get() = colorSwatch(colors.neutral2)
|
|
||||||
override val primary: ColorSwatch
|
|
||||||
get() = colorSwatch(colors.accent1)
|
|
||||||
override val secondary: ColorSwatch
|
|
||||||
get() = colorSwatch(colors.accent2)
|
|
||||||
override val tertiary: ColorSwatch
|
|
||||||
get() = colorSwatch(colors.accent3)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
data class CustomColors(
|
|
||||||
val neutral1: Color,
|
|
||||||
val neutral2: Color,
|
|
||||||
val accent1: Color,
|
|
||||||
val accent2: Color,
|
|
||||||
val accent3: Color,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun customColorsAsState(): State<CustomColors> {
|
|
||||||
val dataStore = LocalContext.current.dataStore
|
|
||||||
return remember {
|
|
||||||
dataStore.data.map {
|
|
||||||
val colors = it.appearance.customColors
|
|
||||||
CustomColors(
|
|
||||||
neutral1 = Color(colors.neutral1).copy(alpha = 1f),
|
|
||||||
neutral2 = Color(colors.neutral2).copy(alpha = 1f),
|
|
||||||
accent1 = Color(colors.accent1).copy(alpha = 1f),
|
|
||||||
accent2 = Color(colors.accent2).copy(alpha = 1f),
|
|
||||||
accent3 = Color(colors.accent3).copy(alpha = 1f),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}.collectAsState(
|
|
||||||
initial = DefaultCustomColors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val DefaultCustomColors = CustomColors(
|
|
||||||
Color.Black,
|
|
||||||
Color.Black,
|
|
||||||
Color.Black,
|
|
||||||
Color.Black,
|
|
||||||
Color.Black,
|
|
||||||
)
|
|
||||||
Loading…
x
Reference in New Issue
Block a user