(feat) transparency schemes

This commit is contained in:
MM20
2025-06-14 17:17:07 +02:00
parent 68874f1d87
commit 167be6e34d
61 changed files with 1608 additions and 904 deletions
@@ -1,245 +1,20 @@
package de.mm20.launcher2.themes
import de.mm20.launcher2.themes.colors.Color
import de.mm20.launcher2.themes.colors.ColorRef
import de.mm20.launcher2.themes.colors.ColorScheme
import de.mm20.launcher2.themes.colors.CorePaletteColor
import de.mm20.launcher2.themes.colors.StaticColor
import java.util.UUID
val DefaultThemeId = UUID(0L, 0L)
val HighContrastThemeId = UUID(0L, 2L)
val BlackAndWhiteThemeId = UUID(0L, 1L)
val ExtraRoundShapesId = UUID(0L, 1L)
val CutShapesId = UUID(0L, 2L)
val RectShapesId = UUID(0L, 3L)
val DefaultLightColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 40),
onPrimary = ColorRef(CorePaletteColor.Primary, 100),
primaryContainer = ColorRef(CorePaletteColor.Primary, 90),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 30),
secondary = ColorRef(CorePaletteColor.Secondary, 40),
onSecondary = ColorRef(CorePaletteColor.Secondary, 100),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 90),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 30),
tertiary = ColorRef(CorePaletteColor.Tertiary, 40),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 100),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 90),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 30),
error = ColorRef(CorePaletteColor.Error, 40),
onError = ColorRef(CorePaletteColor.Error, 100),
errorContainer = ColorRef(CorePaletteColor.Error, 90),
onErrorContainer = ColorRef(CorePaletteColor.Error, 30),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 87),
surface = ColorRef(CorePaletteColor.Neutral, 98),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 98),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 100),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 96),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 94),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 92),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 90),
onSurface = ColorRef(CorePaletteColor.Neutral, 10),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
outline = ColorRef(CorePaletteColor.NeutralVariant, 50),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 80),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 20),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 95),
inversePrimary = ColorRef(CorePaletteColor.Primary, 80),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 90),
surfaceTint = ColorRef(CorePaletteColor.Primary, 40),
background = ColorRef(CorePaletteColor.Neutral, 98),
onBackground = ColorRef(CorePaletteColor.Neutral, 10),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val DefaultDarkColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 80),
onPrimary = ColorRef(CorePaletteColor.Primary, 20),
primaryContainer = ColorRef(CorePaletteColor.Primary, 30),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 90),
secondary = ColorRef(CorePaletteColor.Secondary, 80),
onSecondary = ColorRef(CorePaletteColor.Secondary, 20),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 30),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 90),
tertiary = ColorRef(CorePaletteColor.Tertiary, 80),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 20),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 30),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 90),
error = ColorRef(CorePaletteColor.Error, 80),
onError = ColorRef(CorePaletteColor.Error, 20),
errorContainer = ColorRef(CorePaletteColor.Error, 30),
onErrorContainer = ColorRef(CorePaletteColor.Error, 90),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 6),
surface = ColorRef(CorePaletteColor.Neutral, 6),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 24),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 4),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 10),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 12),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 17),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 22),
onSurface = ColorRef(CorePaletteColor.Neutral, 90),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 80),
outline = ColorRef(CorePaletteColor.NeutralVariant, 60),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 90),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 20),
inversePrimary = ColorRef(CorePaletteColor.Primary, 40),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
surfaceTint = ColorRef(CorePaletteColor.Primary, 80),
background = ColorRef(CorePaletteColor.Neutral, 6),
onBackground = ColorRef(CorePaletteColor.Neutral, 90),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val HighContrastLightColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 20),
onPrimary = ColorRef(CorePaletteColor.Primary, 100),
primaryContainer = ColorRef(CorePaletteColor.Primary, 30),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 100),
secondary = ColorRef(CorePaletteColor.Secondary, 20),
onSecondary = ColorRef(CorePaletteColor.Secondary, 100),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 30),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 100),
tertiary = ColorRef(CorePaletteColor.Tertiary, 20),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 100),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 30),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 100),
error = ColorRef(CorePaletteColor.Error, 20),
onError = ColorRef(CorePaletteColor.Error, 100),
errorContainer = ColorRef(CorePaletteColor.Error, 30),
onErrorContainer = ColorRef(CorePaletteColor.Error, 100),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 87),
surface = ColorRef(CorePaletteColor.Neutral, 98),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 98),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 100),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 96),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 94),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 92),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 90),
onSurface = ColorRef(CorePaletteColor.Neutral, 0),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 0),
outline = ColorRef(CorePaletteColor.NeutralVariant, 20),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 20),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 100),
inversePrimary = ColorRef(CorePaletteColor.Primary, 80),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 90),
surfaceTint = ColorRef(CorePaletteColor.Primary, 20),
background = ColorRef(CorePaletteColor.Neutral, 98),
onBackground = ColorRef(CorePaletteColor.Neutral, 0),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val HighContrastDarkColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 95),
onPrimary = ColorRef(CorePaletteColor.Primary, 0),
primaryContainer = ColorRef(CorePaletteColor.Primary, 80),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 0),
secondary = ColorRef(CorePaletteColor.Secondary, 95),
onSecondary = ColorRef(CorePaletteColor.Secondary, 0),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 80),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 0),
tertiary = ColorRef(CorePaletteColor.Tertiary, 95),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 0),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 80),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 0),
error = ColorRef(CorePaletteColor.Error, 95),
onError = ColorRef(CorePaletteColor.Error, 0),
errorContainer = ColorRef(CorePaletteColor.Error, 80),
onErrorContainer = ColorRef(CorePaletteColor.Error, 0),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 6),
surface = ColorRef(CorePaletteColor.Neutral, 6),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 24),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 4),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 10),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 12),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 17),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 22),
onSurface = ColorRef(CorePaletteColor.Neutral, 100),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 100),
outline = ColorRef(CorePaletteColor.NeutralVariant, 95),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 80),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 90),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 0),
inversePrimary = ColorRef(CorePaletteColor.Primary, 20),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
surfaceTint = ColorRef(CorePaletteColor.Primary, 95),
background = ColorRef(CorePaletteColor.Neutral, 6),
onBackground = ColorRef(CorePaletteColor.Neutral, 100),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val BlackAndWhiteLightColorScheme = ColorScheme<Color?>(
primary = StaticColor(0xFF000000.toInt()),
onPrimary = StaticColor(0xFFFFFFFF.toInt()),
primaryContainer = StaticColor(0xFFFFFFFF.toInt()),
onPrimaryContainer = StaticColor(0xFF000000.toInt()),
inversePrimary = StaticColor(0xFFFFFFFF.toInt()),
secondary = StaticColor(0xFF000000.toInt()),
onSecondary = StaticColor(0xFFFFFFFF.toInt()),
secondaryContainer = StaticColor(0xFFFFFFFF.toInt()),
onSecondaryContainer = StaticColor(0xFF000000.toInt()),
tertiary = StaticColor(0xFF000000.toInt()),
onTertiary = StaticColor(0xFFFFFFFF.toInt()),
tertiaryContainer = StaticColor(0xFFFFFFFF.toInt()),
onTertiaryContainer = StaticColor(0xFF000000.toInt()),
background = StaticColor(0xFFFFFFFF.toInt()),
onBackground = StaticColor(0xFF000000.toInt()),
surface = StaticColor(0xFFFFFFFF.toInt()),
onSurface = StaticColor(0xFF000000.toInt()),
surfaceVariant = StaticColor(0xFFFFFFFF.toInt()),
onSurfaceVariant = StaticColor(0xFF000000.toInt()),
inverseSurface = StaticColor(0xFF000000.toInt()),
inverseOnSurface = StaticColor(0xFFFFFFFF.toInt()),
error = null,
onError = null,
errorContainer = null,
onErrorContainer = null,
outline = StaticColor(0xFF000000.toInt()),
surfaceTint = StaticColor(0xFFFFFFFF.toInt()),
outlineVariant = StaticColor(0xFF000000.toInt()),
scrim = StaticColor(0xFF000000.toInt()),
surfaceDim = StaticColor(0xFFFFFFFF.toInt()),
surfaceBright = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainer = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerHigh = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerHighest = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerLow = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerLowest = StaticColor(0xFFFFFFFF.toInt()),
)
val BlackAndWhiteDarkColorScheme = ColorScheme<Color?>(
primary = StaticColor(0xFFFFFFFF.toInt()),
onPrimary = StaticColor(0xFF000000.toInt()),
primaryContainer = StaticColor(0xFF000000.toInt()),
onPrimaryContainer = StaticColor(0xFFFFFFFF.toInt()),
inversePrimary = StaticColor(0xFF000000.toInt()),
secondary = StaticColor(0xFFFFFFFF.toInt()),
onSecondary = StaticColor(0xFF000000.toInt()),
secondaryContainer = StaticColor(0xFF000000.toInt()),
onSecondaryContainer = StaticColor(0xFFFFFFFF.toInt()),
tertiary = StaticColor(0xFFFFFFFF.toInt()),
onTertiary = StaticColor(0xFF000000.toInt()),
tertiaryContainer = StaticColor(0xFF000000.toInt()),
onTertiaryContainer = StaticColor(0xFFFFFFFF.toInt()),
background = StaticColor(0xFF000000.toInt()),
onBackground = StaticColor(0xFFFFFFFF.toInt()),
surface = StaticColor(0xFF000000.toInt()),
onSurface = StaticColor(0xFFFFFFFF.toInt()),
surfaceVariant = StaticColor(0xFF000000.toInt()),
onSurfaceVariant = StaticColor(0xFFFFFFFF.toInt()),
inverseSurface = StaticColor(0xFFFFFFFF.toInt()),
inverseOnSurface = StaticColor(0xFF000000.toInt()),
error = null,
onError = null,
errorContainer = null,
onErrorContainer = null,
outline = StaticColor(0xFFFFFFFF.toInt()),
surfaceTint = StaticColor(0xFFFFFFFF.toInt()),
outlineVariant = StaticColor(0xFFFFFFFF.toInt()),
scrim = StaticColor(0xFFFFFFFF.toInt()),
surfaceDim = StaticColor(0xFF000000.toInt()),
surfaceBright = StaticColor(0xFF000000.toInt()),
surfaceContainer = StaticColor(0xFF000000.toInt()),
surfaceContainerHigh = StaticColor(0xFF000000.toInt()),
surfaceContainerHighest = StaticColor(0xFF000000.toInt()),
surfaceContainerLow = StaticColor(0xFF000000.toInt()),
surfaceContainerLowest = StaticColor(0xFF000000.toInt()),
)
val SemiTransparentId = UUID(0L, 1L)
@@ -1,5 +1,9 @@
package de.mm20.launcher2.themes
import de.mm20.launcher2.themes.colors.Color
import de.mm20.launcher2.themes.colors.ColorRef
import de.mm20.launcher2.themes.colors.Colors
import de.mm20.launcher2.themes.colors.StaticColor
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException
import kotlinx.serialization.descriptors.PrimitiveKind
@@ -1,5 +1,8 @@
package de.mm20.launcher2.themes
import de.mm20.launcher2.themes.colors.Color
import de.mm20.launcher2.themes.colors.StaticColor
import de.mm20.launcher2.themes.shapes.Shape
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
@@ -8,7 +11,6 @@ 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 val module = SerializersModule {
contextual(Color::class, ColorSerializer)
@@ -2,12 +2,17 @@ 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
import kotlinx.coroutines.withContext
import de.mm20.launcher2.themes.colors.Color
import de.mm20.launcher2.themes.colors.ColorScheme
import de.mm20.launcher2.themes.colors.Colors
import de.mm20.launcher2.themes.colors.CorePalette
import de.mm20.launcher2.themes.colors.DefaultDarkColorScheme
import de.mm20.launcher2.themes.colors.DefaultLightColorScheme
import de.mm20.launcher2.themes.colors.EmptyCorePalette
import de.mm20.launcher2.themes.shapes.Shapes
import de.mm20.launcher2.themes.transparencies.Transparencies
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
@@ -22,6 +27,7 @@ data class ThemeBundle(
val author: String? = null,
val colors: Colors? = null,
val shapes: Shapes? = null,
val transparencies: Transparencies? = null,
/**
* The file version, always 2 for the new theme format.
*/
@@ -4,225 +4,24 @@ import android.content.Context
import de.mm20.launcher2.backup.Backupable
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.database.AppDatabase
import de.mm20.launcher2.preferences.ColorsDescriptor
import de.mm20.launcher2.preferences.ShapesDescriptor
import kotlinx.coroutines.CoroutineScope
import de.mm20.launcher2.themes.colors.Colors
import de.mm20.launcher2.themes.colors.ColorsRepository
import de.mm20.launcher2.themes.shapes.ShapesRepository
import de.mm20.launcher2.themes.transparencies.TransparenciesRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.SerializationException
import java.io.File
import java.util.UUID
class ThemeRepository(
private val context: Context,
private val database: AppDatabase,
) : Backupable {
private val scope = CoroutineScope(Dispatchers.IO + Job())
val colors = ColorsRepository(context, database)
val shapes = ShapesRepository(context, database)
val transparencies = TransparenciesRepository(context, database)
fun getAllColors(): Flow<List<Colors>> {
return database.themeDao().getAllColors().map {
getBuiltInColors() + it.map { Colors(it) }
}
}
fun getColors(id: UUID): Flow<Colors?> {
if (id == DefaultThemeId) return flowOf(getDefaultColors())
if (id == HighContrastThemeId) return flowOf(getHighContrastColors())
if (id == BlackAndWhiteThemeId) return flowOf(getBlackAndWhiteColors())
return database.themeDao().getColors(id).map { it?.let { Colors(it) } }.flowOn(Dispatchers.Default)
}
fun createColors(colors: Colors) {
scope.launch {
database.themeDao().insertColors(colors.toEntity())
}
}
fun updateColors(colors: Colors) {
scope.launch {
database.themeDao().updateColors(colors.toEntity())
}
}
fun getColorsOrDefault(theme: ColorsDescriptor?): Flow<Colors> {
return when(theme) {
is ColorsDescriptor.HighContrast -> flowOf(getHighContrastColors())
is ColorsDescriptor.BlackAndWhite -> flowOf(getBlackAndWhiteColors())
is ColorsDescriptor.Custom -> {
val id = UUID.fromString(theme.id)
getColors(id).map { it ?: getDefaultColors() }
}
else -> flowOf(getDefaultColors())
}
}
private fun getBuiltInColors(): List<Colors> {
return listOf(
getDefaultColors(),
getHighContrastColors(),
getBlackAndWhiteColors(),
)
}
private fun getDefaultColors(): Colors {
return Colors(
id = DefaultThemeId,
builtIn = true,
name = context.getString(R.string.preference_colors_default),
corePalette = EmptyCorePalette,
lightColorScheme = DefaultLightColorScheme,
darkColorScheme = DefaultDarkColorScheme,
)
}
private fun getHighContrastColors(): Colors {
return Colors(
id = HighContrastThemeId,
builtIn = true,
name = context.getString(R.string.preference_colors_high_contrast),
corePalette = EmptyCorePalette,
lightColorScheme = HighContrastLightColorScheme,
darkColorScheme = HighContrastDarkColorScheme,
)
}
private fun getBlackAndWhiteColors(): Colors {
return Colors(
id = BlackAndWhiteThemeId,
builtIn = true,
name = context.getString(R.string.preference_colors_bw),
corePalette = EmptyCorePalette,
lightColorScheme = BlackAndWhiteLightColorScheme,
darkColorScheme = BlackAndWhiteDarkColorScheme,
)
}
fun deleteColors(colors: Colors) {
scope.launch {
database.themeDao().deleteColors(colors.id)
}
}
fun getAllShapes(): Flow<List<Shapes>> {
return database.themeDao().getAllShapes().map {
getBuiltInShapes() + it.map { Shapes(it) }
}
}
fun getShapes(id: UUID): Flow<Shapes?> {
if (id == DefaultThemeId) return flowOf(getDefaultShapes())
if (id == ExtraRoundShapesId) return flowOf(getExtraRoundShapes())
if (id == RectShapesId) return flowOf(getRectShapes())
if (id == CutShapesId) return flowOf(getCutShapes())
return database.themeDao().getShapes(id).map { it?.let { Shapes(it) } }.flowOn(Dispatchers.Default)
}
fun createShapes(shapes: Shapes) {
scope.launch {
database.themeDao().insertShapes(shapes.toEntity())
}
}
fun updateShapes(shapes: Shapes) {
scope.launch {
database.themeDao().updateShapes(shapes.toEntity())
}
}
fun getShapesOrDefault(theme: ShapesDescriptor?): Flow<Shapes> {
return when(theme) {
is ShapesDescriptor.Custom -> {
val id = UUID.fromString(theme.id)
getShapes(id).map { it ?: getDefaultShapes() }
}
is ShapesDescriptor.ExtraRound -> flowOf(getExtraRoundShapes())
is ShapesDescriptor.Rect -> flowOf(getRectShapes())
is ShapesDescriptor.Cut -> flowOf(getCutShapes())
else -> flowOf(getDefaultShapes())
}
}
private fun getBuiltInShapes(): List<Shapes> {
return listOf(
getDefaultShapes(),
getExtraRoundShapes(),
getRectShapes(),
getCutShapes(),
)
}
private fun getDefaultShapes(): Shapes {
return Shapes(
id = DefaultThemeId,
builtIn = true,
name = context.getString(R.string.preference_shapes_default),
baseShape = Shape(
corners = CornerStyle.Rounded,
radii = intArrayOf(12, 12, 12, 12),
)
)
}
private fun getCutShapes(): Shapes {
return Shapes(
id = CutShapesId,
builtIn = true,
name = context.getString(R.string.preference_cards_shape_cut),
baseShape = Shape(
corners = CornerStyle.Cut,
radii = intArrayOf(12, 12, 12, 12),
)
)
}
private fun getExtraRoundShapes(): Shapes {
return Shapes(
id = ExtraRoundShapesId,
builtIn = true,
name = context.getString(R.string.preference_shapes_extra_round),
baseShape = Shape(
corners = CornerStyle.Rounded,
radii = intArrayOf(24, 24, 24, 24),
),
extraSmall = Shape(
radii = intArrayOf(4, 4, 4, 4),
),
extraLarge = Shape(
radii = intArrayOf(36, 36, 36, 36),
),
extraLargeIncreased = Shape(
radii = intArrayOf(40, 40, 40, 40),
),
extraExtraLarge = Shape(
radii = intArrayOf(56, 56, 56, 56),
)
)
}
private fun getRectShapes(): Shapes {
return Shapes(
id = RectShapesId,
builtIn = true,
name = context.getString(R.string.preference_shapes_rect),
baseShape = Shape(
corners = CornerStyle.Rounded,
radii = intArrayOf(0, 0, 0, 0),
)
)
}
fun deleteShapes(shapes: Shapes) {
scope.launch {
database.themeDao().deleteShapes(shapes.id)
}
}
override suspend fun backup(toDir: File) = withContext(Dispatchers.IO) {
val dao = database.themeDao()
@@ -257,5 +56,4 @@ class ThemeRepository(
dao.insertAllColors(colors.map { it.toEntity() })
}
}
}
@@ -1,4 +1,4 @@
package de.mm20.launcher2.themes
package de.mm20.launcher2.themes.colors
import de.mm20.launcher2.database.entities.ColorsEntity
import de.mm20.launcher2.serialization.ColorIntAsHexSerializer
@@ -0,0 +1,102 @@
package de.mm20.launcher2.themes.colors
import android.content.Context
import de.mm20.launcher2.database.AppDatabase
import de.mm20.launcher2.themes.BlackAndWhiteThemeId
import de.mm20.launcher2.themes.DefaultThemeId
import de.mm20.launcher2.themes.HighContrastThemeId
import de.mm20.launcher2.themes.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.util.UUID
class ColorsRepository(
private val context: Context,
private val database: AppDatabase,
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
fun getAll(): Flow<List<Colors>> {
return database.themeDao().getAllColors().map {
getBuiltIn() + it.map { Colors(it) }
}
}
fun get(id: UUID): Flow<Colors?> {
if (id == DefaultThemeId) return flowOf(default)
if (id == HighContrastThemeId) return flowOf(highContrast)
if (id == BlackAndWhiteThemeId) return flowOf(blackAndWhite)
return database.themeDao().getColors(id).map { it?.let { Colors(it) } }
.flowOn(Dispatchers.Default)
}
fun create(colors: Colors) {
scope.launch {
database.themeDao().insertColors(colors.toEntity())
}
}
fun update(colors: Colors) {
scope.launch {
database.themeDao().updateColors(colors.toEntity())
}
}
fun delete(colors: Colors) {
scope.launch {
database.themeDao().deleteColors(colors.id)
}
}
fun getOrDefault(id: UUID?): Flow<Colors> {
if (id == null) return flowOf(default)
return get(id).map { it ?: default }
}
private fun getBuiltIn(): List<Colors> {
return listOf(
default,
highContrast,
blackAndWhite,
)
}
private val default: Colors
get() = Colors(
id = DefaultThemeId,
builtIn = true,
name = context.getString(R.string.preference_colors_default),
corePalette = EmptyCorePalette,
lightColorScheme = DefaultLightColorScheme,
darkColorScheme = DefaultDarkColorScheme,
)
private val highContrast: Colors
get() = Colors(
id = HighContrastThemeId,
builtIn = true,
name = context.getString(R.string.preference_colors_high_contrast),
corePalette = EmptyCorePalette,
lightColorScheme = HighContrastLightColorScheme,
darkColorScheme = HighContrastDarkColorScheme,
)
private val blackAndWhite: Colors
get() = Colors(
id = BlackAndWhiteThemeId,
builtIn = true,
name = context.getString(R.string.preference_colors_bw),
corePalette = EmptyCorePalette,
lightColorScheme = BlackAndWhiteLightColorScheme,
darkColorScheme = BlackAndWhiteDarkColorScheme,
)
}
@@ -0,0 +1,235 @@
package de.mm20.launcher2.themes.colors
val DefaultLightColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 40),
onPrimary = ColorRef(CorePaletteColor.Primary, 100),
primaryContainer = ColorRef(CorePaletteColor.Primary, 90),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 30),
secondary = ColorRef(CorePaletteColor.Secondary, 40),
onSecondary = ColorRef(CorePaletteColor.Secondary, 100),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 90),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 30),
tertiary = ColorRef(CorePaletteColor.Tertiary, 40),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 100),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 90),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 30),
error = ColorRef(CorePaletteColor.Error, 40),
onError = ColorRef(CorePaletteColor.Error, 100),
errorContainer = ColorRef(CorePaletteColor.Error, 90),
onErrorContainer = ColorRef(CorePaletteColor.Error, 30),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 87),
surface = ColorRef(CorePaletteColor.Neutral, 98),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 98),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 100),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 96),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 94),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 92),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 90),
onSurface = ColorRef(CorePaletteColor.Neutral, 10),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
outline = ColorRef(CorePaletteColor.NeutralVariant, 50),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 80),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 20),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 95),
inversePrimary = ColorRef(CorePaletteColor.Primary, 80),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 90),
surfaceTint = ColorRef(CorePaletteColor.Primary, 40),
background = ColorRef(CorePaletteColor.Neutral, 98),
onBackground = ColorRef(CorePaletteColor.Neutral, 10),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val DefaultDarkColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 80),
onPrimary = ColorRef(CorePaletteColor.Primary, 20),
primaryContainer = ColorRef(CorePaletteColor.Primary, 30),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 90),
secondary = ColorRef(CorePaletteColor.Secondary, 80),
onSecondary = ColorRef(CorePaletteColor.Secondary, 20),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 30),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 90),
tertiary = ColorRef(CorePaletteColor.Tertiary, 80),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 20),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 30),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 90),
error = ColorRef(CorePaletteColor.Error, 80),
onError = ColorRef(CorePaletteColor.Error, 20),
errorContainer = ColorRef(CorePaletteColor.Error, 30),
onErrorContainer = ColorRef(CorePaletteColor.Error, 90),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 6),
surface = ColorRef(CorePaletteColor.Neutral, 6),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 24),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 4),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 10),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 12),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 17),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 22),
onSurface = ColorRef(CorePaletteColor.Neutral, 90),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 80),
outline = ColorRef(CorePaletteColor.NeutralVariant, 60),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 90),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 20),
inversePrimary = ColorRef(CorePaletteColor.Primary, 40),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
surfaceTint = ColorRef(CorePaletteColor.Primary, 80),
background = ColorRef(CorePaletteColor.Neutral, 6),
onBackground = ColorRef(CorePaletteColor.Neutral, 90),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val HighContrastLightColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 20),
onPrimary = ColorRef(CorePaletteColor.Primary, 100),
primaryContainer = ColorRef(CorePaletteColor.Primary, 30),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 100),
secondary = ColorRef(CorePaletteColor.Secondary, 20),
onSecondary = ColorRef(CorePaletteColor.Secondary, 100),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 30),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 100),
tertiary = ColorRef(CorePaletteColor.Tertiary, 20),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 100),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 30),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 100),
error = ColorRef(CorePaletteColor.Error, 20),
onError = ColorRef(CorePaletteColor.Error, 100),
errorContainer = ColorRef(CorePaletteColor.Error, 30),
onErrorContainer = ColorRef(CorePaletteColor.Error, 100),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 87),
surface = ColorRef(CorePaletteColor.Neutral, 98),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 98),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 100),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 96),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 94),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 92),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 90),
onSurface = ColorRef(CorePaletteColor.Neutral, 0),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 0),
outline = ColorRef(CorePaletteColor.NeutralVariant, 20),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 20),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 100),
inversePrimary = ColorRef(CorePaletteColor.Primary, 80),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 90),
surfaceTint = ColorRef(CorePaletteColor.Primary, 20),
background = ColorRef(CorePaletteColor.Neutral, 98),
onBackground = ColorRef(CorePaletteColor.Neutral, 0),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val HighContrastDarkColorScheme = ColorScheme<Color>(
primary = ColorRef(CorePaletteColor.Primary, 95),
onPrimary = ColorRef(CorePaletteColor.Primary, 0),
primaryContainer = ColorRef(CorePaletteColor.Primary, 80),
onPrimaryContainer = ColorRef(CorePaletteColor.Primary, 0),
secondary = ColorRef(CorePaletteColor.Secondary, 95),
onSecondary = ColorRef(CorePaletteColor.Secondary, 0),
secondaryContainer = ColorRef(CorePaletteColor.Secondary, 80),
onSecondaryContainer = ColorRef(CorePaletteColor.Secondary, 0),
tertiary = ColorRef(CorePaletteColor.Tertiary, 95),
onTertiary = ColorRef(CorePaletteColor.Tertiary, 0),
tertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 80),
onTertiaryContainer = ColorRef(CorePaletteColor.Tertiary, 0),
error = ColorRef(CorePaletteColor.Error, 95),
onError = ColorRef(CorePaletteColor.Error, 0),
errorContainer = ColorRef(CorePaletteColor.Error, 80),
onErrorContainer = ColorRef(CorePaletteColor.Error, 0),
surfaceDim = ColorRef(CorePaletteColor.Neutral, 6),
surface = ColorRef(CorePaletteColor.Neutral, 6),
surfaceBright = ColorRef(CorePaletteColor.Neutral, 24),
surfaceContainerLowest = ColorRef(CorePaletteColor.Neutral, 4),
surfaceContainerLow = ColorRef(CorePaletteColor.Neutral, 10),
surfaceContainer = ColorRef(CorePaletteColor.Neutral, 12),
surfaceContainerHigh = ColorRef(CorePaletteColor.Neutral, 17),
surfaceContainerHighest = ColorRef(CorePaletteColor.Neutral, 22),
onSurface = ColorRef(CorePaletteColor.Neutral, 100),
onSurfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 100),
outline = ColorRef(CorePaletteColor.NeutralVariant, 95),
outlineVariant = ColorRef(CorePaletteColor.NeutralVariant, 80),
inverseSurface = ColorRef(CorePaletteColor.Neutral, 90),
inverseOnSurface = ColorRef(CorePaletteColor.Neutral, 0),
inversePrimary = ColorRef(CorePaletteColor.Primary, 20),
surfaceVariant = ColorRef(CorePaletteColor.NeutralVariant, 30),
surfaceTint = ColorRef(CorePaletteColor.Primary, 95),
background = ColorRef(CorePaletteColor.Neutral, 6),
onBackground = ColorRef(CorePaletteColor.Neutral, 100),
scrim = ColorRef(CorePaletteColor.Neutral, 0),
)
val BlackAndWhiteLightColorScheme = ColorScheme<Color?>(
primary = StaticColor(0xFF000000.toInt()),
onPrimary = StaticColor(0xFFFFFFFF.toInt()),
primaryContainer = StaticColor(0xFFFFFFFF.toInt()),
onPrimaryContainer = StaticColor(0xFF000000.toInt()),
inversePrimary = StaticColor(0xFFFFFFFF.toInt()),
secondary = StaticColor(0xFF000000.toInt()),
onSecondary = StaticColor(0xFFFFFFFF.toInt()),
secondaryContainer = StaticColor(0xFFFFFFFF.toInt()),
onSecondaryContainer = StaticColor(0xFF000000.toInt()),
tertiary = StaticColor(0xFF000000.toInt()),
onTertiary = StaticColor(0xFFFFFFFF.toInt()),
tertiaryContainer = StaticColor(0xFFFFFFFF.toInt()),
onTertiaryContainer = StaticColor(0xFF000000.toInt()),
background = StaticColor(0xFFFFFFFF.toInt()),
onBackground = StaticColor(0xFF000000.toInt()),
surface = StaticColor(0xFFFFFFFF.toInt()),
onSurface = StaticColor(0xFF000000.toInt()),
surfaceVariant = StaticColor(0xFFFFFFFF.toInt()),
onSurfaceVariant = StaticColor(0xFF000000.toInt()),
inverseSurface = StaticColor(0xFF000000.toInt()),
inverseOnSurface = StaticColor(0xFFFFFFFF.toInt()),
error = null,
onError = null,
errorContainer = null,
onErrorContainer = null,
outline = StaticColor(0xFF000000.toInt()),
surfaceTint = StaticColor(0xFFFFFFFF.toInt()),
outlineVariant = StaticColor(0xFF000000.toInt()),
scrim = StaticColor(0xFF000000.toInt()),
surfaceDim = StaticColor(0xFFFFFFFF.toInt()),
surfaceBright = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainer = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerHigh = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerHighest = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerLow = StaticColor(0xFFFFFFFF.toInt()),
surfaceContainerLowest = StaticColor(0xFFFFFFFF.toInt()),
)
val BlackAndWhiteDarkColorScheme = ColorScheme<Color?>(
primary = StaticColor(0xFFFFFFFF.toInt()),
onPrimary = StaticColor(0xFF000000.toInt()),
primaryContainer = StaticColor(0xFF000000.toInt()),
onPrimaryContainer = StaticColor(0xFFFFFFFF.toInt()),
inversePrimary = StaticColor(0xFF000000.toInt()),
secondary = StaticColor(0xFFFFFFFF.toInt()),
onSecondary = StaticColor(0xFF000000.toInt()),
secondaryContainer = StaticColor(0xFF000000.toInt()),
onSecondaryContainer = StaticColor(0xFFFFFFFF.toInt()),
tertiary = StaticColor(0xFFFFFFFF.toInt()),
onTertiary = StaticColor(0xFF000000.toInt()),
tertiaryContainer = StaticColor(0xFF000000.toInt()),
onTertiaryContainer = StaticColor(0xFFFFFFFF.toInt()),
background = StaticColor(0xFF000000.toInt()),
onBackground = StaticColor(0xFFFFFFFF.toInt()),
surface = StaticColor(0xFF000000.toInt()),
onSurface = StaticColor(0xFFFFFFFF.toInt()),
surfaceVariant = StaticColor(0xFF000000.toInt()),
onSurfaceVariant = StaticColor(0xFFFFFFFF.toInt()),
inverseSurface = StaticColor(0xFFFFFFFF.toInt()),
inverseOnSurface = StaticColor(0xFF000000.toInt()),
error = null,
onError = null,
errorContainer = null,
onErrorContainer = null,
outline = StaticColor(0xFFFFFFFF.toInt()),
surfaceTint = StaticColor(0xFFFFFFFF.toInt()),
outlineVariant = StaticColor(0xFFFFFFFF.toInt()),
scrim = StaticColor(0xFFFFFFFF.toInt()),
surfaceDim = StaticColor(0xFF000000.toInt()),
surfaceBright = StaticColor(0xFF000000.toInt()),
surfaceContainer = StaticColor(0xFF000000.toInt()),
surfaceContainerHigh = StaticColor(0xFF000000.toInt()),
surfaceContainerHighest = StaticColor(0xFF000000.toInt()),
surfaceContainerLow = StaticColor(0xFF000000.toInt()),
surfaceContainerLowest = StaticColor(0xFF000000.toInt()),
)
@@ -1,7 +1,8 @@
package de.mm20.launcher2.themes
package de.mm20.launcher2.themes.shapes
import de.mm20.launcher2.database.entities.ShapesEntity
import de.mm20.launcher2.serialization.UUIDSerializer
import de.mm20.launcher2.themes.ShapeSerializer
import kotlinx.serialization.Serializable
import java.util.UUID
@@ -0,0 +1,129 @@
package de.mm20.launcher2.themes.shapes
import android.content.Context
import de.mm20.launcher2.database.AppDatabase
import de.mm20.launcher2.themes.CutShapesId
import de.mm20.launcher2.themes.DefaultThemeId
import de.mm20.launcher2.themes.ExtraRoundShapesId
import de.mm20.launcher2.themes.R
import de.mm20.launcher2.themes.RectShapesId
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.util.UUID
class ShapesRepository(
private val context: Context,
private val database: AppDatabase,
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
fun getAll(): Flow<List<Shapes>> {
return database.themeDao().getAllShapes().map {
getBuiltIn() + it.map { Shapes(it) }
}
}
fun get(id: UUID): Flow<Shapes?> {
if (id == DefaultThemeId) return flowOf(default)
if (id == ExtraRoundShapesId) return flowOf(extraRound)
if (id == RectShapesId) return flowOf(rect)
if (id == CutShapesId) return flowOf(cut)
return database.themeDao().getShapes(id).map { it?.let { Shapes(it) } }
.flowOn(Dispatchers.Default)
}
fun create(shapes: Shapes) {
scope.launch {
database.themeDao().insertShapes(shapes.toEntity())
}
}
fun update(shapes: Shapes) {
scope.launch {
database.themeDao().updateShapes(shapes.toEntity())
}
}
fun delete(shapes: Shapes) {
scope.launch {
database.themeDao().deleteShapes(shapes.id)
}
}
fun getOrDefault(id: UUID?): Flow<Shapes> {
if (id == null) return flowOf(default)
return get(id).map { it ?: default }
}
private fun getBuiltIn(): List<Shapes> {
return listOf(
default,
extraRound,
rect,
cut,
)
}
private val default: Shapes
get() = Shapes(
id = DefaultThemeId,
builtIn = true,
name = context.getString(R.string.preference_shapes_default),
baseShape = Shape(
corners = CornerStyle.Rounded,
radii = intArrayOf(12, 12, 12, 12),
)
)
private val cut: Shapes
get() = Shapes(
id = CutShapesId,
builtIn = true,
name = context.getString(R.string.preference_cards_shape_cut),
baseShape = Shape(
corners = CornerStyle.Cut,
radii = intArrayOf(12, 12, 12, 12),
)
)
private val extraRound: Shapes
get() = Shapes(
id = ExtraRoundShapesId,
builtIn = true,
name = context.getString(R.string.preference_shapes_extra_round),
baseShape = Shape(
corners = CornerStyle.Rounded,
radii = intArrayOf(24, 24, 24, 24),
),
extraSmall = Shape(
radii = intArrayOf(4, 4, 4, 4),
),
extraLarge = Shape(
radii = intArrayOf(36, 36, 36, 36),
),
extraLargeIncreased = Shape(
radii = intArrayOf(40, 40, 40, 40),
),
extraExtraLarge = Shape(
radii = intArrayOf(56, 56, 56, 56),
)
)
private val rect: Shapes
get() = Shapes(
id = RectShapesId,
builtIn = true,
name = context.getString(R.string.preference_shapes_rect),
baseShape = Shape(
corners = CornerStyle.Rounded,
radii = intArrayOf(0, 0, 0, 0),
)
)
}
@@ -0,0 +1,35 @@
package de.mm20.launcher2.themes.transparencies
import de.mm20.launcher2.database.entities.TransparenciesEntity
import de.mm20.launcher2.serialization.UUIDSerializer
import kotlinx.serialization.Serializable
import java.util.UUID
@Serializable
data class Transparencies(
@Serializable(with = UUIDSerializer::class) val id: UUID = UUID.randomUUID(),
val builtIn: Boolean = false,
val name: String,
val background: Float? = null,
val surface: Float? = null,
val elevatedSurface: Float? = null,
) {
constructor(entity: TransparenciesEntity) : this(
id = entity.id,
builtIn = false,
name = entity.name,
background = entity.background,
surface = entity.surface,
elevatedSurface = entity.elevatedSurface,
)
internal fun toEntity(): TransparenciesEntity {
return TransparenciesEntity(
id = id,
name = name,
background = background,
surface = surface,
elevatedSurface = elevatedSurface,
)
}
}
@@ -0,0 +1,87 @@
package de.mm20.launcher2.themes.transparencies
import android.content.Context
import de.mm20.launcher2.database.AppDatabase
import de.mm20.launcher2.themes.DefaultThemeId
import de.mm20.launcher2.themes.R
import de.mm20.launcher2.themes.SemiTransparentId
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.util.UUID
class TransparenciesRepository(
private val context: Context,
private val database: AppDatabase,
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
fun getAll(): Flow<List<Transparencies>> {
return database.themeDao().getAllTransparencies().map {
getBuiltIn() + it.map { Transparencies(it) }
}
}
fun get(id: UUID): Flow<Transparencies?> {
if (id == DefaultThemeId) return flowOf(default)
if (id == SemiTransparentId) return flowOf(semiTransparent)
return database.themeDao().getTransparencies(id).map { it?.let { Transparencies(it) } }
}
fun create(transparencies: Transparencies) {
scope.launch {
database.themeDao().insertTransparencies(transparencies.toEntity())
}
}
fun update(transparencies: Transparencies) {
scope.launch {
database.themeDao().updateTransparencies(transparencies.toEntity())
}
}
fun delete(transparencies: Transparencies) {
scope.launch {
database.themeDao().deleteTransparencies(transparencies.id)
}
}
fun getOrDefault(id: UUID?): Flow<Transparencies> {
if (id == null) return flowOf(default)
return get(id).map { it ?: default }
}
private fun getBuiltIn(): List<Transparencies> {
return listOf(
default,
semiTransparent,
)
}
private val default: Transparencies
get() = Transparencies(
id = DefaultThemeId,
builtIn = true,
name = context.getString(R.string.preference_transparencies_default),
background = 0.85f,
surface = 1f,
elevatedSurface = 1f,
)
private val semiTransparent: Transparencies
get() = Transparencies(
id = SemiTransparentId,
builtIn = true,
name = context.getString(R.string.preference_transparencies_semi_transparent),
background = 0.40f,
surface = 0.65f,
elevatedSurface = 0.85f,
)
}