EARHORNMUSIC UPnP · Android TV · Phones · Android Auto · GNU/Linux
Release 0.5.0

StaveTheme.kt

package dev.stave.ui.theme

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Shapes
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

/**
 * Desktop + mobile version of StaveTheme. Uses standard compose.material3 so it renders
 * on Compose Multiplatform Desktop and on Android non-TV.
 *
 * Android TV flavor has its own StaveTheme wrapper around androidx.tv.material3.
 */
private val StaveColorScheme = darkColorScheme(
    primary = AccentAmber,
    onPrimary = OnAmber,
    primaryContainer = AccentAmberSoft,
    onPrimaryContainer = OnPrimary,

    secondary = AccentSage,
    onSecondary = SurfaceBase,
    secondaryContainer = SurfaceHover,
    onSecondaryContainer = OnPrimary,

    tertiary = AccentRose,
    onTertiary = SurfaceBase,
    tertiaryContainer = AccentRoseSoft,
    onTertiaryContainer = OnPrimary,

    background = SurfaceBase,
    onBackground = OnPrimary,

    surface = SurfaceBase,
    onSurface = OnPrimary,
    surfaceVariant = SurfaceRaised,
    onSurfaceVariant = OnMuted,

    // outline is an input boundary (text fields, checkbox/radio, outlined
    // buttons, slider track) and needs 3:1; outlineVariant stays the
    // decorative divider.
    outline = OutlineStrong,
    outlineVariant = SurfaceDivider,

    // Every slot below was left to darkColorScheme()'s Material baseline,
    // which is purple-grey (#211F26 / #2B2930), a lavender inverse surface and
    // a pink error. Material3 1.2+ draws DropdownMenu on surfaceContainer,
    // AlertDialog on surfaceContainerHigh and Snackbar on inverseSurface, so
    // menus, dialogs and every toast came out lavender on a warm-brown app.
    surfaceContainerLowest = SurfaceLowest,
    surfaceContainerLow = SurfaceBase,
    surfaceContainer = SurfaceRaised,
    surfaceContainerHigh = SurfaceHover,
    surfaceContainerHighest = SurfaceHighest,
    surfaceBright = SurfaceBright,
    surfaceDim = SurfaceBase,
    surfaceTint = AccentAmber,

    inverseSurface = OnPrimary,
    inverseOnSurface = SurfaceBase,
    inversePrimary = Color(0xFF8A5A14), // 4.81:1 on the inverse surface

    error = AccentRose,
    onError = SurfaceBase,
    errorContainer = AccentRoseSoft,
    onErrorContainer = OnPrimary,

    scrim = Color.Black,
)

val StaveShapes = Shapes(
    extraSmall = RoundedCornerShape(4.dp),
    small = RoundedCornerShape(8.dp),
    medium = RoundedCornerShape(12.dp),
    large = RoundedCornerShape(20.dp),
    extraLarge = RoundedCornerShape(28.dp),
)

@Composable
fun StaveTheme(
    typography: androidx.compose.material3.Typography = StaveTypography,
    content: @Composable () -> Unit,
) {
    MaterialTheme(
        colorScheme = StaveColorScheme,
        typography = typography,
        shapes = StaveShapes,
        content = content,
    )
}