OXYGENHUB
# 263c6cad5e51 oxygenhub-android / app / src / main / java / io / oxygenhub / android / ui / theme / Theme.kt
4.0 KiB · last changed A home screen widget: latest runs, unread, reviews waiting (closes #28) 7 days ago source blame history raw
1
package io.oxygenhub.android.ui.theme
2
3
import androidx.compose.foundation.isSystemInDarkTheme
4
import androidx.compose.material3.ColorScheme
5
import androidx.compose.material3.MaterialTheme
6
import androidx.compose.material3.darkColorScheme
7
import androidx.compose.material3.dynamicDarkColorScheme
8
import androidx.compose.material3.dynamicLightColorScheme
9
import androidx.compose.material3.lightColorScheme
10
import androidx.compose.runtime.Composable
11
import androidx.compose.runtime.Immutable
12
import androidx.compose.runtime.staticCompositionLocalOf
13
import androidx.compose.ui.graphics.Color
14
import androidx.compose.ui.graphics.lerp
15
import androidx.compose.ui.platform.LocalContext
16
17
internal val DarkColorScheme = darkColorScheme(
18
    primary = DarkAccent,
19
    onPrimary = DarkBackground,
20
    primaryContainer = DarkBand,
21
    onPrimaryContainer = Color.White,
22
    secondary = DarkAccent2,
23
    onSecondary = Color.White,
24
    secondaryContainer = DarkSelected,
25
    onSecondaryContainer = DarkInk,
26
    tertiary = DarkWarn,
27
    background = DarkBackground,
28
    onBackground = DarkInk,
29
    surface = DarkBackground,
30
    onSurface = DarkInk,
31
    surfaceVariant = DarkSurfaceSoft,
32
    onSurfaceVariant = DarkMute,
33
    surfaceContainerLowest = DarkBackground,
34
    surfaceContainerLow = DarkPanel,
35
    surfaceContainer = DarkPanelMid,
36
    surfaceContainerHigh = DarkPanelHigh,
37
    surfaceContainerHighest = DarkPanelHighest,
38
    outline = DarkMute,
39
    outlineVariant = DarkEdge,
40
    error = DarkBad,
41
)
42
43
internal val LightColorScheme = lightColorScheme(
44
    primary = LightAccent,
45
    onPrimary = Color.White,
46
    primaryContainer = LightBand,
47
    onPrimaryContainer = Color.White,
48
    secondary = LightAccent2,
49
    onSecondary = Color.White,
50
    secondaryContainer = LightSelected,
51
    onSecondaryContainer = LightInk,
52
    tertiary = LightWarn,
53
    background = LightBackground,
54
    onBackground = LightInk,
55
    surface = LightBackground,
56
    onSurface = LightInk,
57
    surfaceVariant = LightSurfaceSoft,
58
    onSurfaceVariant = LightMute,
59
    surfaceContainerLowest = LightSurface,
60
    surfaceContainerLow = LightSurface,
61
    surfaceContainer = LightSurface,
62
    surfaceContainerHigh = LightSurfaceSoft,
63
    surfaceContainerHighest = LightSurfaceSoft,
64
    outline = LightMute,
65
    outlineVariant = LightLine,
66
    error = LightBad,
67
)
68
69
/** Colours Material has no slot for: an open or closed state. */
70
@Immutable
71
data class StatusColors(val ok: Color, val bad: Color, val warn: Color)
72
73
val LocalStatusColors = staticCompositionLocalOf { StatusColors(LightOk, LightBad, LightWarn) }
74
75
/**
76
 * Wallpaper colours in the dark, with containers lifted off the background
77
 * (#24): Android's dark tones sit a shade apart, which a phone's screen hardly
78
 * shows. Each container a clear step up, and edges brighter than the default.
79
 */
80
internal fun lifted(scheme: ColorScheme): ColorScheme {
81
    val step = { f: Float -> lerp(scheme.background, scheme.onSurface, f) }
82
    return scheme.copy(
83
        surfaceContainerLow = step(0.06f),
84
        surfaceContainer = step(0.09f),
85
        surfaceContainerHigh = step(0.12f),
86
        surfaceContainerHighest = step(0.15f),
87
        outlineVariant = step(0.26f),
88
    )
89
}
90
91
@Composable
92
fun OxygenHubTheme(
93
    darkTheme: Boolean = isSystemInDarkTheme(),
94
    // The hub's own palette, unless Account's "Wallpaper colours" is on (#24).
95
    dynamicColor: Boolean = rememberWallpaperColours(),
96
    content: @Composable () -> Unit,
97
) {
98
    val colorScheme: ColorScheme = when {
99
        dynamicColor -> {
100
            val context = LocalContext.current
101
            if (darkTheme) lifted(dynamicDarkColorScheme(context)) else dynamicLightColorScheme(context)
102
        }
103
        darkTheme -> DarkColorScheme
104
        else -> LightColorScheme
105
    }
106
    val status = if (darkTheme) StatusColors(DarkOk, DarkBad, DarkWarn) else StatusColors(LightOk, LightBad, LightWarn)
107
    androidx.compose.runtime.CompositionLocalProvider(LocalStatusColors provides status) {
108
        MaterialTheme(colorScheme = colorScheme, typography = Typography, content = content)
109
    }
110
}