wip: glass theme tokens + demo page + charcoal base port
This commit is contained in:
parent
a99d4c43f4
commit
6628965e68
941 changed files with 1688 additions and 1160 deletions
|
|
@ -8,9 +8,11 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.rada.player.PlaybackManager
|
||||
import com.rada.ui.navigation.NavGraph
|
||||
import com.rada.ui.theme.GlassBackground
|
||||
import com.rada.ui.theme.RadAmpTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
|
@ -27,11 +29,13 @@ class MainActivity : ComponentActivity() {
|
|||
|
||||
setContent {
|
||||
RadAmpTheme {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background,
|
||||
) {
|
||||
NavGraph(navController = rememberNavController())
|
||||
GlassBackground {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = Color.Transparent,
|
||||
) {
|
||||
NavGraph(navController = rememberNavController())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,12 +196,12 @@ fun LibraryScreen(
|
|||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -213,7 +213,7 @@ fun LibraryScreen(
|
|||
selectedTabIndex = selectedTabIndex,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
edgePadding = 16.dp,
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = PremiumPurple,
|
||||
indicator = { tabPositions ->
|
||||
if (selectedTabIndex < tabPositions.size) {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@ import androidx.compose.animation.AnimatedVisibility
|
|||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
|
|
@ -15,7 +19,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MusicNote
|
||||
import androidx.compose.material.icons.filled.Radio
|
||||
import androidx.compose.material.icons.filled.Pause
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material3.Icon
|
||||
|
|
@ -30,14 +34,15 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.rada.player.PlaybackManager
|
||||
import com.rada.ui.theme.PremiumBorder
|
||||
import com.rada.ui.theme.PremiumPurple
|
||||
import com.rada.ui.theme.PremiumSurface
|
||||
import com.rada.ui.theme.RadAmpGlass
|
||||
import com.rada.ui.theme.PremiumText
|
||||
import com.rada.ui.theme.PremiumTextSecondary
|
||||
|
||||
|
|
@ -59,7 +64,12 @@ fun NowPlayingBar(
|
|||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(PremiumSurface)
|
||||
.padding(horizontal = 12.dp)
|
||||
.clip(RoundedCornerShape(RadAmpGlass.rCard))
|
||||
// glass: textSafe 90% overlay + 6% white + highlight border
|
||||
.background(RadAmpGlass.textSafe)
|
||||
.background(RadAmpGlass.surface)
|
||||
.border(1.dp, RadAmpGlass.border, RoundedCornerShape(RadAmpGlass.rCard))
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
|
|
@ -86,12 +96,21 @@ fun NowPlayingBar(
|
|||
.padding(start = 12.dp, end = 4.dp, top = 10.dp, bottom = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.MusicNote,
|
||||
contentDescription = null,
|
||||
tint = PremiumPurple,
|
||||
modifier = Modifier.size(22.dp),
|
||||
)
|
||||
// violet icon chip (glass hero element)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(PremiumPurple),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Radio,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(24.dp),
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -191,10 +191,11 @@ fun PlayerScreen(
|
|||
}
|
||||
|
||||
Scaffold(
|
||||
containerColor = Color.Transparent,
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
bottomBar = {
|
||||
BottomAppBar(
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
containerColor = PremiumSurface.copy(alpha = 0.94f),
|
||||
contentColor = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
NavigationBarItem(
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
|
@ -151,12 +152,12 @@ fun PlaylistManagerScreen(
|
|||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -130,11 +131,11 @@ fun StationBrowserScreen(
|
|||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
)
|
||||
},
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -117,11 +117,11 @@ fun StreamsScreen(
|
|||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
),
|
||||
)
|
||||
},
|
||||
containerColor = MaterialTheme.colorScheme.background,
|
||||
containerColor = Color.Transparent,
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -2,31 +2,45 @@ package com.rada.ui.theme
|
|||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
// ── Premium dark palette ──
|
||||
val PremiumBlack = Color(0xFF0A0A14)
|
||||
val PremiumDark = Color(0xFF12121E)
|
||||
val PremiumSurface = Color(0xFF1A1A2E)
|
||||
val PremiumSurfaceVariant = Color(0xFF222238)
|
||||
val PremiumBorder = Color(0xFF2A2A44)
|
||||
// ── RadAmp Glass palette (see design/glass-radio-theme.css for tokens + WCAG data) ──
|
||||
// Base: flat dark charcoal gradient #23232B → #1B1B22
|
||||
val PremiumBlack = Color(0xFF1B1B22) // base bottom
|
||||
val PremiumDark = Color(0xFF23232B) // base top
|
||||
val PremiumSurface = Color(0xFF202029) // solid panel (~90% opaque base)
|
||||
val PremiumSurfaceVariant = Color(0xFF262631)
|
||||
val PremiumBorder = Color(0x1AFFFFFF) // glass border 10% white (decorative)
|
||||
// Interactive borders need 3:1 (WCAG 1.4.11): 36% white over glass
|
||||
val PremiumBorderInteractive = Color(0x5CFFFFFF)
|
||||
|
||||
val PremiumPurple = Color(0xFF7C3AED)
|
||||
val PremiumPurple = Color(0xFF7C4DFF) // accent
|
||||
val PremiumPurpleHover = Color(0xFF8E66FF)
|
||||
val PremiumPurplePressed = Color(0xFF6A3DE0)
|
||||
val PremiumPurpleSoft = Color(0x297C4DFF) // accent soft fill 16% — chips/active
|
||||
val PremiumPurpleLight = Color(0xFFA78BFA)
|
||||
// AA-safe accent TEXT on glass (7C4DFF is only 2.71:1 on glass)
|
||||
val PremiumAccentText = Color(0xFFA78BFF)
|
||||
val PremiumBlue = Color(0xFF3B82F6)
|
||||
val PremiumCyan = Color(0xFF06B6D4)
|
||||
val PremiumPink = Color(0xFFEC4899)
|
||||
|
||||
val PremiumText = Color(0xFFF0F0F5)
|
||||
val PremiumTextSecondary = Color(0xFF9CA3AF)
|
||||
val PremiumTextMuted = Color(0xFF6B7280)
|
||||
// Text tokens: all pairs ≥4.5:1 on base AND on glass (measured; see demo page)
|
||||
val PremiumText = Color(0xFFFFFFFF) // 13.1:1 on glass
|
||||
val PremiumTextSecondary = Color(0xFFD9D9DE) // 10.5:1 on glass (body 88% white)
|
||||
val PremiumTextMuted = Color(0xFF8C8C96) // 5.1:1 on base (caption floor, never dimmer)
|
||||
|
||||
val PremiumSuccess = Color(0xFF10B981)
|
||||
val PremiumSuccess = Color(0xFF34C759)
|
||||
val PremiumError = Color(0xFFEF4444)
|
||||
val PremiumWarning = Color(0xFFF59E0B)
|
||||
|
||||
// Gradient colors for accents
|
||||
val GradientStart = Color(0xFF7C3AED)
|
||||
val GradientStart = Color(0xFF7C4DFF)
|
||||
val GradientMid = Color(0xFF3B82F6)
|
||||
val GradientEnd = Color(0xFF06B6D4)
|
||||
// Base background gradient (flat charcoal, very subtle)
|
||||
val BaseTop = Color(0xFF23232B)
|
||||
val BaseBottom = Color(0xFF1B1B22)
|
||||
// Live indicator
|
||||
val LiveGreen = Color(0xFF34C759)
|
||||
|
||||
// Legacy terminal palette (cliamp-inspired)
|
||||
val TerminalBlack = Color(0xFF000000)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
package com.rada.ui.theme
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
private val PremiumColorScheme = darkColorScheme(
|
||||
primary = PremiumPurple,
|
||||
onPrimary = Color.White,
|
||||
primaryContainer = PremiumPurple.copy(alpha = 0.15f),
|
||||
onPrimaryContainer = PremiumPurpleLight,
|
||||
onPrimary = Color.White, // 4.81:1 on #7C4DFF
|
||||
primaryContainer = PremiumPurpleSoft,
|
||||
onPrimaryContainer = PremiumAccentText, // AA-safe accent text on glass
|
||||
|
||||
secondary = PremiumBlue,
|
||||
onSecondary = Color.White,
|
||||
|
|
@ -22,12 +27,12 @@ private val PremiumColorScheme = darkColorScheme(
|
|||
tertiaryContainer = PremiumCyan.copy(alpha = 0.15f),
|
||||
onTertiaryContainer = PremiumCyan,
|
||||
|
||||
background = PremiumBlack,
|
||||
background = BaseBottom, // charcoal gradient bottom
|
||||
onBackground = PremiumText,
|
||||
|
||||
surface = PremiumDark,
|
||||
surface = PremiumDark, // base top
|
||||
onSurface = PremiumText,
|
||||
surfaceVariant = PremiumSurface,
|
||||
surfaceVariant = PremiumSurface, // solid panel
|
||||
onSurfaceVariant = PremiumTextSecondary,
|
||||
|
||||
error = PremiumError,
|
||||
|
|
@ -35,14 +40,46 @@ private val PremiumColorScheme = darkColorScheme(
|
|||
errorContainer = PremiumError.copy(alpha = 0.15f),
|
||||
onErrorContainer = PremiumError,
|
||||
|
||||
outline = PremiumBorder,
|
||||
outline = PremiumBorder, // decorative 10% white glass border
|
||||
outlineVariant = PremiumBorder.copy(alpha = 0.5f),
|
||||
inverseSurface = PremiumText,
|
||||
inverseOnSurface = PremiumBlack,
|
||||
inversePrimary = PremiumPurpleLight,
|
||||
inverseOnSurface = BaseBottom,
|
||||
inversePrimary = PremiumAccentText,
|
||||
surfaceTint = PremiumPurple,
|
||||
)
|
||||
|
||||
/**
|
||||
* RadAmp Glass tokens — mirrors design/glass-radio-theme.css.
|
||||
* Compose has no backdrop blur without a lib, so "glass" = translucent white
|
||||
* layer + inner highlight border over the charcoal base. Text never sits on
|
||||
* glass alone without the 90%-opaque overlay (GlassTextSafe).
|
||||
*/
|
||||
object RadAmpGlass {
|
||||
val bgGradient = Brush.verticalGradient(listOf(BaseTop, BaseBottom))
|
||||
// very subtle violet glows, painted under content, never behind text
|
||||
val glowTop = Brush.radialGradient(
|
||||
colors = listOf(PremiumPurple.copy(alpha = 0.14f), Color.Transparent),
|
||||
center = androidx.compose.ui.geometry.Offset(900f, 260f),
|
||||
radius = 900f,
|
||||
)
|
||||
val surface = Color(0x0FFFFFFF) // rgba(255,255,255,0.06)
|
||||
val surfaceStrong = Color(0x17FFFFFF) // hover 0.09
|
||||
val border = Color(0x1AFFFFFF) // 0.10 decorative
|
||||
val borderInteractive = Color(0x5CFFFFFF)// 0.36 → 3:1 on glass
|
||||
val highlight = Color(0x24FFFFFF) // inset top highlight 0.14
|
||||
val textSafe = Color(0xE61B1B22) // 90% opaque overlay behind text
|
||||
val rCard = 20.dp
|
||||
val rInput = 14.dp
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GlassBackground(content: @Composable () -> Unit) {
|
||||
Box(Modifier.fillMaxSize().background(RadAmpGlass.bgGradient)) {
|
||||
Box(Modifier.fillMaxSize().background(RadAmpGlass.glowTop))
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
object RadAmpGradients {
|
||||
val primary = Brush.linearGradient(
|
||||
colors = listOf(GradientStart, GradientMid, GradientEnd)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue