From 0e16019ef2be82145497b8de0f9cde29e8b198d2 Mon Sep 17 00:00:00 2001 From: gthgomez Date: Thu, 8 Oct 2026 14:44:09 -0500 Subject: [PATCH] feat(ui): ring-gradient titles and borders across guide + More Controls surfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rememberRingBrush() helper: remembered vertical brush over the ring gradient stops - Connection guide: dialog title, step titles, and Saved-TVs title render with the ring gradient; pending step cards and the Saved panel get ring-gradient hairline borders (completed steps keep status green); functional text (step bodies, device list, TV-connection chip) stays white/neutral - More Controls: affordance label + chevron, sheet title, and the Apps/Settings/watch pills (GlassPill) use the ring gradient for text and borders - Dock/rail glyphs already gradient from PR13 ./gradlew :app:assembleDebug :app:testDebugUnitTest — pass --- .../java/com/rgremote/app/ui/HaloScreen.kt | 7 +++++-- .../com/rgremote/app/ui/MoreControlsSheet.kt | 13 +++++++------ .../java/com/rgremote/app/ui/RGRemoteApp.kt | 18 ++++++++++++------ .../com/rgremote/app/ui/theme/HaloColors.kt | 10 ++++++++++ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/rgremote/app/ui/HaloScreen.kt b/app/src/main/java/com/rgremote/app/ui/HaloScreen.kt index 7932c5f..48052f3 100644 --- a/app/src/main/java/com/rgremote/app/ui/HaloScreen.kt +++ b/app/src/main/java/com/rgremote/app/ui/HaloScreen.kt @@ -65,6 +65,7 @@ import com.rgremote.app.ui.ringGradientFill import com.rgremote.app.ui.theme.HaloColors import com.rgremote.app.ui.theme.HaloSpec import com.rgremote.app.ui.theme.ringGradientColors +import com.rgremote.app.ui.theme.rememberRingBrush import com.rgremote.app.ui.theme.LocalHaloColors /** @@ -482,6 +483,7 @@ private fun MoreControlsAffordance( onClick: () -> Unit, ) { val halo = LocalHaloColors.current + val ringBrush = rememberRingBrush() Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier @@ -510,13 +512,14 @@ private fun MoreControlsAffordance( Icon( imageVector = Icons.Filled.KeyboardArrowUp, contentDescription = null, - tint = halo.moreControls + tint = Color.White, + modifier = Modifier.ringGradientFill(halo.ringGradientColors()) ) } Spacer(Modifier.height(6.dp)) Text( text = stringResource(R.string.halo_more_controls), - color = halo.moreControls, + style = MaterialTheme.typography.labelSmall.copy(brush = ringBrush), fontSize = 11.sp, letterSpacing = 2.sp ) diff --git a/app/src/main/java/com/rgremote/app/ui/MoreControlsSheet.kt b/app/src/main/java/com/rgremote/app/ui/MoreControlsSheet.kt index 455731f..362d49b 100644 --- a/app/src/main/java/com/rgremote/app/ui/MoreControlsSheet.kt +++ b/app/src/main/java/com/rgremote/app/ui/MoreControlsSheet.kt @@ -40,6 +40,7 @@ import com.rgremote.app.domain.AppLaunchTarget import com.rgremote.app.domain.HdmiPort import com.rgremote.app.domain.VolumeCommand import com.rgremote.app.ui.theme.HaloSpec +import com.rgremote.app.ui.theme.rememberRingBrush import com.rgremote.app.ui.theme.LocalHaloColors /** @@ -73,6 +74,7 @@ internal fun MoreControlsSheet( onDismiss: () -> Unit, ) { val halo = LocalHaloColors.current + val ringBrush = rememberRingBrush() ModalBottomSheet( onDismissRequest = onDismiss, containerColor = MaterialTheme.colorScheme.surface @@ -87,8 +89,7 @@ internal fun MoreControlsSheet( ) { Text( text = stringResource(R.string.halo_more_controls), - style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.titleMedium.copy(brush = ringBrush), modifier = Modifier .fillMaxWidth() .padding(horizontal = 4.dp) @@ -237,7 +238,7 @@ private fun SheetSeparator() { ) } -/** Halo-styled text pill: glass fill, hairline border, dock-icon text. */ +/** Halo-styled text pill: glass fill, ring-gradient border and label. */ @Composable private fun GlassPill( label: String, @@ -245,19 +246,19 @@ private fun GlassPill( modifier: Modifier = Modifier, ) { val halo = LocalHaloColors.current + val ringBrush = rememberRingBrush() val shape = RoundedCornerShape(24.dp) Box( modifier = modifier .height(48.dp) .background(halo.dockFill, shape) - .border(1.dp, halo.dockBorder, shape) + .border(1.dp, ringBrush, shape) .clickable(onClickLabel = label, onClick = onClick), contentAlignment = Alignment.Center ) { Text( text = label, - color = halo.dockIcon, - fontSize = 15.sp, + style = MaterialTheme.typography.labelLarge.copy(brush = ringBrush), fontWeight = FontWeight.Medium ) } diff --git a/app/src/main/java/com/rgremote/app/ui/RGRemoteApp.kt b/app/src/main/java/com/rgremote/app/ui/RGRemoteApp.kt index 92245f9..5a7469c 100644 --- a/app/src/main/java/com/rgremote/app/ui/RGRemoteApp.kt +++ b/app/src/main/java/com/rgremote/app/ui/RGRemoteApp.kt @@ -106,6 +106,7 @@ import com.rgremote.app.domain.AppLaunchTarget import com.rgremote.app.domain.DeviceType import com.rgremote.app.roku.RokuPowerMode import com.rgremote.app.ui.theme.LocalHaloColors +import com.rgremote.app.ui.theme.rememberRingBrush import com.rgremote.app.ui.theme.ThemeMode import com.rgremote.app.domain.DpadDirection import com.rgremote.app.domain.duplicateDeviceCount @@ -695,6 +696,7 @@ private fun SetupGuideDialog( val googlePaired = google?.id?.let { state.pairedDeviceIds.contains(it) } == true val hdmiMapped = mappedPort != null val halo = LocalHaloColors.current + val ringBrush = rememberRingBrush() AlertDialog( onDismissRequest = onDismiss, confirmButton = { @@ -714,7 +716,10 @@ private fun SetupGuideDialog( } }, title = { - Text(stringResource(R.string.setup_guide_title)) + Text( + text = stringResource(R.string.setup_guide_title), + style = MaterialTheme.typography.titleLarge.copy(brush = ringBrush) + ) }, text = { Column( @@ -811,6 +816,7 @@ private fun GuideStep( accent: Color ) { val halo = LocalHaloColors.current + val ringBrush = rememberRingBrush() Surface( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(16.dp), @@ -822,7 +828,7 @@ private fun GuideStep( border = if (complete) { BorderStroke(0.5.dp, halo.statusOnline.copy(alpha = 0.30f)) } else { - null + BorderStroke(0.5.dp, ringBrush) } ) { Column( @@ -863,8 +869,7 @@ private fun GuideStep( } Text( text = title, - color = MaterialTheme.colorScheme.onSurface, - style = MaterialTheme.typography.titleSmall, + style = MaterialTheme.typography.titleSmall.copy(brush = ringBrush), fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f) ) @@ -882,11 +887,12 @@ private fun GuideStep( private fun SavedTvsSummary(state: RGRemoteUiState) { if (state.devices.isEmpty()) return val halo = LocalHaloColors.current + val ringBrush = rememberRingBrush() Surface( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(16.dp), color = halo.dockWell, - border = BorderStroke(0.5.dp, halo.chipBorder) + border = BorderStroke(0.5.dp, ringBrush) ) { Column( modifier = Modifier.padding(12.dp), @@ -894,7 +900,7 @@ private fun SavedTvsSummary(state: RGRemoteUiState) { ) { Text( text = stringResource(R.string.saved_summary_title), - style = MaterialTheme.typography.labelLarge, + style = MaterialTheme.typography.labelLarge.copy(brush = ringBrush), fontWeight = FontWeight.Bold, color = PrimaryText ) diff --git a/app/src/main/java/com/rgremote/app/ui/theme/HaloColors.kt b/app/src/main/java/com/rgremote/app/ui/theme/HaloColors.kt index b1fe5f1..84c4f9d 100644 --- a/app/src/main/java/com/rgremote/app/ui/theme/HaloColors.kt +++ b/app/src/main/java/com/rgremote/app/ui/theme/HaloColors.kt @@ -1,7 +1,10 @@ package com.rgremote.app.ui.theme +import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable +import androidx.compose.runtime.remember import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color /** @@ -126,6 +129,13 @@ fun HaloColors.ringGradientColors(): List = listOf( ringPink ) +/** Remembered vertical brush over the ring gradient, for text and borders. */ +@Composable +fun rememberRingBrush(): Brush { + val halo = LocalHaloColors.current + return remember(halo) { Brush.verticalGradient(halo.ringGradientColors()) } +} + /** * Measured geometry contract from `docs/ui-target.md`. Fractions are relative * to screen width (ring) or parent size (the rest); components must consume