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
|
||||
|
||||
val themesModule = module {
|
||||
factory { ThemeRepository(get()) }
|
||||
factory { ThemeRepository(get(), get()) }
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package de.mm20.launcher2.themes
|
||||
|
||||
import de.mm20.launcher2.database.entities.ThemeEntity
|
||||
import hct.Hct
|
||||
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
|
||||
|
||||
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(
|
||||
val color: CorePaletteColor,
|
||||
val tone: Int,
|
||||
) : Color {
|
||||
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 PartialCorePalette = CorePalette<Int?>
|
||||
|
||||
data class ColorScheme<out T: Color?>(
|
||||
data class ColorScheme<out T : Color?>(
|
||||
val primary: T,
|
||||
val onPrimary: T,
|
||||
val primaryContainer: T,
|
||||
@ -105,7 +134,186 @@ data class Theme(
|
||||
val corePalette: PartialCorePalette = EmptyCorePalette,
|
||||
val lightColorScheme: PartialColorScheme = DefaultLightColorScheme,
|
||||
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 {
|
||||
return when (color) {
|
||||
|
||||
@ -2,16 +2,24 @@ package de.mm20.launcher2.themes
|
||||
|
||||
import android.content.Context
|
||||
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.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
class ThemeRepository(
|
||||
private val context: Context,
|
||||
private val database: AppDatabase,
|
||||
) {
|
||||
private val scope = CoroutineScope(Dispatchers.IO + Job())
|
||||
|
||||
private val customTheme = MutableStateFlow(Theme(
|
||||
id = UUID.randomUUID(),
|
||||
builtIn = false,
|
||||
@ -22,23 +30,26 @@ class ThemeRepository(
|
||||
))
|
||||
|
||||
fun getThemes(): Flow<List<Theme>> {
|
||||
return flowOf(getBuiltInThemes()).combine(customTheme) {
|
||||
builtIn, custom ->
|
||||
builtIn + custom
|
||||
return database.themeDao().getAll().map {
|
||||
getBuiltInThemes() + it.map { Theme(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun getTheme(id: UUID): Flow<Theme?> {
|
||||
if (id == DefaultThemeId) return flowOf(getDefaultTheme())
|
||||
return customTheme
|
||||
return database.themeDao().get(id).map { it?.let { Theme(it) } }
|
||||
}
|
||||
|
||||
fun createTheme(theme: Theme) {
|
||||
scope.launch {
|
||||
database.themeDao().insert(theme.toEntity())
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTheme(theme: Theme) {
|
||||
Log.d("MM20", "updateTheme: $theme")
|
||||
customTheme.value = theme
|
||||
scope.launch {
|
||||
database.themeDao().update(theme.toEntity())
|
||||
}
|
||||
}
|
||||
|
||||
fun getThemeOrDefault(id: UUID): Flow<Theme> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user