Add import for new color scheme format

This commit is contained in:
MM20
2025-06-07 14:06:09 +02:00
parent f21feba000
commit 889aa37915
15 changed files with 642 additions and 64 deletions
@@ -1,14 +1,16 @@
package de.mm20.launcher2.themes
import de.mm20.launcher2.database.entities.ColorsEntity
import de.mm20.launcher2.serialization.ColorIntAsHexSerializer
import de.mm20.launcher2.serialization.UUIDSerializer
import hct.Hct
import kotlinx.serialization.Contextual
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import java.util.UUID
@Serializable
data class Colors(
@Transient val id: UUID = UUID.randomUUID(),
@Serializable(with = UUIDSerializer::class) val id: UUID = UUID.randomUUID(),
val builtIn: Boolean = false,
val name: String,
val corePalette: PartialCorePalette = EmptyCorePalette,
@@ -229,7 +231,6 @@ enum class CorePaletteColor {
}
}
@Serializable(with = ColorSerializer::class)
sealed interface Color {
companion object {
fun fromString(string: String?): Color? {
@@ -267,6 +268,8 @@ value class StaticColor(val color: Int) : Color {
}
}
typealias CorePaletteColorValue = @Serializable(with = ColorIntAsHexSerializer::class) Int
@Serializable
data class CorePalette<out T : Int?>(
val primary: T,
@@ -277,50 +280,50 @@ data class CorePalette<out T : Int?>(
val error: T,
)
val EmptyCorePalette = CorePalette<Int?>(null, null, null, null, null, null)
val EmptyCorePalette = CorePalette<CorePaletteColorValue?>(null, null, null, null, null, null)
typealias FullCorePalette = CorePalette<Int>
typealias PartialCorePalette = CorePalette<Int?>
typealias FullCorePalette = CorePalette<CorePaletteColorValue>
typealias PartialCorePalette = CorePalette<CorePaletteColorValue?>
@Serializable
data class ColorScheme<out T : Color?>(
val primary: T,
val onPrimary: T,
val primaryContainer: T,
val onPrimaryContainer: T,
val secondary: T,
val onSecondary: T,
val secondaryContainer: T,
val onSecondaryContainer: T,
val tertiary: T,
val onTertiary: T,
val tertiaryContainer: T,
val onTertiaryContainer: T,
val error: T,
val onError: T,
val errorContainer: T,
val onErrorContainer: T,
val surface: T,
val onSurface: T,
val onSurfaceVariant: T,
val outline: T,
val outlineVariant: T,
val inverseSurface: T,
val inverseOnSurface: T,
val inversePrimary: T,
val surfaceDim: T,
val surfaceBright: T,
val surfaceContainerLowest: T,
val surfaceContainerLow: T,
val surfaceContainer: T,
val surfaceContainerHigh: T,
val surfaceContainerHighest: T,
@Contextual val primary: T,
@Contextual val onPrimary: T,
@Contextual val primaryContainer: T,
@Contextual val onPrimaryContainer: T,
@Contextual val secondary: T,
@Contextual val onSecondary: T,
@Contextual val secondaryContainer: T,
@Contextual val onSecondaryContainer: T,
@Contextual val tertiary: T,
@Contextual val onTertiary: T,
@Contextual val tertiaryContainer: T,
@Contextual val onTertiaryContainer: T,
@Contextual val error: T,
@Contextual val onError: T,
@Contextual val errorContainer: T,
@Contextual val onErrorContainer: T,
@Contextual val surface: T,
@Contextual val onSurface: T,
@Contextual val onSurfaceVariant: T,
@Contextual val outline: T,
@Contextual val outlineVariant: T,
@Contextual val inverseSurface: T,
@Contextual val inverseOnSurface: T,
@Contextual val inversePrimary: T,
@Contextual val surfaceDim: T,
@Contextual val surfaceBright: T,
@Contextual val surfaceContainerLowest: T,
@Contextual val surfaceContainerLow: T,
@Contextual val surfaceContainer: T,
@Contextual val surfaceContainerHigh: T,
@Contextual val surfaceContainerHighest: T,
val background: T,
val onBackground: T,
val surfaceTint: T,
val scrim: T,
val surfaceVariant: T,
@Contextual val background: T,
@Contextual val onBackground: T,
@Contextual val surfaceTint: T,
@Contextual val scrim: T,
@Contextual val surfaceVariant: T,
)
typealias FullColorScheme = ColorScheme<Color>
@@ -6,8 +6,25 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
internal class ColorSerializer: KSerializer<Color> {
internal val module = SerializersModule {
contextual(Color::class, ColorSerializer)
}
val ThemeJson = Json {
serializersModule = module
encodeDefaults = true
ignoreUnknownKeys = true
explicitNulls = false
isLenient = true
coerceInputValues = true
}
internal object ColorSerializer: KSerializer<Color> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ColorSerializer", PrimitiveKind.STRING)
override fun serialize(
@@ -18,12 +35,12 @@ internal class ColorSerializer: KSerializer<Color> {
}
override fun deserialize(decoder: Decoder): Color {
TODO("Not yet implemented")
val stringValue = decoder.decodeString()
return Color.fromString(stringValue) ?: StaticColor(0xFF000000.toInt())
}
}
internal class ShapeSerializer: KSerializer<Shape> {
internal object ShapeSerializer: KSerializer<Shape> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ShapeSerializer", PrimitiveKind.STRING)
override fun serialize(
@@ -1,13 +1,13 @@
package de.mm20.launcher2.themes
import de.mm20.launcher2.database.entities.ShapesEntity
import de.mm20.launcher2.serialization.UUIDSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import java.util.UUID
@Serializable
data class Shapes(
@Transient val id: UUID = UUID.randomUUID(),
@Serializable(with = UUIDSerializer::class) val id: UUID = UUID.randomUUID(),
val builtIn: Boolean = false,
val name: String,
val baseShape: Shape = Shape(
@@ -1,5 +1,6 @@
package de.mm20.launcher2.themes
import android.util.Log
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.serialization.Json
import kotlinx.coroutines.Dispatchers
@@ -7,10 +8,13 @@ import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.intOrNull
import kotlinx.serialization.json.jsonObject
import java.util.UUID
@Serializable
data class ThemeBundle(
@@ -24,21 +28,23 @@ data class ThemeBundle(
val version: Int = 2,
) {
fun toJson(): String {
return Json.Lenient.encodeToString(this)
return ThemeJson.encodeToString(this)
}
companion object {
fun fromJson(jsonString: String): ThemeBundle? {
try {
val jsonElement = Json.Lenient.parseToJsonElement(jsonString).jsonObject
val jsonElement = ThemeJson.parseToJsonElement(jsonString).jsonObject
val version = (jsonElement.get("version") as? JsonPrimitive)?.intOrNull
val version = (jsonElement["version"] as? JsonPrimitive)?.intOrNull
if (version != 2) {
return fromLegacyJson(jsonElement)
}
return Json.Lenient.decodeFromJsonElement(jsonElement)
return ThemeJson.decodeFromJsonElement<ThemeBundle>(jsonElement).also {
Log.d("MM20", "$it")
}
} catch (e: SerializationException) {
CrashReporter.logException(e)
@@ -49,9 +55,26 @@ data class ThemeBundle(
}
}
private fun fromLegacyJson(jsonElement: JsonElement): ThemeBundle? {
private fun fromLegacyJson(jsonElement: JsonObject): ThemeBundle? {
try {
val colorScheme: Colors = LegacyThemeJson.decodeFromJsonElement(jsonElement)
val name = (jsonElement["name"] as? JsonPrimitive)?.contentOrNull ?: return null
val corePalette = (jsonElement["corePalette"] as? JsonObject)?.let {
LegacyThemeJson.decodeFromJsonElement<CorePalette<Int?>>(it)
}
val lightColorScheme = (jsonElement["lightColorScheme"] as? JsonObject)?.let {
LegacyThemeJson.decodeFromJsonElement<ColorScheme<Color?>>(it)
}
val darkColorScheme = (jsonElement["darkColorScheme"] as? JsonObject)?.let {
LegacyThemeJson.decodeFromJsonElement<ColorScheme<Color?>>(it)
}
val colorScheme = Colors(
id = UUID.randomUUID(),
name = name,
corePalette = corePalette ?: EmptyCorePalette,
lightColorScheme = lightColorScheme ?: DefaultLightColorScheme,
darkColorScheme = darkColorScheme ?: DefaultDarkColorScheme,
)
return ThemeBundle(
name = colorScheme.name,
author = "",