Custom color schemes v2 - Part 3
Store custom themes in database
This commit is contained in:
parent
4e681234fd
commit
70f658f9f3
@ -3,5 +3,5 @@ package de.mm20.launcher2.themes
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val themesModule = module {
|
val themesModule = module {
|
||||||
factory { ThemeRepository(get()) }
|
factory { ThemeRepository(get(), get()) }
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package de.mm20.launcher2.themes
|
package de.mm20.launcher2.themes
|
||||||
|
|
||||||
|
import de.mm20.launcher2.database.entities.ThemeEntity
|
||||||
import hct.Hct
|
import hct.Hct
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@ -23,14 +24,42 @@ enum class CorePaletteColor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CorePaletteColor(color: String): CorePaletteColor? {
|
||||||
|
return when (color) {
|
||||||
|
"p" -> CorePaletteColor.Primary
|
||||||
|
"s" -> CorePaletteColor.Secondary
|
||||||
|
"t" -> CorePaletteColor.Tertiary
|
||||||
|
"n" -> CorePaletteColor.Neutral
|
||||||
|
"nv" -> CorePaletteColor.NeutralVariant
|
||||||
|
"e" -> CorePaletteColor.Error
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealed interface Color
|
sealed interface Color
|
||||||
|
|
||||||
|
internal fun Color(string: String?): Color? {
|
||||||
|
if (string == null) return null
|
||||||
|
if (string.startsWith("#")) {
|
||||||
|
return StaticColor(string.substring(1).toLongOrNull(16)?.toInt() ?: return null)
|
||||||
|
}
|
||||||
|
if (string.startsWith("$")) {
|
||||||
|
val parts = string.substring(1).split(".").takeIf { it.size == 2 } ?: return null
|
||||||
|
val color = CorePaletteColor(parts[0]) ?: return null
|
||||||
|
return ColorRef(
|
||||||
|
color = color,
|
||||||
|
tone = parts[1].toIntOrNull() ?: return null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
data class ColorRef(
|
data class ColorRef(
|
||||||
val color: CorePaletteColor,
|
val color: CorePaletteColor,
|
||||||
val tone: Int,
|
val tone: Int,
|
||||||
) : Color {
|
) : Color {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "\$${color.name}.$tone"
|
return "\$${color.toString()}.$tone"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +84,7 @@ val EmptyCorePalette = CorePalette<Int?>(null, null, null, null, null, null)
|
|||||||
typealias FullCorePalette = CorePalette<Int>
|
typealias FullCorePalette = CorePalette<Int>
|
||||||
typealias PartialCorePalette = CorePalette<Int?>
|
typealias PartialCorePalette = CorePalette<Int?>
|
||||||
|
|
||||||
data class ColorScheme<out T: Color?>(
|
data class ColorScheme<out T : Color?>(
|
||||||
val primary: T,
|
val primary: T,
|
||||||
val onPrimary: T,
|
val onPrimary: T,
|
||||||
val primaryContainer: T,
|
val primaryContainer: T,
|
||||||
@ -105,7 +134,186 @@ data class Theme(
|
|||||||
val corePalette: PartialCorePalette = EmptyCorePalette,
|
val corePalette: PartialCorePalette = EmptyCorePalette,
|
||||||
val lightColorScheme: PartialColorScheme = DefaultLightColorScheme,
|
val lightColorScheme: PartialColorScheme = DefaultLightColorScheme,
|
||||||
val darkColorScheme: PartialColorScheme = DefaultDarkColorScheme,
|
val darkColorScheme: PartialColorScheme = DefaultDarkColorScheme,
|
||||||
)
|
) {
|
||||||
|
|
||||||
|
constructor(entity: ThemeEntity) : this(
|
||||||
|
id = entity.id,
|
||||||
|
builtIn = false,
|
||||||
|
name = entity.name,
|
||||||
|
corePalette = CorePalette(
|
||||||
|
primary = entity.corePaletteA1,
|
||||||
|
secondary = entity.corePaletteA2,
|
||||||
|
tertiary = entity.corePaletteA3,
|
||||||
|
neutral = entity.corePaletteN1,
|
||||||
|
neutralVariant = entity.corePaletteN2,
|
||||||
|
error = entity.corePaletteE,
|
||||||
|
),
|
||||||
|
lightColorScheme = ColorScheme(
|
||||||
|
primary = Color(entity.lightPrimary),
|
||||||
|
onPrimary = Color(entity.lightOnPrimary),
|
||||||
|
primaryContainer = Color(entity.lightPrimaryContainer),
|
||||||
|
onPrimaryContainer = Color(entity.lightOnPrimaryContainer),
|
||||||
|
secondary = Color(entity.lightSecondary),
|
||||||
|
onSecondary = Color(entity.lightOnSecondary),
|
||||||
|
secondaryContainer = Color(entity.lightSecondaryContainer),
|
||||||
|
onSecondaryContainer = Color(entity.lightOnSecondaryContainer),
|
||||||
|
tertiary = Color(entity.lightTertiary),
|
||||||
|
onTertiary = Color(entity.lightOnTertiary),
|
||||||
|
tertiaryContainer = Color(entity.lightTertiaryContainer),
|
||||||
|
onTertiaryContainer = Color(entity.lightOnTertiaryContainer),
|
||||||
|
error = Color(entity.lightError),
|
||||||
|
onError = Color(entity.lightOnError),
|
||||||
|
errorContainer = Color(entity.lightErrorContainer),
|
||||||
|
onErrorContainer = Color(entity.lightOnErrorContainer),
|
||||||
|
surface = Color(entity.lightSurface),
|
||||||
|
onSurface = Color(entity.lightOnSurface),
|
||||||
|
onSurfaceVariant = Color(entity.lightOnSurfaceVariant),
|
||||||
|
outline = Color(entity.lightOutline),
|
||||||
|
outlineVariant = Color(entity.lightOutlineVariant),
|
||||||
|
inverseSurface = Color(entity.lightInverseSurface),
|
||||||
|
inverseOnSurface = Color(entity.lightInverseOnSurface),
|
||||||
|
inversePrimary = Color(entity.lightInversePrimary),
|
||||||
|
surfaceDim = Color(entity.lightSurfaceDim),
|
||||||
|
surfaceBright = Color(entity.lightSurfaceBright),
|
||||||
|
surfaceContainerLowest = Color(entity.lightSurfaceContainerLowest),
|
||||||
|
surfaceContainerLow = Color(entity.lightSurfaceContainerLow),
|
||||||
|
surfaceContainer = Color(entity.lightSurfaceContainer),
|
||||||
|
surfaceContainerHigh = Color(entity.lightSurfaceContainerHigh),
|
||||||
|
surfaceContainerHighest = Color(entity.lightSurfaceContainerHighest),
|
||||||
|
background = Color(entity.lightBackground),
|
||||||
|
onBackground = Color(entity.lightOnBackground),
|
||||||
|
surfaceTint = Color(entity.lightSurfaceTint),
|
||||||
|
scrim = Color(entity.lightScrim),
|
||||||
|
surfaceVariant = Color(entity.lightSurfaceVariant),
|
||||||
|
),
|
||||||
|
darkColorScheme = ColorScheme(
|
||||||
|
primary = Color(entity.darkPrimary),
|
||||||
|
onPrimary = Color(entity.darkOnPrimary),
|
||||||
|
primaryContainer = Color(entity.darkPrimaryContainer),
|
||||||
|
onPrimaryContainer = Color(entity.darkOnPrimaryContainer),
|
||||||
|
secondary = Color(entity.darkSecondary),
|
||||||
|
onSecondary = Color(entity.darkOnSecondary),
|
||||||
|
secondaryContainer = Color(entity.darkSecondaryContainer),
|
||||||
|
onSecondaryContainer = Color(entity.darkOnSecondaryContainer),
|
||||||
|
tertiary = Color(entity.darkTertiary),
|
||||||
|
onTertiary = Color(entity.darkOnTertiary),
|
||||||
|
tertiaryContainer = Color(entity.darkTertiaryContainer),
|
||||||
|
onTertiaryContainer = Color(entity.darkOnTertiaryContainer),
|
||||||
|
error = Color(entity.darkError),
|
||||||
|
onError = Color(entity.darkOnError),
|
||||||
|
errorContainer = Color(entity.darkErrorContainer),
|
||||||
|
onErrorContainer = Color(entity.darkOnErrorContainer),
|
||||||
|
surface = Color(entity.darkSurface),
|
||||||
|
onSurface = Color(entity.darkOnSurface),
|
||||||
|
onSurfaceVariant = Color(entity.darkOnSurfaceVariant),
|
||||||
|
outline = Color(entity.darkOutline),
|
||||||
|
outlineVariant = Color(entity.darkOutlineVariant),
|
||||||
|
inverseSurface = Color(entity.darkInverseSurface),
|
||||||
|
inverseOnSurface = Color(entity.darkInverseOnSurface),
|
||||||
|
inversePrimary = Color(entity.darkInversePrimary),
|
||||||
|
surfaceDim = Color(entity.darkSurfaceDim),
|
||||||
|
surfaceBright = Color(entity.darkSurfaceBright),
|
||||||
|
surfaceContainerLowest = Color(entity.darkSurfaceContainerLowest),
|
||||||
|
surfaceContainerLow = Color(entity.darkSurfaceContainerLow),
|
||||||
|
surfaceContainer = Color(entity.darkSurfaceContainer),
|
||||||
|
surfaceContainerHigh = Color(entity.darkSurfaceContainerHigh),
|
||||||
|
surfaceContainerHighest = Color(entity.darkSurfaceContainerHighest),
|
||||||
|
background = Color(entity.darkBackground),
|
||||||
|
onBackground = Color(entity.darkOnBackground),
|
||||||
|
surfaceTint = Color(entity.darkSurfaceTint),
|
||||||
|
scrim = Color(entity.darkScrim),
|
||||||
|
surfaceVariant = Color(entity.darkSurfaceVariant),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
internal fun toEntity(): ThemeEntity {
|
||||||
|
return ThemeEntity(
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
corePaletteA1 = corePalette.primary,
|
||||||
|
corePaletteA2 = corePalette.secondary,
|
||||||
|
corePaletteA3 = corePalette.tertiary,
|
||||||
|
corePaletteN1 = corePalette.neutral,
|
||||||
|
corePaletteN2 = corePalette.neutralVariant,
|
||||||
|
corePaletteE = corePalette.error,
|
||||||
|
|
||||||
|
lightPrimary = lightColorScheme.primary?.toString(),
|
||||||
|
lightOnPrimary = lightColorScheme.onPrimary?.toString(),
|
||||||
|
lightPrimaryContainer = lightColorScheme.primaryContainer?.toString(),
|
||||||
|
lightOnPrimaryContainer = lightColorScheme.onPrimaryContainer?.toString(),
|
||||||
|
lightSecondary = lightColorScheme.secondary?.toString(),
|
||||||
|
lightOnSecondary = lightColorScheme.onSecondary?.toString(),
|
||||||
|
lightSecondaryContainer = lightColorScheme.secondaryContainer?.toString(),
|
||||||
|
lightOnSecondaryContainer = lightColorScheme.onSecondaryContainer?.toString(),
|
||||||
|
lightTertiary = lightColorScheme.tertiary?.toString(),
|
||||||
|
lightOnTertiary = lightColorScheme.onTertiary?.toString(),
|
||||||
|
lightTertiaryContainer = lightColorScheme.tertiaryContainer?.toString(),
|
||||||
|
lightOnTertiaryContainer = lightColorScheme.onTertiaryContainer?.toString(),
|
||||||
|
lightError = lightColorScheme.error?.toString(),
|
||||||
|
lightOnError = lightColorScheme.onError?.toString(),
|
||||||
|
lightErrorContainer = lightColorScheme.errorContainer?.toString(),
|
||||||
|
lightOnErrorContainer = lightColorScheme.onErrorContainer?.toString(),
|
||||||
|
lightSurface = lightColorScheme.surface?.toString(),
|
||||||
|
lightOnSurface = lightColorScheme.onSurface?.toString(),
|
||||||
|
lightOnSurfaceVariant = lightColorScheme.onSurfaceVariant?.toString(),
|
||||||
|
lightOutline = lightColorScheme.outline?.toString(),
|
||||||
|
lightOutlineVariant = lightColorScheme.outlineVariant?.toString(),
|
||||||
|
lightInverseSurface = lightColorScheme.inverseSurface?.toString(),
|
||||||
|
lightInverseOnSurface = lightColorScheme.inverseOnSurface?.toString(),
|
||||||
|
lightInversePrimary = lightColorScheme.inversePrimary?.toString(),
|
||||||
|
lightSurfaceDim = lightColorScheme.surfaceDim?.toString(),
|
||||||
|
lightSurfaceBright = lightColorScheme.surfaceBright?.toString(),
|
||||||
|
lightSurfaceContainerLowest = lightColorScheme.surfaceContainerLowest?.toString(),
|
||||||
|
lightSurfaceContainerLow = lightColorScheme.surfaceContainerLow?.toString(),
|
||||||
|
lightSurfaceContainer = lightColorScheme.surfaceContainer?.toString(),
|
||||||
|
lightSurfaceContainerHigh = lightColorScheme.surfaceContainerHigh?.toString(),
|
||||||
|
lightSurfaceContainerHighest = lightColorScheme.surfaceContainerHighest?.toString(),
|
||||||
|
lightBackground = lightColorScheme.background?.toString(),
|
||||||
|
lightOnBackground = lightColorScheme.onBackground?.toString(),
|
||||||
|
lightSurfaceTint = lightColorScheme.surfaceTint?.toString(),
|
||||||
|
lightScrim = lightColorScheme.scrim?.toString(),
|
||||||
|
lightSurfaceVariant = lightColorScheme.surfaceVariant?.toString(),
|
||||||
|
|
||||||
|
darkPrimary = darkColorScheme.primary?.toString(),
|
||||||
|
darkOnPrimary = darkColorScheme.onPrimary?.toString(),
|
||||||
|
darkPrimaryContainer = darkColorScheme.primaryContainer?.toString(),
|
||||||
|
darkOnPrimaryContainer = darkColorScheme.onPrimaryContainer?.toString(),
|
||||||
|
darkSecondary = darkColorScheme.secondary?.toString(),
|
||||||
|
darkOnSecondary = darkColorScheme.onSecondary?.toString(),
|
||||||
|
darkSecondaryContainer = darkColorScheme.secondaryContainer?.toString(),
|
||||||
|
darkOnSecondaryContainer = darkColorScheme.onSecondaryContainer?.toString(),
|
||||||
|
darkTertiary = darkColorScheme.tertiary?.toString(),
|
||||||
|
darkOnTertiary = darkColorScheme.onTertiary?.toString(),
|
||||||
|
darkTertiaryContainer = darkColorScheme.tertiaryContainer?.toString(),
|
||||||
|
darkOnTertiaryContainer = darkColorScheme.onTertiaryContainer?.toString(),
|
||||||
|
darkError = darkColorScheme.error?.toString(),
|
||||||
|
darkOnError = darkColorScheme.onError?.toString(),
|
||||||
|
darkErrorContainer = darkColorScheme.errorContainer?.toString(),
|
||||||
|
darkOnErrorContainer = darkColorScheme.onErrorContainer?.toString(),
|
||||||
|
darkSurface = darkColorScheme.surface?.toString(),
|
||||||
|
darkOnSurface = darkColorScheme.onSurface?.toString(),
|
||||||
|
darkOnSurfaceVariant = darkColorScheme.onSurfaceVariant?.toString(),
|
||||||
|
darkOutline = darkColorScheme.outline?.toString(),
|
||||||
|
darkOutlineVariant = darkColorScheme.outlineVariant?.toString(),
|
||||||
|
darkInverseSurface = darkColorScheme.inverseSurface?.toString(),
|
||||||
|
darkInverseOnSurface = darkColorScheme.inverseOnSurface?.toString(),
|
||||||
|
darkInversePrimary = darkColorScheme.inversePrimary?.toString(),
|
||||||
|
darkSurfaceDim = darkColorScheme.surfaceDim?.toString(),
|
||||||
|
darkSurfaceBright = darkColorScheme.surfaceBright?.toString(),
|
||||||
|
darkSurfaceContainerLowest = darkColorScheme.surfaceContainerLowest?.toString(),
|
||||||
|
darkSurfaceContainerLow = darkColorScheme.surfaceContainerLow?.toString(),
|
||||||
|
darkSurfaceContainer = darkColorScheme.surfaceContainer?.toString(),
|
||||||
|
darkSurfaceContainerHigh = darkColorScheme.surfaceContainerHigh?.toString(),
|
||||||
|
darkSurfaceContainerHighest = darkColorScheme.surfaceContainerHighest?.toString(),
|
||||||
|
darkBackground = darkColorScheme.background?.toString(),
|
||||||
|
darkOnBackground = darkColorScheme.onBackground?.toString(),
|
||||||
|
darkSurfaceTint = darkColorScheme.surfaceTint?.toString(),
|
||||||
|
darkScrim = darkColorScheme.scrim?.toString(),
|
||||||
|
darkSurfaceVariant = darkColorScheme.surfaceVariant?.toString(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <T : Int?> CorePalette<T>.get(color: CorePaletteColor): T {
|
fun <T : Int?> CorePalette<T>.get(color: CorePaletteColor): T {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
|
|||||||
@ -2,16 +2,24 @@ package de.mm20.launcher2.themes
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import de.mm20.launcher2.database.AppDatabase
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class ThemeRepository(
|
class ThemeRepository(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
private val database: AppDatabase,
|
||||||
) {
|
) {
|
||||||
|
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
||||||
|
|
||||||
private val customTheme = MutableStateFlow(Theme(
|
private val customTheme = MutableStateFlow(Theme(
|
||||||
id = UUID.randomUUID(),
|
id = UUID.randomUUID(),
|
||||||
builtIn = false,
|
builtIn = false,
|
||||||
@ -22,23 +30,26 @@ class ThemeRepository(
|
|||||||
))
|
))
|
||||||
|
|
||||||
fun getThemes(): Flow<List<Theme>> {
|
fun getThemes(): Flow<List<Theme>> {
|
||||||
return flowOf(getBuiltInThemes()).combine(customTheme) {
|
return database.themeDao().getAll().map {
|
||||||
builtIn, custom ->
|
getBuiltInThemes() + it.map { Theme(it) }
|
||||||
builtIn + custom
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTheme(id: UUID): Flow<Theme?> {
|
fun getTheme(id: UUID): Flow<Theme?> {
|
||||||
if (id == DefaultThemeId) return flowOf(getDefaultTheme())
|
if (id == DefaultThemeId) return flowOf(getDefaultTheme())
|
||||||
return customTheme
|
return database.themeDao().get(id).map { it?.let { Theme(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTheme(theme: Theme) {
|
fun createTheme(theme: Theme) {
|
||||||
|
scope.launch {
|
||||||
|
database.themeDao().insert(theme.toEntity())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTheme(theme: Theme) {
|
fun updateTheme(theme: Theme) {
|
||||||
Log.d("MM20", "updateTheme: $theme")
|
scope.launch {
|
||||||
customTheme.value = theme
|
database.themeDao().update(theme.toEntity())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getThemeOrDefault(id: UUID): Flow<Theme> {
|
fun getThemeOrDefault(id: UUID): Flow<Theme> {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user