From 51e0479c293dba223671c8bc9f06d25e5f7daa82 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 16:11:31 +0000 Subject: [PATCH 01/14] feat: derive Material3 container colors from the selected accent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The accent-color setting only overrode primary/secondary/tertiary, leaving every Material3 *Container role (primaryContainer, secondaryContainer, tertiaryContainer and their on-colors), inversePrimary and surfaceTint at Material's baseline violet. Container-backed surfaces — settings icon boxes, selected reaction chips, zap-amount chips, calendar selection, relay-group top bars — therefore stayed purple no matter which accent was chosen. Complete the dark/light schemes so those roles are derived from the accent: containers are a faint accent tint composited over the base surface, on-colors are the accent (dark) or a deepened accent (light), and on-accent fills pick black/white by WCAG contrast (also fixing white-on-teal for the purple theme's bright secondary). Mobile app only. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 81 ++++++++++++++++--- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 3e1e26b70d..5d10ddd218 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -46,6 +46,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.compositeOver +import androidx.compose.ui.graphics.lerp +import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity @@ -93,25 +95,84 @@ private fun accentSecondary( dark: Boolean, ): Color = if (accent == AccentColorType.PURPLE) Teal200 else accentPrimary(accent, dark) -private fun darkColors(accent: AccentColorType) = - darkColorScheme( - primary = accentPrimary(accent, dark = true), - secondary = accentSecondary(accent, dark = true), - tertiary = accentSecondary(accent, dark = true), +// Black or white — whichever has the higher WCAG contrast ratio against a solid accent fill +// (primary/secondary/tertiary). Runs once per scheme build (not on a render path), so the +// luminance() cost is irrelevant here. Picks black on the light pastel accents used in the dark +// theme and on the purple theme's bright teal secondary, white on the deep accents used in light. +private fun onAccent(color: Color): Color { + val luminance = color.luminance() + val contrastOnBlack = (luminance + 0.05f) / 0.05f + val contrastOnWhite = 1.05f / (luminance + 0.05f) + return if (contrastOnBlack >= contrastOnWhite) Color.Black else Color.White +} + +// Faint accent-tinted fill for the Material3 "container" roles (primaryContainer, etc.), laid +// over the theme's base surface. Left unset, these roles fall back to Material's baseline violet, +// which is why container-backed UI (settings icon boxes, selected reaction chips, zap-amount +// chips, calendar selection, relay-group top bars) stayed purple under every accent. +private fun accentContainer( + color: Color, + surface: Color, + alpha: Float, +): Color = color.copy(alpha = alpha).compositeOver(surface) + +// Text/icon color drawn on an accentContainer. The container sits close to the base surface, so +// in the dark theme the light accent reads directly; in the light theme it is deepened toward +// black to stay legible on the pale tint. +private fun onAccentContainer( + color: Color, + dark: Boolean, +): Color = if (dark) color else lerp(color, Color.Black, 0.30f) + +private fun darkColors(accent: AccentColorType): ColorScheme { + val primary = accentPrimary(accent, dark = true) + val secondary = accentSecondary(accent, dark = true) + val surface = Color.Black + return darkColorScheme( + primary = primary, + onPrimary = onAccent(primary), + primaryContainer = accentContainer(primary, surface, 0.16f), + onPrimaryContainer = onAccentContainer(primary, dark = true), + secondary = secondary, + onSecondary = onAccent(secondary), + secondaryContainer = accentContainer(secondary, surface, 0.16f), + onSecondaryContainer = onAccentContainer(secondary, dark = true), + tertiary = secondary, + onTertiary = onAccent(secondary), + tertiaryContainer = accentContainer(secondary, surface, 0.16f), + onTertiaryContainer = onAccentContainer(secondary, dark = true), + inversePrimary = accentPrimary(accent, dark = false), + surfaceTint = primary, background = Color.Black, surface = Color.Black, surfaceDim = Color.Black, surfaceVariant = Color(red = 29, green = 26, blue = 34), ) +} -private fun lightColors(accent: AccentColorType) = - lightColorScheme( - primary = accentPrimary(accent, dark = false), - secondary = accentSecondary(accent, dark = false), - tertiary = accentSecondary(accent, dark = false), +private fun lightColors(accent: AccentColorType): ColorScheme { + val primary = accentPrimary(accent, dark = false) + val secondary = accentSecondary(accent, dark = false) + val surface = Color.White + return lightColorScheme( + primary = primary, + onPrimary = onAccent(primary), + primaryContainer = accentContainer(primary, surface, 0.12f), + onPrimaryContainer = onAccentContainer(primary, dark = false), + secondary = secondary, + onSecondary = onAccent(secondary), + secondaryContainer = accentContainer(secondary, surface, 0.12f), + onSecondaryContainer = onAccentContainer(secondary, dark = false), + tertiary = secondary, + onTertiary = onAccent(secondary), + tertiaryContainer = accentContainer(secondary, surface, 0.12f), + onTertiaryContainer = onAccentContainer(secondary, dark = false), + inversePrimary = accentPrimary(accent, dark = true), + surfaceTint = primary, surfaceContainerHighest = Color(red = 236, green = 230, blue = 240), surfaceVariant = Color(red = 250, green = 245, blue = 252), ) +} private val DarkColorPalette = darkColors(AccentColorType.PURPLE) private val LightColorPalette = lightColors(AccentColorType.PURPLE) From e9f0c601c276392bf1b08aa4f107bc7efa6065a8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 19:33:01 +0000 Subject: [PATCH 02/14] feat: make unread-dot and selected-reaction highlight follow the accent The new-item unread dot and the selected-reaction box were built from static Modifier vals whose fill was baked from the purple ColorPalette at class load, so they stayed purple under every accent. Split the color-free geometry into pre-built vals and apply the live scheme role (primary for the dot, secondaryContainer for the reaction box) in the getters, so both now track the selected accent. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 5d10ddd218..86c8cf0451 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -284,21 +284,14 @@ val LightMaxWidthWithBackground = .fillMaxWidth() .background(LightColorPalette.background) -val DarkSelectedReactionBoxModifier = +// Geometry only — no color. The fill is applied live from the scheme's secondaryContainer in +// the selectedReactionBoxModifier getter so the selected-reaction highlight follows the accent +// instead of freezing to the purple palette captured at class load. +val SelectedReactionBoxOuterModifier = Modifier .padding(horizontal = 5.dp, vertical = 5.dp) .size(Size40dp) .clip(shape = SmallBorder) - .background(DarkColorPalette.secondaryContainer) - .padding(5.dp) - -val LightSelectedReactionBoxModifier = - Modifier - .padding(horizontal = 5.dp, vertical = 5.dp) - .size(Size40dp) - .clip(shape = SmallBorder) - .background(LightColorPalette.secondaryContainer) - .padding(5.dp) val DarkChannelNotePictureModifier = Modifier @@ -348,17 +341,13 @@ val lightLargeProfilePictureModifier = .clip(shape = CircleShape) .border(3.dp, LightColorPalette.onBackground, CircleShape) -val darkNewItemBubbleModifier = +// Geometry only — no color. The fill is applied live from the scheme's primary in the +// newItemBubbleModifier getter so the unread dot follows the accent (matching its sibling +// newItemBackgroundColor) instead of freezing to the purple palette captured at class load. +val NewItemBubbleShapeModifier = Modifier .size(10.dp) .clip(shape = CircleShape) - .background(DarkColorPalette.primary) - -val lightNewItemBubbleModifier = - Modifier - .size(10.dp) - .clip(shape = CircleShape) - .background(LightColorPalette.primary) val darkBlackTagModifier = Modifier @@ -613,7 +602,7 @@ val ColorScheme.relayIconModifier: Modifier @Suppress("ModifierFactoryExtensionFunction") val ColorScheme.selectedReactionBoxModifier: Modifier - get() = if (isLight) LightSelectedReactionBoxModifier else DarkSelectedReactionBoxModifier + get() = SelectedReactionBoxOuterModifier.background(secondaryContainer).padding(5.dp) @Suppress("ModifierFactoryExtensionFunction") val ColorScheme.largeProfilePictureModifier: Modifier @@ -621,7 +610,7 @@ val ColorScheme.largeProfilePictureModifier: Modifier @Suppress("ModifierFactoryExtensionFunction") val ColorScheme.newItemBubbleModifier: Modifier - get() = if (isLight) lightNewItemBubbleModifier else darkNewItemBubbleModifier + get() = NewItemBubbleShapeModifier.background(primary) @Suppress("ModifierFactoryExtensionFunction") val ColorScheme.blackTagModifier: Modifier From ec466d8bc0f0ec0f7efdb12915449fe435827dab Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 20:32:21 +0000 Subject: [PATCH 03/14] feat: neutralize violet-tinted surface greys in the mobile theme The dark/light color builders left the Material3 neutral roles (background, surface, the surfaceContainer ramp, surfaceVariant, outline and the neutral on-colors) at Material's baseline, which is violet-tinted. That produced a faint purple wash on backgrounds, cards, dividers and secondary text that did not follow the user-selected accent. Replace them with hue-free greys that keep Material's lightness, so contrast is unchanged while the chrome reads as neutral. Accent-derived roles (primary/secondary/tertiary and their containers) are untouched and still drive the themed surfaces. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 86c8cf0451..402bfe9df5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -143,10 +143,24 @@ private fun darkColors(accent: AccentColorType): ColorScheme { onTertiaryContainer = onAccentContainer(secondary, dark = true), inversePrimary = accentPrimary(accent, dark = false), surfaceTint = primary, + // Neutral (hue-free) base + surface ramp. Left unset, these fall back to Material's + // violet-tinted baseline greys, which read as a faint purple wash independent of the + // accent. The greys below keep Material's lightness so contrast is unchanged. background = Color.Black, + onBackground = Color(0xFFE6E6E6), surface = Color.Black, + onSurface = Color(0xFFE6E6E6), + surfaceVariant = Color(0xFF1E1E1E), + onSurfaceVariant = Color(0xFFCACACA), surfaceDim = Color.Black, - surfaceVariant = Color(red = 29, green = 26, blue = 34), + surfaceBright = Color(0xFF383838), + surfaceContainerLowest = Color(0xFF141414), + surfaceContainerLow = Color(0xFF1A1A1A), + surfaceContainer = Color(0xFF252525), + surfaceContainerHigh = Color(0xFF2E2E2E), + surfaceContainerHighest = Color(0xFF383838), + outline = Color(0xFF909090), + outlineVariant = Color(0xFF454545), ) } @@ -169,8 +183,25 @@ private fun lightColors(accent: AccentColorType): ColorScheme { onTertiaryContainer = onAccentContainer(secondary, dark = false), inversePrimary = accentPrimary(accent, dark = true), surfaceTint = primary, - surfaceContainerHighest = Color(red = 236, green = 230, blue = 240), - surfaceVariant = Color(red = 250, green = 245, blue = 252), + // Neutral (hue-free) base + surface ramp. Left unset, these fall back to Material's + // violet-tinted baseline greys (e.g. surface #FEF7FF), which read as a faint purple wash + // independent of the accent. The greys below keep Material's lightness so contrast is + // unchanged. + background = Color(0xFFFDFDFD), + onBackground = Color(0xFF1C1C1C), + surface = Color(0xFFFDFDFD), + onSurface = Color(0xFF1C1C1C), + surfaceVariant = Color(0xFFFAFAFA), + onSurfaceVariant = Color(0xFF484848), + surfaceDim = Color(0xFFDEDEDE), + surfaceBright = Color(0xFFFDFDFD), + surfaceContainerLowest = Color(0xFFFFFFFF), + surfaceContainerLow = Color(0xFFF7F7F7), + surfaceContainer = Color(0xFFF2F2F2), + surfaceContainerHigh = Color(0xFFECECEC), + surfaceContainerHighest = Color(0xFFEBEBEB), + outline = Color(0xFF767676), + outlineVariant = Color(0xFFCACACA), ) } From abdb3be021663f8d23799da5354b1ff6d8ba0aa5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 20:51:32 +0000 Subject: [PATCH 04/14] refactor: route ad-hoc status colors through existing semantic tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Status telemetry (broadcast result, relay latency ping, memory heap gauge) hardcoded its own greens/ambers/reds instead of using the app's existing semantic tokens, so the same "success"/"warning" meaning drifted across a handful of near-identical shades. Route them onto the tokens already used everywhere else for that meaning: green -> allGoodColor, amber -> warningColor, the fixed critical red -> colorScheme.error. Also point OtsSettingsSection's re-hardcoded #F7931A at the shared BitcoinOrange constant. No new colors introduced. Brand/categorical palettes (git diff, crypto brands, road-event categories, chess, call UI, live-red indicators, medals) are intentionally left as-is — they are meaning-carrying and unique by design. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../amethyst/ui/broadcast/BroadcastBanner.kt | 11 ++++++----- .../amethyst/ui/broadcast/BroadcastDetailsSheet.kt | 14 ++++++++------ .../amethyst/ui/note/types/RelayDiscovery.kt | 7 ++++--- .../loggedIn/relays/RelayInformationScreen.kt | 10 ++++------ .../screen/loggedIn/settings/OtsSettingsSection.kt | 8 ++++---- .../loggedIn/settings/ResourceUsageScreen.kt | 8 +++++--- 6 files changed, 31 insertions(+), 27 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt index c241f50787..8d8cceda8e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt @@ -58,7 +58,6 @@ 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.platform.LocalContext import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.text.style.TextOverflow @@ -78,6 +77,8 @@ import com.vitorpamplona.amethyst.service.pow.formatTimeLeft import com.vitorpamplona.amethyst.service.pow.powKindLabelRes import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn +import com.vitorpamplona.amethyst.ui.theme.allGoodColor +import com.vitorpamplona.amethyst.ui.theme.warningColor import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent @@ -440,8 +441,8 @@ fun CompletedBroadcastContent( modifier = Modifier.fillMaxWidth(), ) { // Status colors (for icon tint only) - val successColor = Color(0xFF22C55E) - val warningColor = Color(0xFFF59E0B) + val successColor = MaterialTheme.colorScheme.allGoodColor + val warningColor = MaterialTheme.colorScheme.warningColor val (statusIcon, iconTint) = when (broadcast.status) { @@ -530,8 +531,8 @@ fun MultipleCompletedBroadcastContent( modifier = Modifier.fillMaxWidth(), ) { // Status colors (for icon tint only) - val successColor = Color(0xFF22C55E) - val warningColor = Color(0xFFF59E0B) + val successColor = MaterialTheme.colorScheme.allGoodColor + val warningColor = MaterialTheme.colorScheme.warningColor val totalRelayCount = broadcasts.sumOf { it.totalRelays } val failedRelayCount = broadcasts.sumOf { it.failedRelays.size } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastDetailsSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastDetailsSheet.kt index 2c9a3afbe5..ec05f787bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastDetailsSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastDetailsSheet.kt @@ -77,6 +77,8 @@ import com.vitorpamplona.amethyst.commons.service.broadcast.BroadcastStatus import com.vitorpamplona.amethyst.commons.service.broadcast.RelayResult import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow +import com.vitorpamplona.amethyst.ui.theme.allGoodColor +import com.vitorpamplona.amethyst.ui.theme.warningColor import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip18Reposts.RepostEvent @@ -299,8 +301,8 @@ private fun BroadcastSection( @Composable private fun statusColor(status: BroadcastStatus): Color = when (status) { - BroadcastStatus.SUCCESS -> Color(0xFF22C55E) - BroadcastStatus.PARTIAL -> Color(0xFFF59E0B) + BroadcastStatus.SUCCESS -> MaterialTheme.colorScheme.allGoodColor + BroadcastStatus.PARTIAL -> MaterialTheme.colorScheme.warningColor BroadcastStatus.FAILED -> MaterialTheme.colorScheme.error BroadcastStatus.IN_PROGRESS -> MaterialTheme.colorScheme.primary } @@ -312,8 +314,8 @@ private fun StatusIcon( ) { val (icon, tint, shouldRotate) = when (status) { - BroadcastStatus.SUCCESS -> Triple(MaterialSymbols.CheckCircle, Color(0xFF22C55E), false) - BroadcastStatus.PARTIAL -> Triple(MaterialSymbols.Error, Color(0xFFF59E0B), false) + BroadcastStatus.SUCCESS -> Triple(MaterialSymbols.CheckCircle, MaterialTheme.colorScheme.allGoodColor, false) + BroadcastStatus.PARTIAL -> Triple(MaterialSymbols.Error, MaterialTheme.colorScheme.warningColor, false) BroadcastStatus.FAILED -> Triple(MaterialSymbols.Error, MaterialTheme.colorScheme.error, false) BroadcastStatus.IN_PROGRESS -> Triple(MaterialSymbols.HourglassEmpty, MaterialTheme.colorScheme.primary, true) } @@ -342,9 +344,9 @@ private fun RelayResultRow( onRetry: () -> Unit, rotationAngle: Float = 0f, ) { - val successColor = Color(0xFF22C55E) + val successColor = MaterialTheme.colorScheme.allGoodColor val errorColor = MaterialTheme.colorScheme.error - val warningColor = Color(0xFFF59E0B) + val warningColor = MaterialTheme.colorScheme.warningColor Row( modifier = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayDiscovery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayDiscovery.kt index 5a21dce426..99400ce188 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayDiscovery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayDiscovery.kt @@ -38,7 +38,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -52,6 +51,8 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.ui.theme.allGoodColor +import com.vitorpamplona.amethyst.ui.theme.warningColor import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip66RelayMonitor.discovery.RelayDiscoveryEvent @@ -215,8 +216,8 @@ private fun RttMetricChip( ) { val color = when { - ms < 200 -> Color(0xFF4CAF50) - ms < 500 -> Color(0xFFFFC107) + ms < 200 -> MaterialTheme.colorScheme.allGoodColor + ms < 500 -> MaterialTheme.colorScheme.warningColor else -> MaterialTheme.colorScheme.error } Column(horizontalAlignment = Alignment.CenterHorizontally) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt index a4e71057af..b58e73db79 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt @@ -107,8 +107,10 @@ import com.vitorpamplona.amethyst.ui.theme.SpacedBy10dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow +import com.vitorpamplona.amethyst.ui.theme.allGoodColor import com.vitorpamplona.amethyst.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.ui.theme.redColorOnSecondSurface +import com.vitorpamplona.amethyst.ui.theme.warningColor import com.vitorpamplona.quartz.kinds.KindNames import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.stats.ErrorDebugMessage @@ -1437,12 +1439,8 @@ private fun RttChip( ) { val color = when { - ms < 200 -> Color(0xFF4CAF50) - - // green - ms < 500 -> Color(0xFFFFC107) - - // amber + ms < 200 -> MaterialTheme.colorScheme.allGoodColor + ms < 500 -> MaterialTheme.colorScheme.warningColor else -> MaterialTheme.colorScheme.error } Column(horizontalAlignment = Alignment.CenterHorizontally) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/OtsSettingsSection.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/OtsSettingsSection.kt index c233fa52fb..29452dca28 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/OtsSettingsSection.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/OtsSettingsSection.kt @@ -48,7 +48,6 @@ import androidx.compose.runtime.saveable.rememberSaveable 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.platform.LocalSoftwareKeyboardController import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight @@ -60,6 +59,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.model.nip03Timestamp.OtsSettings import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.quartz.nip03Timestamp.okhttp.OkHttpBitcoinExplorer /** @@ -149,7 +149,7 @@ private fun SectionHeaderOts() { Icon( MaterialSymbols.Search, contentDescription = null, - tint = Color(0xFFF7931A), // Bitcoin orange + tint = BitcoinOrange, modifier = Modifier.size(22.dp), ) Spacer(Modifier.width(10.dp)) @@ -194,11 +194,11 @@ private fun ActiveExplorerDisplay( "CUSTOM", style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Bold, - color = Color(0xFFF7931A), + color = BitcoinOrange, modifier = Modifier .background( - Color(0xFFF7931A).copy(alpha = 0.1f), + BitcoinOrange.copy(alpha = 0.1f), RoundedCornerShape(4.dp), ).padding(horizontal = 6.dp, vertical = 2.dp), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt index 4e841ad4ab..a916dea583 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt @@ -73,6 +73,8 @@ import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.ui.theme.allGoodColor +import com.vitorpamplona.amethyst.ui.theme.warningColor import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext @@ -447,9 +449,9 @@ private fun MemorySection(memory: MemorySnapshot?) { if (memory == null) return val heapColor = when { - memory.heapFraction > 0.80f -> Color(0xFFE53935) - memory.heapFraction > 0.60f -> Color(0xFFFFA000) - else -> Color(0xFF43A047) + memory.heapFraction > 0.80f -> MaterialTheme.colorScheme.error + memory.heapFraction > 0.60f -> MaterialTheme.colorScheme.warningColor + else -> MaterialTheme.colorScheme.allGoodColor } SettingsSection(R.string.resource_usage_memory_section) { BarRow( From e61b3fbebd5b4f4a8d96b3f1a6773ea8b1cf4030 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 21:08:28 +0000 Subject: [PATCH 05/14] refactor: drop dead purple constants and fix FAB glyph contrast Two cleanup passes on the mobile theme: - Remove definition-only colour constants from Color.kt that had no references anywhere (the Primary50..80 purple ramp, DEFAULT_PRIMARY, LIGHT_PURPLE, Purple700, FollowsFollow, NIP05Verified, the base Nip05EmailColor, DarkerGreen and LighterRedColor). - Point the "new item" FloatingActionButton glyphs at onPrimary instead of a hardcoded Color.White. With a light accent in the dark theme the container is a pale pastel, so a white glyph was low-contrast; onPrimary resolves to the correct high-contrast on-colour in both themes. Only FAB glyphs on a primary container were changed; white icons on dark overlays were left as-is. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../screen/loggedIn/articles/NewArticleButton.kt | 3 +-- .../ui/screen/loggedIn/badges/NewBadgeButton.kt | 3 +-- .../loggedIn/calendars/NewCalendarButton.kt | 9 ++++----- .../loggedIn/chats/rooms/ChannelFabColumn.kt | 3 +-- .../screen/loggedIn/chess/NewChessGameButton.kt | 3 +-- .../communities/NewCommunityNoteButton.kt | 3 +-- .../communities/list/NewCommunityButton.kt | 3 +-- .../ui/screen/loggedIn/discover/DiscoverScreen.kt | 5 ++--- .../screen/loggedIn/geohash/NewGeoNoteButton.kt | 3 +-- .../loggedIn/hashtag/NewHashtagNoteButton.kt | 3 +-- .../ui/screen/loggedIn/home/NewNoteButton.kt | 3 +-- .../screen/loggedIn/longs/NewLongVideoButton.kt | 9 ++++----- .../screen/loggedIn/music/NewMusicPlaylistFab.kt | 3 +-- .../screen/loggedIn/music/NewMusicTrackButton.kt | 3 +-- .../screen/loggedIn/pictures/NewPictureButton.kt | 9 ++++----- .../ui/screen/loggedIn/podcasts/PodcastsScreen.kt | 3 +-- .../ui/screen/loggedIn/polls/NewPollButton.kt | 3 +-- .../screen/loggedIn/products/NewProductButton.kt | 3 +-- .../loggedIn/publicChats/NewPublicChatButton.kt | 3 +-- .../screen/loggedIn/relay/NewRelayNoteButton.kt | 3 +-- .../screen/loggedIn/shorts/NewShortVideoButton.kt | 9 ++++----- .../ui/screen/loggedIn/url/NewUrlNoteButton.kt | 3 +-- .../ui/screen/loggedIn/video/NewImageButton.kt | 11 +++++------ .../screen/loggedIn/workouts/NewWorkoutButton.kt | 3 +-- .../com/vitorpamplona/amethyst/ui/theme/Color.kt | 15 --------------- 25 files changed, 41 insertions(+), 80 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/NewArticleButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/NewArticleButton.kt index eaa6d05c72..e5d419b4ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/NewArticleButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/NewArticleButton.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -46,7 +45,7 @@ fun NewArticleButton(nav: INav) { symbol = MaterialSymbols.Add, contentDescription = stringRes(id = R.string.new_long_form_post), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt index 209be6fe91..ea9017c3fd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.graphics.Color import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.painterRes @@ -63,7 +62,7 @@ fun NewBadgeButton(accountViewModel: AccountViewModel) { painter = painterRes(R.drawable.ic_compose, 5), contentDescription = stringRes(id = R.string.new_badge), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/NewCalendarButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/NewCalendarButton.kt index c4b0981c20..1d44af0116 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/NewCalendarButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/NewCalendarButton.kt @@ -37,7 +37,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -74,7 +73,7 @@ fun NewCalendarButton(nav: INav) { // string is ambiguous out of context. contentDescription = stringRes(R.string.calendar_fab_new_collection), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -93,7 +92,7 @@ fun NewCalendarButton(nav: INav) { symbol = MaterialSymbols.Add, contentDescription = stringRes(R.string.calendar_fab_new_event), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -116,7 +115,7 @@ fun NewCalendarButton(nav: INav) { symbol = MaterialSymbols.Close, contentDescription = stringRes(R.string.calendar_fab_toggle), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -130,7 +129,7 @@ fun NewCalendarButton(nav: INav) { // Top FAB toggles the sub-FABs in/out — describe that, not the sub-action. contentDescription = stringRes(R.string.calendar_fab_toggle), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt index 34f60218c3..20fb4dfed2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChannelFabColumn.kt @@ -26,7 +26,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -54,7 +53,7 @@ fun ChannelFabColumn(nav: INav) { symbol = MaterialSymbols.Add, contentDescription = stringRes(R.string.messages_create_public_private_chat_description), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt index d9ce5c8fdb..15e0b68109 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -48,7 +47,7 @@ fun NewChessGameButton(onClick: () -> Unit) { symbol = MaterialSymbols.Add, contentDescription = stringRes(R.string.new_chess_game), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt index 0bb6305ed6..348afee567 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt @@ -25,7 +25,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.components.LoadNote @@ -70,7 +69,7 @@ fun NewCommunityNoteButton( painter = painterRes(R.drawable.ic_compose, 2), contentDescription = stringRes(id = R.string.new_community_note), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/NewCommunityButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/NewCommunityButton.kt index c8187a63ae..b9f5273384 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/NewCommunityButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/NewCommunityButton.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -46,7 +45,7 @@ fun NewCommunityButton(nav: INav) { symbol = MaterialSymbols.Add, contentDescription = stringRes(id = R.string.new_community), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt index 84ce056f9a..833e843078 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt @@ -48,7 +48,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R @@ -370,7 +369,7 @@ fun NewProductButton( symbol = MaterialSymbols.Add, contentDescription = stringRes(id = R.string.new_product), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } @@ -392,7 +391,7 @@ fun NewLongFormMarkdownButton( symbol = MaterialSymbols.Add, contentDescription = stringRes(id = R.string.new_long_form_post), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt index e7071436f0..b8f0906a1d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt @@ -25,7 +25,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -53,7 +52,7 @@ fun NewGeoPostButton( painter = painterRes(R.drawable.ic_compose, 1), contentDescription = stringRes(id = R.string.new_community_note), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt index 46bbbeda5a..8d02bac91c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt @@ -25,7 +25,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -53,7 +52,7 @@ fun NewHashtagPostButton( painter = painterRes(R.drawable.ic_compose, 3), contentDescription = stringRes(id = R.string.new_community_note), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt index 298d5f5263..3d3574924e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt @@ -29,7 +29,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R @@ -66,7 +65,7 @@ fun NewNoteButton(nav: INav) { painter = painterRes(R.drawable.ic_compose, 4), contentDescription = stringRes(R.string.new_post), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt index b446229a66..f3b13641dc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R @@ -130,7 +129,7 @@ fun NewLongVideoButton( symbol = MaterialSymbols.Videocam, contentDescription = stringRes(id = R.string.record_a_video), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -149,7 +148,7 @@ fun NewLongVideoButton( symbol = MaterialSymbols.AddPhotoAlternate, contentDescription = stringRes(id = R.string.upload_image), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -172,7 +171,7 @@ fun NewLongVideoButton( symbol = MaterialSymbols.Close, contentDescription = stringRes(id = R.string.new_long_video), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -185,7 +184,7 @@ fun NewLongVideoButton( painter = painterRes(R.drawable.ic_compose, 5), contentDescription = stringRes(id = R.string.new_long_video), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistFab.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistFab.kt index 65b4d39f78..3b002a1cf6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistFab.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistFab.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -52,7 +51,7 @@ fun NewMusicPlaylistFab(nav: INav) { symbol = MaterialSymbols.AutoMirrored.PlaylistAdd, contentDescription = stringRes(R.string.new_music_playlist), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackButton.kt index 9d05b125dd..ef3dcfdb93 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackButton.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -54,7 +53,7 @@ fun NewMusicTrackButton( symbol = MaterialSymbols.MusicNote, contentDescription = stringRes(R.string.new_music_track), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt index e1fbd437c7..4521e82df0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R @@ -130,7 +129,7 @@ fun NewPictureButton( symbol = MaterialSymbols.CameraAlt, contentDescription = stringRes(id = R.string.take_a_picture), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -149,7 +148,7 @@ fun NewPictureButton( symbol = MaterialSymbols.AddPhotoAlternate, contentDescription = stringRes(id = R.string.upload_image), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -172,7 +171,7 @@ fun NewPictureButton( symbol = MaterialSymbols.Close, contentDescription = stringRes(id = R.string.new_picture), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -185,7 +184,7 @@ fun NewPictureButton( painter = painterRes(R.drawable.ic_compose, 5), contentDescription = stringRes(id = R.string.new_picture), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsScreen.kt index ec3685bbfc..0a5471bd9b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsScreen.kt @@ -26,7 +26,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R @@ -101,7 +100,7 @@ fun PodcastsScreen( Icon( symbol = MaterialSymbols.Mic, contentDescription = stringRes(R.string.podcast_your_podcast), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/NewPollButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/NewPollButton.kt index 8172c942a5..62dbedf6d5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/NewPollButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/NewPollButton.kt @@ -25,7 +25,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -46,7 +45,7 @@ fun NewPollButton(nav: INav) { painter = painterRes(R.drawable.ic_compose, 4), contentDescription = stringRes(id = R.string.new_poll), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/NewProductButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/NewProductButton.kt index 5de13885cb..17f154ebfb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/NewProductButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/NewProductButton.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -52,7 +51,7 @@ fun NewProductButton( symbol = MaterialSymbols.Add, contentDescription = stringRes(id = R.string.new_product), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/NewPublicChatButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/NewPublicChatButton.kt index 4347f862ca..f13e94a04b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/NewPublicChatButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/NewPublicChatButton.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -46,7 +45,7 @@ fun NewPublicChatButton(nav: INav) { symbol = MaterialSymbols.Add, contentDescription = stringRes(id = R.string.new_public_chat), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt index 592aa4cd03..748a1806d8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt @@ -25,7 +25,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -52,7 +51,7 @@ fun NewRelayNoteButton( painter = painterRes(R.drawable.ic_compose, 3), contentDescription = stringRes(id = R.string.new_community_note), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt index f8c5a9a59f..264102f79c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R @@ -130,7 +129,7 @@ fun NewShortVideoButton( symbol = MaterialSymbols.Videocam, contentDescription = stringRes(id = R.string.record_a_video), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -149,7 +148,7 @@ fun NewShortVideoButton( symbol = MaterialSymbols.AddPhotoAlternate, contentDescription = stringRes(id = R.string.upload_image), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -172,7 +171,7 @@ fun NewShortVideoButton( symbol = MaterialSymbols.Close, contentDescription = stringRes(id = R.string.new_short_video), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -185,7 +184,7 @@ fun NewShortVideoButton( painter = painterRes(R.drawable.ic_compose, 5), contentDescription = stringRes(id = R.string.new_short_video), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt index cecf7e0950..913642da1c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt @@ -25,7 +25,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -53,7 +52,7 @@ fun NewUrlPostButton( painter = painterRes(R.drawable.ic_compose, 1), contentDescription = stringRes(id = R.string.new_community_note), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewImageButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewImageButton.kt index abd23e7cf0..e8d254eb0a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewImageButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewImageButton.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R @@ -144,7 +143,7 @@ fun NewImageButton( symbol = MaterialSymbols.CameraAlt, contentDescription = stringRes(id = R.string.take_a_picture), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -163,7 +162,7 @@ fun NewImageButton( symbol = MaterialSymbols.Videocam, contentDescription = stringRes(id = R.string.record_a_video), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -182,7 +181,7 @@ fun NewImageButton( symbol = MaterialSymbols.AddPhotoAlternate, contentDescription = stringRes(id = R.string.upload_image), modifier = Modifier.size(26.dp), - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -207,7 +206,7 @@ fun NewImageButton( symbol = MaterialSymbols.Close, contentDescription = stringRes(id = R.string.new_short), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } @@ -220,7 +219,7 @@ fun NewImageButton( painter = painterRes(R.drawable.ic_compose, 5), contentDescription = stringRes(id = R.string.new_short), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutButton.kt index 945ab25509..8cbe58f87c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutButton.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -46,7 +45,7 @@ fun NewWorkoutButton(nav: INav) { symbol = MaterialSymbols.Add, contentDescription = stringRes(id = R.string.new_workout), modifier = Size26Modifier, - tint = Color.White, + tint = MaterialTheme.colorScheme.onPrimary, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt index 6ca1574e84..047ea2941e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt @@ -24,17 +24,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorMatrix -val Primary50 = Color(red = 127, green = 103, blue = 190) -val Primary60 = Color(red = 154, green = 130, blue = 219) -val Primary70 = Color(red = 182, green = 157, blue = 248) -val Primary80 = Color(red = 208, green = 188, blue = 255) - -val DEFAULT_PRIMARY = Color(red = 208, green = 188, blue = 255) -val LIGHT_PURPLE = Color(red = 187, green = 134, blue = 252) - val Purple200 = Color(0xFFBB86FC) val Purple500 = Color(0xFF6200EE) -val Purple700 = Color(0xFF3700B3) val Teal200 = Color(0xFF03DAC5) // Accent palette options selected through Settings -> Accent Color. @@ -56,17 +47,11 @@ val BitcoinDark = Color(0xFFF7931A) val BitcoinLight = Color(0xFFB66605) val Following = Color(0xFF03DAC5) -val FollowsFollow = Color.Yellow -val NIP05Verified = Color.Blue -val Nip05EmailColor = Color(0xFFb198ec) val Nip05EmailColorDark = Color(0xFF765AA2) val Nip05EmailColorLight = Color(0xFFa770f3) -val DarkerGreen = Color.Green.copy(alpha = 0.32f) - val LightRedColor = Color(0xFFC62828) -val LighterRedColor = Color(0xFFFF0E0E) val RelayIconFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0.5f) }) From 424160200b02dcf60f11ca14a2154f5334363b06 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 21:13:32 +0000 Subject: [PATCH 06/14] feat: show colored swatches in the accent-color picker Replace the plain text-dropdown accent picker with a row of tappable colour swatches, each filled with the accent's real primary for the current light/dark mode so the choice previews the actual result. The selected swatch is marked with a ring and a check. Adds two small public helpers in the theme (previewColor, contentColorOnAccent) that reuse the existing accent resolution. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../loggedIn/settings/AppSettingsScreen.kt | 91 +++++++++++++++---- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 8 ++ 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt index 9a3f6839da..f0c9abca96 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt @@ -21,15 +21,21 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings import android.content.Context +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold @@ -40,14 +46,19 @@ import androidx.compose.runtime.getValue 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.platform.LocalContext +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.os.LocaleListCompat import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.commons.icons.symbols.Icon +import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.model.AccentColorType import com.vitorpamplona.amethyst.model.ConnectivityType import com.vitorpamplona.amethyst.model.FeatureSetType @@ -55,7 +66,6 @@ import com.vitorpamplona.amethyst.model.FontFamilyType import com.vitorpamplona.amethyst.model.FontSizeType import com.vitorpamplona.amethyst.model.ThemeType import com.vitorpamplona.amethyst.model.UiSettingsFlow -import com.vitorpamplona.amethyst.model.parseAccentColorType import com.vitorpamplona.amethyst.model.parseBooleanType import com.vitorpamplona.amethyst.model.parseConnectivityType import com.vitorpamplona.amethyst.model.parseFeatureSetType @@ -72,6 +82,9 @@ import com.vitorpamplona.amethyst.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow +import com.vitorpamplona.amethyst.ui.theme.contentColorOnAccent +import com.vitorpamplona.amethyst.ui.theme.isLight +import com.vitorpamplona.amethyst.ui.theme.previewColor import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.persistentListOf @@ -226,25 +239,67 @@ fun ShowThemeChoice(sharedPrefs: UiSettingsFlow) { @Composable fun ShowAccentColorChoice(sharedPrefs: UiSettingsFlow) { - val accentOptions = - persistentListOf( - TitleExplainer(stringRes(AccentColorType.PURPLE.resourceId)), - TitleExplainer(stringRes(AccentColorType.BLUE.resourceId)), - TitleExplainer(stringRes(AccentColorType.GREEN.resourceId)), - TitleExplainer(stringRes(AccentColorType.ORANGE.resourceId)), - TitleExplainer(stringRes(AccentColorType.RED.resourceId)), - TitleExplainer(stringRes(AccentColorType.PINK.resourceId)), - ) + val accent by sharedPrefs.accentColor.collectAsState() + val dark = !MaterialTheme.colorScheme.isLight - val accentIndex by sharedPrefs.accentColor.collectAsState() - - SettingsRow( - R.string.accent_color, - R.string.accent_color_description, - accentOptions, - accentIndex.screenCode, + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp), ) { - sharedPrefs.accentColor.tryEmit(parseAccentColorType(it)) + Text( + text = stringRes(R.string.accent_color), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Text( + text = stringRes(R.string.accent_color_description), + style = MaterialTheme.typography.bodySmall, + color = Color.Gray, + ) + Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { + AccentColorType.entries.forEach { option -> + AccentColorSwatch( + color = option.previewColor(dark), + label = stringRes(option.resourceId), + selected = option == accent, + onClick = { sharedPrefs.accentColor.tryEmit(option) }, + ) + } + } + } +} + +@Composable +private fun AccentColorSwatch( + color: Color, + label: String, + selected: Boolean, + onClick: () -> Unit, +) { + Box( + modifier = + Modifier + .size(36.dp) + .clip(CircleShape) + .background(color) + .then( + if (selected) { + Modifier.border(2.dp, MaterialTheme.colorScheme.onSurface, CircleShape) + } else { + Modifier + }, + ).clickable(onClick = onClick) + .semantics { contentDescription = label }, + contentAlignment = Alignment.Center, + ) { + if (selected) { + Icon( + symbol = MaterialSymbols.Done, + contentDescription = null, + tint = contentColorOnAccent(color), + modifier = Modifier.size(20.dp), + ) + } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 402bfe9df5..da98930d03 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -124,6 +124,14 @@ private fun onAccentContainer( dark: Boolean, ): Color = if (dark) color else lerp(color, Color.Black, 0.30f) +// Representative colour for an accent option, used by the Settings accent-picker swatches — the +// same primary the theme would apply for the given light/dark mode, so the swatch previews the +// real result. +fun AccentColorType.previewColor(dark: Boolean): Color = accentPrimary(this, dark) + +// Contrast colour (black or white) for content drawn on top of an accent swatch. +fun contentColorOnAccent(color: Color): Color = onAccent(color) + private fun darkColors(accent: AccentColorType): ColorScheme { val primary = accentPrimary(accent, dark = true) val secondary = accentSecondary(accent, dark = true) From 479c20a2e6f32d215525157501b0b48e8c3f41bf Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 21:36:05 +0000 Subject: [PATCH 07/14] refactor: make commons action icons tintable and follow the accent The Following, Liked and Reposted vectors baked their own colours (a purple shield, a red heart, a green check) and were rendered with Color.Unspecified, so they ignored the theme and stayed those fixed hues under every accent. Strip the baked colours to a neutral tintable black and tint them at the icon wrappers with the theme primary, so the follow badge, liked heart and reposted check now follow the user's selected accent. Call sites that relied on the old baked colour via Color.Unspecified are pointed at the accent (or keep their explicit tint, e.g. white-on-coloured-background). The already-monochrome vectors (Bookmark, Like, Reply, Repost, Search, Share, Zap, ZapSplit) were already tinted by their callers and are unchanged. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../java/com/vitorpamplona/amethyst/ui/note/Icons.kt | 11 +++++++---- .../vitorpamplona/amethyst/ui/note/ReactionsRow.kt | 2 +- .../amethyst/ui/note/UpdateReactionTypeDialog.kt | 2 +- .../vitorpamplona/amethyst/commons/icons/Following.kt | 10 +++++----- .../com/vitorpamplona/amethyst/commons/icons/Liked.kt | 2 +- .../vitorpamplona/amethyst/commons/icons/Reposted.kt | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index 27623eb4f1..d5d3963e61 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -65,12 +65,15 @@ fun AmethystIcon(iconSize: Dp) { } @Composable -fun FollowingIcon(modifier: Modifier) { +fun FollowingIcon( + modifier: Modifier, + tint: Color = MaterialTheme.colorScheme.primary, +) { Icon( imageVector = Following, contentDescription = stringRes(id = R.string.following), modifier = modifier, - tint = Color.Unspecified, + tint = tint, ) } @@ -99,7 +102,7 @@ fun DownloadForOfflineIcon( @Composable fun LikedIcon( modifier: Modifier, - tint: Color = Color.Unspecified, + tint: Color = MaterialTheme.colorScheme.primary, ) { Icon( imageVector = Liked, @@ -151,7 +154,7 @@ fun RepostIcon( @Composable fun RepostedIcon( modifier: Modifier, - tint: Color = Color.Unspecified, + tint: Color = MaterialTheme.colorScheme.primary, ) { Icon( imageVector = Reposted, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 095037c07a..551906429d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -929,7 +929,7 @@ fun BoostReaction( }, ) { ObserveBoostIcon(baseNote, accountViewModel) { hasBoosted -> - RepostedIcon(iconSizeModifier, if (hasBoosted) Color.Unspecified else grayTint) + RepostedIcon(iconSizeModifier, if (hasBoosted) MaterialTheme.colorScheme.primary else grayTint) } if (wantsToBoost) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt index 9cec7d50ba..1f2523a4ff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt @@ -302,7 +302,7 @@ private fun RenderReactionOption( when (reactionType) { "+" -> { Row { - LikedIcon(modifier = Modifier.size(20.dp), tint = Color.Unspecified) + LikedIcon(modifier = Modifier.size(20.dp)) Text( text = " ✖", diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt index 326474d8a8..cd052a111d 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt @@ -51,7 +51,7 @@ public val Following: ImageVector viewportHeight = 30f, ).apply { path( - fill = SolidColor(Color(0xFF7F2EFF)), + fill = SolidColor(Color.Black), fillAlpha = 1.0f, stroke = null, strokeAlpha = 1.0f, @@ -77,9 +77,9 @@ public val Following: ImageVector close() } path( - fill = SolidColor(Color(0xFFFFFFFF)), + fill = SolidColor(Color.Black), fillAlpha = 1.0f, - stroke = SolidColor(Color(0xFF7F2EFF)), + stroke = SolidColor(Color.Black), strokeAlpha = 1.0f, strokeLineWidth = 0.5f, strokeLineCap = StrokeCap.Butt, @@ -101,9 +101,9 @@ public val Following: ImageVector close() } path( - fill = SolidColor(Color(0xFFFFFFFF)), + fill = SolidColor(Color.Black), fillAlpha = 1.0f, - stroke = SolidColor(Color(0xFF7F2EFF)), + stroke = SolidColor(Color.Black), strokeAlpha = 1.0f, strokeLineWidth = 0.5f, strokeLineCap = StrokeCap.Butt, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt index d41cc91b37..7640cc4e6f 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt @@ -51,7 +51,7 @@ public val Liked: ImageVector viewportHeight = 24.0f, ).apply { path( - fill = SolidColor(Color(0xFFCA395f)), + fill = SolidColor(Color.Black), strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt index 5d99988b47..7d0d50f266 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt @@ -51,7 +51,7 @@ public val Reposted: ImageVector viewportHeight = 24.0f, ).apply { path( - fill = SolidColor(Color(0xFF59bc6d)), + fill = SolidColor(Color.Black), stroke = null, strokeLineWidth = 0.0f, strokeLineCap = Butt, From 2725a9356918bffc1b78d2eae4dcafeeedf59ea0 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 21:50:01 +0000 Subject: [PATCH 08/14] fix: keep the liked heart and reposted check their semantic colours MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous change made every commons action icon follow the accent, but the liked heart (red) and reposted check (green) are semantic status colours, not brand purple. Restore their original baked colours and Color.Unspecified rendering. Only the Following badge — which was brand purple — keeps following the accent. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt | 4 ++-- .../java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt | 2 +- .../amethyst/ui/note/UpdateReactionTypeDialog.kt | 2 +- .../kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt | 2 +- .../com/vitorpamplona/amethyst/commons/icons/Reposted.kt | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index d5d3963e61..685fcf2151 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -102,7 +102,7 @@ fun DownloadForOfflineIcon( @Composable fun LikedIcon( modifier: Modifier, - tint: Color = MaterialTheme.colorScheme.primary, + tint: Color = Color.Unspecified, ) { Icon( imageVector = Liked, @@ -154,7 +154,7 @@ fun RepostIcon( @Composable fun RepostedIcon( modifier: Modifier, - tint: Color = MaterialTheme.colorScheme.primary, + tint: Color = Color.Unspecified, ) { Icon( imageVector = Reposted, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 551906429d..095037c07a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -929,7 +929,7 @@ fun BoostReaction( }, ) { ObserveBoostIcon(baseNote, accountViewModel) { hasBoosted -> - RepostedIcon(iconSizeModifier, if (hasBoosted) MaterialTheme.colorScheme.primary else grayTint) + RepostedIcon(iconSizeModifier, if (hasBoosted) Color.Unspecified else grayTint) } if (wantsToBoost) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt index 1f2523a4ff..9cec7d50ba 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt @@ -302,7 +302,7 @@ private fun RenderReactionOption( when (reactionType) { "+" -> { Row { - LikedIcon(modifier = Modifier.size(20.dp)) + LikedIcon(modifier = Modifier.size(20.dp), tint = Color.Unspecified) Text( text = " ✖", diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt index 7640cc4e6f..d41cc91b37 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Liked.kt @@ -51,7 +51,7 @@ public val Liked: ImageVector viewportHeight = 24.0f, ).apply { path( - fill = SolidColor(Color.Black), + fill = SolidColor(Color(0xFFCA395f)), strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt index 7d0d50f266..5d99988b47 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Reposted.kt @@ -51,7 +51,7 @@ public val Reposted: ImageVector viewportHeight = 24.0f, ).apply { path( - fill = SolidColor(Color.Black), + fill = SolidColor(Color(0xFF59bc6d)), stroke = null, strokeLineWidth = 0.0f, strokeLineCap = Butt, From 901650f4a9b8d82ed92245f3f97073e577193b14 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 21:56:29 +0000 Subject: [PATCH 09/14] feat: make NIP-05 and image hash-verify symbols follow the accent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NIP-05 identifier colour and its verified badge were a fixed purple, and the image hash-verification "passed" seal was a fixed purple drawable — none followed the selected accent. Redefine the nip05 token to the theme primary (covering the identifier text, badge and the other nip05 call sites) and tint the nip_05 and original drawables with the accent at render. Also switch the hash-verification "failed" icon from a raw Color.Red to colorScheme.error, matching the themed error red used everywhere else. Removes the now-unused Nip05EmailColor light/dark constants. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../amethyst/ui/components/ZoomableContentView.kt | 4 ++-- .../amethyst/ui/note/NIP05VerificationDisplay.kt | 3 +-- .../main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt | 3 --- .../main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt | 3 ++- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 0e9f4eaba8..a499c08102 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -1254,7 +1254,7 @@ private fun HashVerificationSymbol(verifiedHash: Boolean) { painter = painterRes(R.drawable.original, 1), contentDescription = stringRes(id = R.string.hash_verification_passed), modifier = Size30Modifier, - tint = Color.Unspecified, + tint = MaterialTheme.colorScheme.primary, ) } } else { @@ -1268,7 +1268,7 @@ private fun HashVerificationSymbol(verifiedHash: Boolean) { symbol = MaterialSymbols.Report, contentDescription = stringRes(id = R.string.hash_verification_failed), modifier = Size30Modifier, - tint = Color.Red, + tint = MaterialTheme.colorScheme.error, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index b87ed48c44..32730d9424 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -36,7 +36,6 @@ 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.platform.LocalUriHandler import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextOverflow @@ -481,7 +480,7 @@ fun RenderNIP05VerifiedSymbol( painter = painterRes(R.drawable.nip_05, compositionSizeReference), contentDescription = stringRes(id = R.string.nip05_verified), modifier = modifier, - tint = Color.Unspecified, + tint = MaterialTheme.colorScheme.nip05, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt index 047ea2941e..f432f5e73f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt @@ -48,9 +48,6 @@ val BitcoinLight = Color(0xFFB66605) val Following = Color(0xFF03DAC5) -val Nip05EmailColorDark = Color(0xFF765AA2) -val Nip05EmailColorLight = Color(0xFFa770f3) - val LightRedColor = Color(0xFFC62828) val RelayIconFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0.5f) }) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index da98930d03..3bbf7ab42e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -546,8 +546,9 @@ val ColorScheme.mediumImportanceLink: Color val ColorScheme.placeholderText: Color get() = if (isLight) LightPlaceholderText else DarkPlaceholderText +// NIP-05 identifiers were a fixed purple; follow the selected accent instead. val ColorScheme.nip05: Color - get() = if (isLight) Nip05EmailColorLight else Nip05EmailColorDark + get() = primary val ColorScheme.onBackgroundColorFilter: ColorFilter get() = if (isLight) LightOnBackgroundColorFilter else DarkOnBackgroundColorFilter From 853d5e1b2525b3c13a97bf93dc722c955f29dd71 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 22:45:20 +0000 Subject: [PATCH 10/14] =?UTF-8?q?fix:=20address=20accent=20regressions=20?= =?UTF-8?q?=E2=80=94=20teal=20tonal=20buttons,=20FAB=20glyph,=20follow=20b?= =?UTF-8?q?adge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three fixes from on-device review: - Secondary/tertiary CONTAINER roles now derive from the accent (primary) instead of the purple theme's teal secondary. FilledTonalButton (profile follow/edit/message, "Show more"/"Show anyway", tonal chips) was neutral before and had turned teal-on-teal; it now reads as an accent tonal button. The solid secondary/tertiary roles stay teal (unchanged, as before). - onPrimary is white again. Deriving it by max contrast made it black on the light accents used in dark mode, flipping FAB glyphs from white to black; white reads better on the accent. - The Following badge is two-tone again: the shield follows the accent while the inner figure stays white, instead of a flat single-colour shield. The vector is now a following(accent) builder cached per accent at the call site. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../vitorpamplona/amethyst/ui/note/Icons.kt | 13 +- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 26 ++- .../amethyst/commons/icons/Following.kt | 176 +++++++++--------- 3 files changed, 109 insertions(+), 106 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index 685fcf2151..5b7731cef3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -35,7 +35,6 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.hashtags.Amethyst import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons -import com.vitorpamplona.amethyst.commons.icons.Following import com.vitorpamplona.amethyst.commons.icons.Like import com.vitorpamplona.amethyst.commons.icons.Liked import com.vitorpamplona.amethyst.commons.icons.Reply @@ -43,6 +42,7 @@ import com.vitorpamplona.amethyst.commons.icons.Repost import com.vitorpamplona.amethyst.commons.icons.Reposted import com.vitorpamplona.amethyst.commons.icons.Search import com.vitorpamplona.amethyst.commons.icons.Zap +import com.vitorpamplona.amethyst.commons.icons.following import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.ui.stringRes @@ -65,15 +65,14 @@ fun AmethystIcon(iconSize: Dp) { } @Composable -fun FollowingIcon( - modifier: Modifier, - tint: Color = MaterialTheme.colorScheme.primary, -) { +fun FollowingIcon(modifier: Modifier) { + val accent = MaterialTheme.colorScheme.primary + val icon = remember(accent) { following(accent) } Icon( - imageVector = Following, + imageVector = icon, contentDescription = stringRes(id = R.string.following), modifier = modifier, - tint = tint, + tint = Color.Unspecified, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 3bbf7ab42e..f3864fdebe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -138,17 +138,20 @@ private fun darkColors(accent: AccentColorType): ColorScheme { val surface = Color.Black return darkColorScheme( primary = primary, - onPrimary = onAccent(primary), + onPrimary = Color.White, primaryContainer = accentContainer(primary, surface, 0.16f), onPrimaryContainer = onAccentContainer(primary, dark = true), secondary = secondary, onSecondary = onAccent(secondary), - secondaryContainer = accentContainer(secondary, surface, 0.16f), - onSecondaryContainer = onAccentContainer(secondary, dark = true), + // Container roles derive from the accent (primary), not the teal secondary. Secondary/tertiary + // container surfaces (FilledTonalButton, tonal chips) were neutral before; deriving them from + // teal made them read as teal-on-teal, so they follow the accent hue instead. + secondaryContainer = accentContainer(primary, surface, 0.16f), + onSecondaryContainer = onAccentContainer(primary, dark = true), tertiary = secondary, onTertiary = onAccent(secondary), - tertiaryContainer = accentContainer(secondary, surface, 0.16f), - onTertiaryContainer = onAccentContainer(secondary, dark = true), + tertiaryContainer = accentContainer(primary, surface, 0.16f), + onTertiaryContainer = onAccentContainer(primary, dark = true), inversePrimary = accentPrimary(accent, dark = false), surfaceTint = primary, // Neutral (hue-free) base + surface ramp. Left unset, these fall back to Material's @@ -178,17 +181,20 @@ private fun lightColors(accent: AccentColorType): ColorScheme { val surface = Color.White return lightColorScheme( primary = primary, - onPrimary = onAccent(primary), + onPrimary = Color.White, primaryContainer = accentContainer(primary, surface, 0.12f), onPrimaryContainer = onAccentContainer(primary, dark = false), secondary = secondary, onSecondary = onAccent(secondary), - secondaryContainer = accentContainer(secondary, surface, 0.12f), - onSecondaryContainer = onAccentContainer(secondary, dark = false), + // Container roles derive from the accent (primary), not the teal secondary. Secondary/tertiary + // container surfaces (FilledTonalButton, tonal chips) were neutral before; deriving them from + // teal made them read as teal-on-teal, so they follow the accent hue instead. + secondaryContainer = accentContainer(primary, surface, 0.12f), + onSecondaryContainer = onAccentContainer(primary, dark = false), tertiary = secondary, onTertiary = onAccent(secondary), - tertiaryContainer = accentContainer(secondary, surface, 0.12f), - onTertiaryContainer = onAccentContainer(secondary, dark = false), + tertiaryContainer = accentContainer(primary, surface, 0.12f), + onTertiaryContainer = onAccentContainer(primary, dark = false), inversePrimary = accentPrimary(accent, dark = true), surfaceTint = primary, // Neutral (hue-free) base + surface ramp. Left unset, these fall back to Material's diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt index cd052a111d..62e000fc0e 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt @@ -35,94 +35,92 @@ import androidx.compose.ui.unit.dp @Preview @Composable private fun VectorPreview() { - Image(Following, null) + Image(following(Color(0xFF7F2EFF)), null) } -private var labelsFollowing: ImageVector? = null - -public val Following: ImageVector - get() = - labelsFollowing ?: ImageVector - .Builder( - name = "Following", - defaultWidth = 30.dp, - defaultHeight = 30.dp, - viewportWidth = 30f, - viewportHeight = 30f, - ).apply { - path( - fill = SolidColor(Color.Black), - fillAlpha = 1.0f, - stroke = null, - strokeAlpha = 1.0f, - strokeLineWidth = 1.0f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(27.8f, 12.8f) - lineTo(27.8f, 12.8f) - curveTo(27.8f, 5f, 27.2f, 0f, 24.4f, 0f) - reflectiveCurveTo(15f, 0f, 15f, 0f) - reflectiveCurveTo(8.4f, 0f, 5.6f, 0f) - curveTo(2.8f, 0f, 2.2f, 5f, 2.2f, 12.8f) - verticalLineToRelative(0f) - lineToRelative(0f, 0f) - curveToRelative(0f, 0f, 0f, 0f, 0f, 0f) - curveTo(2.2f, 24.9f, 15f, 30f, 15f, 30f) - reflectiveCurveTo(27.8f, 24.9f, 27.8f, 12.8f) - curveTo(27.8f, 12.8f, 27.8f, 12.8f, 27.8f, 12.8f) - lineTo(27.8f, 12.8f) - close() - } - path( - fill = SolidColor(Color.Black), - fillAlpha = 1.0f, - stroke = SolidColor(Color.Black), - strokeAlpha = 1.0f, - strokeLineWidth = 0.5f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(15.1f, 24f) - lineToRelative(-0.5f, -0.2f) - curveToRelative(-0.2f, -0.1f, -4.5f, -2f, -6.8f, -6.4f) - curveToRelative(-0.3f, -0.6f, -0.1f, -1.4f, 0.6f, -1.7f) - curveToRelative(0.6f, -0.3f, 1.4f, -0.1f, 1.7f, 0.6f) - curveToRelative(1.4f, 2.8f, 3.9f, 4.4f, 5f, 4.9f) - curveToRelative(1.1f, -0.6f, 3.6f, -2.2f, 5f, -4.9f) - curveToRelative(0.3f, -0.6f, 1.1f, -0.9f, 1.7f, -0.6f) - curveToRelative(0.6f, 0.3f, 0.9f, 1.1f, 0.6f, 1.7f) - curveToRelative(-2.2f, 4.4f, -6.6f, 6.3f, -6.8f, 6.4f) - lineTo(15.1f, 24f) - close() - } - path( - fill = SolidColor(Color.Black), - fillAlpha = 1.0f, - stroke = SolidColor(Color.Black), - strokeAlpha = 1.0f, - strokeLineWidth = 0.5f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(15f, 15f) - curveToRelative(-2.9f, 0f, -5.2f, -2.3f, -5.2f, -5.2f) - reflectiveCurveToRelative(2.3f, -5.2f, 5.2f, -5.2f) - reflectiveCurveToRelative(5.2f, 2.3f, 5.2f, 5.2f) - reflectiveCurveTo(17.8f, 15f, 15f, 15f) - close() - moveTo(15f, 7.2f) - curveToRelative(-1.4f, 0f, -2.6f, 1.2f, -2.6f, 2.6f) - reflectiveCurveToRelative(1.2f, 2.6f, 2.6f, 2.6f) - reflectiveCurveToRelative(2.6f, -1.2f, 2.6f, -2.6f) - reflectiveCurveTo(16.4f, 7.2f, 15f, 7.2f) - close() - } - }.build() - .also { labelsFollowing = it } +// Two-tone follow badge: the shield takes the caller-supplied [accent] so it follows the theme, +// while the inner figure stays white. Build once per accent and cache at the call site. +public fun following(accent: Color): ImageVector = + ImageVector + .Builder( + name = "Following", + defaultWidth = 30.dp, + defaultHeight = 30.dp, + viewportWidth = 30f, + viewportHeight = 30f, + ).apply { + path( + fill = SolidColor(accent), + fillAlpha = 1.0f, + stroke = null, + strokeAlpha = 1.0f, + strokeLineWidth = 1.0f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(27.8f, 12.8f) + lineTo(27.8f, 12.8f) + curveTo(27.8f, 5f, 27.2f, 0f, 24.4f, 0f) + reflectiveCurveTo(15f, 0f, 15f, 0f) + reflectiveCurveTo(8.4f, 0f, 5.6f, 0f) + curveTo(2.8f, 0f, 2.2f, 5f, 2.2f, 12.8f) + verticalLineToRelative(0f) + lineToRelative(0f, 0f) + curveToRelative(0f, 0f, 0f, 0f, 0f, 0f) + curveTo(2.2f, 24.9f, 15f, 30f, 15f, 30f) + reflectiveCurveTo(27.8f, 24.9f, 27.8f, 12.8f) + curveTo(27.8f, 12.8f, 27.8f, 12.8f, 27.8f, 12.8f) + lineTo(27.8f, 12.8f) + close() + } + path( + fill = SolidColor(Color.White), + fillAlpha = 1.0f, + stroke = SolidColor(accent), + strokeAlpha = 1.0f, + strokeLineWidth = 0.5f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(15.1f, 24f) + lineToRelative(-0.5f, -0.2f) + curveToRelative(-0.2f, -0.1f, -4.5f, -2f, -6.8f, -6.4f) + curveToRelative(-0.3f, -0.6f, -0.1f, -1.4f, 0.6f, -1.7f) + curveToRelative(0.6f, -0.3f, 1.4f, -0.1f, 1.7f, 0.6f) + curveToRelative(1.4f, 2.8f, 3.9f, 4.4f, 5f, 4.9f) + curveToRelative(1.1f, -0.6f, 3.6f, -2.2f, 5f, -4.9f) + curveToRelative(0.3f, -0.6f, 1.1f, -0.9f, 1.7f, -0.6f) + curveToRelative(0.6f, 0.3f, 0.9f, 1.1f, 0.6f, 1.7f) + curveToRelative(-2.2f, 4.4f, -6.6f, 6.3f, -6.8f, 6.4f) + lineTo(15.1f, 24f) + close() + } + path( + fill = SolidColor(Color.White), + fillAlpha = 1.0f, + stroke = SolidColor(accent), + strokeAlpha = 1.0f, + strokeLineWidth = 0.5f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(15f, 15f) + curveToRelative(-2.9f, 0f, -5.2f, -2.3f, -5.2f, -5.2f) + reflectiveCurveToRelative(2.3f, -5.2f, 5.2f, -5.2f) + reflectiveCurveToRelative(5.2f, 2.3f, 5.2f, 5.2f) + reflectiveCurveTo(17.8f, 15f, 15f, 15f) + close() + moveTo(15f, 7.2f) + curveToRelative(-1.4f, 0f, -2.6f, 1.2f, -2.6f, 2.6f) + reflectiveCurveToRelative(1.2f, 2.6f, 2.6f, 2.6f) + reflectiveCurveToRelative(2.6f, -1.2f, 2.6f, -2.6f) + reflectiveCurveTo(16.4f, 7.2f, 15f, 7.2f) + close() + } + }.build() From dd03307ac36309db3dda98811d0bd042abe04a86 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 22:59:40 +0000 Subject: [PATCH 11/14] fix: solid accent container tones + keep Following its brand purple MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two more on-device fixes: - Container roles were a faint 0.12/0.16 tint over the surface, so filled shapes like the Settings icon boxes nearly vanished (accent icon on almost no background) and tonal buttons looked washed. Retune the container tones to a moderately saturated fill (mirroring Material's baseline containers, recoloured to the accent) with near-white content in dark mode, so the settings icon boxes and profile-header tonal buttons read as white-on-accent again. - The Following badge keeps its original deep purple (#7F2EFF) instead of following the accent — it reads as a brand identity mark, and the accent-tinted version looked flat. Reverted to the fixed two-tone vector. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../vitorpamplona/amethyst/ui/note/Icons.kt | 6 +- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 43 ++--- .../amethyst/commons/icons/Following.kt | 177 +++++++++--------- 3 files changed, 112 insertions(+), 114 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index 5b7731cef3..27623eb4f1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -35,6 +35,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.hashtags.Amethyst import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons +import com.vitorpamplona.amethyst.commons.icons.Following import com.vitorpamplona.amethyst.commons.icons.Like import com.vitorpamplona.amethyst.commons.icons.Liked import com.vitorpamplona.amethyst.commons.icons.Reply @@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.icons.Repost import com.vitorpamplona.amethyst.commons.icons.Reposted import com.vitorpamplona.amethyst.commons.icons.Search import com.vitorpamplona.amethyst.commons.icons.Zap -import com.vitorpamplona.amethyst.commons.icons.following import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.ui.stringRes @@ -66,10 +66,8 @@ fun AmethystIcon(iconSize: Dp) { @Composable fun FollowingIcon(modifier: Modifier) { - val accent = MaterialTheme.colorScheme.primary - val icon = remember(accent) { following(accent) } Icon( - imageVector = icon, + imageVector = Following, contentDescription = stringRes(id = R.string.following), modifier = modifier, tint = Color.Unspecified, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index f3864fdebe..ca9b74e687 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -106,23 +106,22 @@ private fun onAccent(color: Color): Color { return if (contrastOnBlack >= contrastOnWhite) Color.Black else Color.White } -// Faint accent-tinted fill for the Material3 "container" roles (primaryContainer, etc.), laid -// over the theme's base surface. Left unset, these roles fall back to Material's baseline violet, -// which is why container-backed UI (settings icon boxes, selected reaction chips, zap-amount -// chips, calendar selection, relay-group top bars) stayed purple under every accent. +// Fill for the Material3 "container" roles (primaryContainer, etc.). A moderately saturated tone, +// mirroring Material's baseline containers but recoloured to the accent, so filled shapes such as +// the settings icon boxes, tonal buttons and selected chips stay clearly visible (not a faint +// wash). Dark themes darken the light accent toward a mid tone; light themes lighten the deep +// accent toward a pale tint. Left unset, these roles fall back to Material's baseline violet. private fun accentContainer( - color: Color, - surface: Color, - alpha: Float, -): Color = color.copy(alpha = alpha).compositeOver(surface) - -// Text/icon color drawn on an accentContainer. The container sits close to the base surface, so -// in the dark theme the light accent reads directly; in the light theme it is deepened toward -// black to stay legible on the pale tint. -private fun onAccentContainer( - color: Color, + accent: Color, dark: Boolean, -): Color = if (dark) color else lerp(color, Color.Black, 0.30f) +): Color = if (dark) lerp(accent, Color.Black, 0.58f) else lerp(accent, Color.White, 0.85f) + +// High-contrast content for an accentContainer: near-white in dark (so icons/labels read as white +// on the accent), deep accent in light. +private fun onAccentContainer( + accent: Color, + dark: Boolean, +): Color = if (dark) lerp(accent, Color.White, 0.85f) else lerp(accent, Color.Black, 0.40f) // Representative colour for an accent option, used by the Settings accent-picker swatches — the // same primary the theme would apply for the given light/dark mode, so the swatch previews the @@ -135,22 +134,21 @@ fun contentColorOnAccent(color: Color): Color = onAccent(color) private fun darkColors(accent: AccentColorType): ColorScheme { val primary = accentPrimary(accent, dark = true) val secondary = accentSecondary(accent, dark = true) - val surface = Color.Black return darkColorScheme( primary = primary, onPrimary = Color.White, - primaryContainer = accentContainer(primary, surface, 0.16f), + primaryContainer = accentContainer(primary, dark = true), onPrimaryContainer = onAccentContainer(primary, dark = true), secondary = secondary, onSecondary = onAccent(secondary), // Container roles derive from the accent (primary), not the teal secondary. Secondary/tertiary // container surfaces (FilledTonalButton, tonal chips) were neutral before; deriving them from // teal made them read as teal-on-teal, so they follow the accent hue instead. - secondaryContainer = accentContainer(primary, surface, 0.16f), + secondaryContainer = accentContainer(primary, dark = true), onSecondaryContainer = onAccentContainer(primary, dark = true), tertiary = secondary, onTertiary = onAccent(secondary), - tertiaryContainer = accentContainer(primary, surface, 0.16f), + tertiaryContainer = accentContainer(primary, dark = true), onTertiaryContainer = onAccentContainer(primary, dark = true), inversePrimary = accentPrimary(accent, dark = false), surfaceTint = primary, @@ -178,22 +176,21 @@ private fun darkColors(accent: AccentColorType): ColorScheme { private fun lightColors(accent: AccentColorType): ColorScheme { val primary = accentPrimary(accent, dark = false) val secondary = accentSecondary(accent, dark = false) - val surface = Color.White return lightColorScheme( primary = primary, onPrimary = Color.White, - primaryContainer = accentContainer(primary, surface, 0.12f), + primaryContainer = accentContainer(primary, dark = false), onPrimaryContainer = onAccentContainer(primary, dark = false), secondary = secondary, onSecondary = onAccent(secondary), // Container roles derive from the accent (primary), not the teal secondary. Secondary/tertiary // container surfaces (FilledTonalButton, tonal chips) were neutral before; deriving them from // teal made them read as teal-on-teal, so they follow the accent hue instead. - secondaryContainer = accentContainer(primary, surface, 0.12f), + secondaryContainer = accentContainer(primary, dark = false), onSecondaryContainer = onAccentContainer(primary, dark = false), tertiary = secondary, onTertiary = onAccent(secondary), - tertiaryContainer = accentContainer(primary, surface, 0.12f), + tertiaryContainer = accentContainer(primary, dark = false), onTertiaryContainer = onAccentContainer(primary, dark = false), inversePrimary = accentPrimary(accent, dark = true), surfaceTint = primary, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt index 62e000fc0e..fd6de54a04 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt @@ -35,92 +35,95 @@ import androidx.compose.ui.unit.dp @Preview @Composable private fun VectorPreview() { - Image(following(Color(0xFF7F2EFF)), null) + Image(Following, null) } -// Two-tone follow badge: the shield takes the caller-supplied [accent] so it follows the theme, -// while the inner figure stays white. Build once per accent and cache at the call site. -public fun following(accent: Color): ImageVector = - ImageVector - .Builder( - name = "Following", - defaultWidth = 30.dp, - defaultHeight = 30.dp, - viewportWidth = 30f, - viewportHeight = 30f, - ).apply { - path( - fill = SolidColor(accent), - fillAlpha = 1.0f, - stroke = null, - strokeAlpha = 1.0f, - strokeLineWidth = 1.0f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(27.8f, 12.8f) - lineTo(27.8f, 12.8f) - curveTo(27.8f, 5f, 27.2f, 0f, 24.4f, 0f) - reflectiveCurveTo(15f, 0f, 15f, 0f) - reflectiveCurveTo(8.4f, 0f, 5.6f, 0f) - curveTo(2.8f, 0f, 2.2f, 5f, 2.2f, 12.8f) - verticalLineToRelative(0f) - lineToRelative(0f, 0f) - curveToRelative(0f, 0f, 0f, 0f, 0f, 0f) - curveTo(2.2f, 24.9f, 15f, 30f, 15f, 30f) - reflectiveCurveTo(27.8f, 24.9f, 27.8f, 12.8f) - curveTo(27.8f, 12.8f, 27.8f, 12.8f, 27.8f, 12.8f) - lineTo(27.8f, 12.8f) - close() - } - path( - fill = SolidColor(Color.White), - fillAlpha = 1.0f, - stroke = SolidColor(accent), - strokeAlpha = 1.0f, - strokeLineWidth = 0.5f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(15.1f, 24f) - lineToRelative(-0.5f, -0.2f) - curveToRelative(-0.2f, -0.1f, -4.5f, -2f, -6.8f, -6.4f) - curveToRelative(-0.3f, -0.6f, -0.1f, -1.4f, 0.6f, -1.7f) - curveToRelative(0.6f, -0.3f, 1.4f, -0.1f, 1.7f, 0.6f) - curveToRelative(1.4f, 2.8f, 3.9f, 4.4f, 5f, 4.9f) - curveToRelative(1.1f, -0.6f, 3.6f, -2.2f, 5f, -4.9f) - curveToRelative(0.3f, -0.6f, 1.1f, -0.9f, 1.7f, -0.6f) - curveToRelative(0.6f, 0.3f, 0.9f, 1.1f, 0.6f, 1.7f) - curveToRelative(-2.2f, 4.4f, -6.6f, 6.3f, -6.8f, 6.4f) - lineTo(15.1f, 24f) - close() - } - path( - fill = SolidColor(Color.White), - fillAlpha = 1.0f, - stroke = SolidColor(accent), - strokeAlpha = 1.0f, - strokeLineWidth = 0.5f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(15f, 15f) - curveToRelative(-2.9f, 0f, -5.2f, -2.3f, -5.2f, -5.2f) - reflectiveCurveToRelative(2.3f, -5.2f, 5.2f, -5.2f) - reflectiveCurveToRelative(5.2f, 2.3f, 5.2f, 5.2f) - reflectiveCurveTo(17.8f, 15f, 15f, 15f) - close() - moveTo(15f, 7.2f) - curveToRelative(-1.4f, 0f, -2.6f, 1.2f, -2.6f, 2.6f) - reflectiveCurveToRelative(1.2f, 2.6f, 2.6f, 2.6f) - reflectiveCurveToRelative(2.6f, -1.2f, 2.6f, -2.6f) - reflectiveCurveTo(16.4f, 7.2f, 15f, 7.2f) - close() - } - }.build() +private var labelsFollowing: ImageVector? = null + +// Brand identity badge: keeps its own deep purple regardless of the selected accent. +public val Following: ImageVector + get() = + labelsFollowing ?: ImageVector + .Builder( + name = "Following", + defaultWidth = 30.dp, + defaultHeight = 30.dp, + viewportWidth = 30f, + viewportHeight = 30f, + ).apply { + path( + fill = SolidColor(Color(0xFF7F2EFF)), + fillAlpha = 1.0f, + stroke = null, + strokeAlpha = 1.0f, + strokeLineWidth = 1.0f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(27.8f, 12.8f) + lineTo(27.8f, 12.8f) + curveTo(27.8f, 5f, 27.2f, 0f, 24.4f, 0f) + reflectiveCurveTo(15f, 0f, 15f, 0f) + reflectiveCurveTo(8.4f, 0f, 5.6f, 0f) + curveTo(2.8f, 0f, 2.2f, 5f, 2.2f, 12.8f) + verticalLineToRelative(0f) + lineToRelative(0f, 0f) + curveToRelative(0f, 0f, 0f, 0f, 0f, 0f) + curveTo(2.2f, 24.9f, 15f, 30f, 15f, 30f) + reflectiveCurveTo(27.8f, 24.9f, 27.8f, 12.8f) + curveTo(27.8f, 12.8f, 27.8f, 12.8f, 27.8f, 12.8f) + lineTo(27.8f, 12.8f) + close() + } + path( + fill = SolidColor(Color(0xFFFFFFFF)), + fillAlpha = 1.0f, + stroke = SolidColor(Color(0xFF7F2EFF)), + strokeAlpha = 1.0f, + strokeLineWidth = 0.5f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(15.1f, 24f) + lineToRelative(-0.5f, -0.2f) + curveToRelative(-0.2f, -0.1f, -4.5f, -2f, -6.8f, -6.4f) + curveToRelative(-0.3f, -0.6f, -0.1f, -1.4f, 0.6f, -1.7f) + curveToRelative(0.6f, -0.3f, 1.4f, -0.1f, 1.7f, 0.6f) + curveToRelative(1.4f, 2.8f, 3.9f, 4.4f, 5f, 4.9f) + curveToRelative(1.1f, -0.6f, 3.6f, -2.2f, 5f, -4.9f) + curveToRelative(0.3f, -0.6f, 1.1f, -0.9f, 1.7f, -0.6f) + curveToRelative(0.6f, 0.3f, 0.9f, 1.1f, 0.6f, 1.7f) + curveToRelative(-2.2f, 4.4f, -6.6f, 6.3f, -6.8f, 6.4f) + lineTo(15.1f, 24f) + close() + } + path( + fill = SolidColor(Color(0xFFFFFFFF)), + fillAlpha = 1.0f, + stroke = SolidColor(Color(0xFF7F2EFF)), + strokeAlpha = 1.0f, + strokeLineWidth = 0.5f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(15f, 15f) + curveToRelative(-2.9f, 0f, -5.2f, -2.3f, -5.2f, -5.2f) + reflectiveCurveToRelative(2.3f, -5.2f, 5.2f, -5.2f) + reflectiveCurveToRelative(5.2f, 2.3f, 5.2f, 5.2f) + reflectiveCurveTo(17.8f, 15f, 15f, 15f) + close() + moveTo(15f, 7.2f) + curveToRelative(-1.4f, 0f, -2.6f, 1.2f, -2.6f, 2.6f) + reflectiveCurveToRelative(1.2f, 2.6f, 2.6f, 2.6f) + reflectiveCurveToRelative(2.6f, -1.2f, 2.6f, -2.6f) + reflectiveCurveTo(16.4f, 7.2f, 15f, 7.2f) + close() + } + }.build() + .also { labelsFollowing = it } From 8891e3a1a7603ce8ce9597fdfaccc2ad3690e9a1 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 23:33:01 +0000 Subject: [PATCH 12/14] feat: match the Following badge to the FilledTonalButton palette Per review, the follow badge now uses the same two colours as the tonal buttons (Show more, profile actions): the shield is secondaryContainer and the inner figure is onSecondaryContainer. The vector is a following(shield, figure) builder cached per colour at the call site, so the badge follows the accent and stays visually consistent with the tonal buttons in both themes. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../vitorpamplona/amethyst/ui/note/Icons.kt | 8 +- .../amethyst/commons/icons/Following.kt | 181 +++++++++--------- 2 files changed, 97 insertions(+), 92 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index 27623eb4f1..a2ad634813 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -35,7 +35,6 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.hashtags.Amethyst import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons -import com.vitorpamplona.amethyst.commons.icons.Following import com.vitorpamplona.amethyst.commons.icons.Like import com.vitorpamplona.amethyst.commons.icons.Liked import com.vitorpamplona.amethyst.commons.icons.Reply @@ -43,6 +42,7 @@ import com.vitorpamplona.amethyst.commons.icons.Repost import com.vitorpamplona.amethyst.commons.icons.Reposted import com.vitorpamplona.amethyst.commons.icons.Search import com.vitorpamplona.amethyst.commons.icons.Zap +import com.vitorpamplona.amethyst.commons.icons.following import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.ui.stringRes @@ -66,8 +66,12 @@ fun AmethystIcon(iconSize: Dp) { @Composable fun FollowingIcon(modifier: Modifier) { + // Match the FilledTonalButton palette: shield = secondaryContainer, figure = onSecondaryContainer. + val shield = MaterialTheme.colorScheme.secondaryContainer + val figure = MaterialTheme.colorScheme.onSecondaryContainer + val icon = remember(shield, figure) { following(shield, figure) } Icon( - imageVector = Following, + imageVector = icon, contentDescription = stringRes(id = R.string.following), modifier = modifier, tint = Color.Unspecified, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt index fd6de54a04..216343a4cb 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/Following.kt @@ -35,95 +35,96 @@ import androidx.compose.ui.unit.dp @Preview @Composable private fun VectorPreview() { - Image(Following, null) + Image(following(Color(0xFF7F2EFF), Color.White), null) } -private var labelsFollowing: ImageVector? = null - -// Brand identity badge: keeps its own deep purple regardless of the selected accent. -public val Following: ImageVector - get() = - labelsFollowing ?: ImageVector - .Builder( - name = "Following", - defaultWidth = 30.dp, - defaultHeight = 30.dp, - viewportWidth = 30f, - viewportHeight = 30f, - ).apply { - path( - fill = SolidColor(Color(0xFF7F2EFF)), - fillAlpha = 1.0f, - stroke = null, - strokeAlpha = 1.0f, - strokeLineWidth = 1.0f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(27.8f, 12.8f) - lineTo(27.8f, 12.8f) - curveTo(27.8f, 5f, 27.2f, 0f, 24.4f, 0f) - reflectiveCurveTo(15f, 0f, 15f, 0f) - reflectiveCurveTo(8.4f, 0f, 5.6f, 0f) - curveTo(2.8f, 0f, 2.2f, 5f, 2.2f, 12.8f) - verticalLineToRelative(0f) - lineToRelative(0f, 0f) - curveToRelative(0f, 0f, 0f, 0f, 0f, 0f) - curveTo(2.2f, 24.9f, 15f, 30f, 15f, 30f) - reflectiveCurveTo(27.8f, 24.9f, 27.8f, 12.8f) - curveTo(27.8f, 12.8f, 27.8f, 12.8f, 27.8f, 12.8f) - lineTo(27.8f, 12.8f) - close() - } - path( - fill = SolidColor(Color(0xFFFFFFFF)), - fillAlpha = 1.0f, - stroke = SolidColor(Color(0xFF7F2EFF)), - strokeAlpha = 1.0f, - strokeLineWidth = 0.5f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(15.1f, 24f) - lineToRelative(-0.5f, -0.2f) - curveToRelative(-0.2f, -0.1f, -4.5f, -2f, -6.8f, -6.4f) - curveToRelative(-0.3f, -0.6f, -0.1f, -1.4f, 0.6f, -1.7f) - curveToRelative(0.6f, -0.3f, 1.4f, -0.1f, 1.7f, 0.6f) - curveToRelative(1.4f, 2.8f, 3.9f, 4.4f, 5f, 4.9f) - curveToRelative(1.1f, -0.6f, 3.6f, -2.2f, 5f, -4.9f) - curveToRelative(0.3f, -0.6f, 1.1f, -0.9f, 1.7f, -0.6f) - curveToRelative(0.6f, 0.3f, 0.9f, 1.1f, 0.6f, 1.7f) - curveToRelative(-2.2f, 4.4f, -6.6f, 6.3f, -6.8f, 6.4f) - lineTo(15.1f, 24f) - close() - } - path( - fill = SolidColor(Color(0xFFFFFFFF)), - fillAlpha = 1.0f, - stroke = SolidColor(Color(0xFF7F2EFF)), - strokeAlpha = 1.0f, - strokeLineWidth = 0.5f, - strokeLineCap = StrokeCap.Butt, - strokeLineJoin = StrokeJoin.Miter, - strokeLineMiter = 1.0f, - pathFillType = PathFillType.NonZero, - ) { - moveTo(15f, 15f) - curveToRelative(-2.9f, 0f, -5.2f, -2.3f, -5.2f, -5.2f) - reflectiveCurveToRelative(2.3f, -5.2f, 5.2f, -5.2f) - reflectiveCurveToRelative(5.2f, 2.3f, 5.2f, 5.2f) - reflectiveCurveTo(17.8f, 15f, 15f, 15f) - close() - moveTo(15f, 7.2f) - curveToRelative(-1.4f, 0f, -2.6f, 1.2f, -2.6f, 2.6f) - reflectiveCurveToRelative(1.2f, 2.6f, 2.6f, 2.6f) - reflectiveCurveToRelative(2.6f, -1.2f, 2.6f, -2.6f) - reflectiveCurveTo(16.4f, 7.2f, 15f, 7.2f) - close() - } - }.build() - .also { labelsFollowing = it } +// Two-tone follow badge. [shield] fills the outer shape and outlines the figure; [figure] fills the +// inner person. Callers pass the FilledTonalButton pair (secondaryContainer / onSecondaryContainer) +// so the badge tracks the accent and matches the tonal buttons. Build once and cache with remember(). +public fun following( + shield: Color, + figure: Color, +): ImageVector = + ImageVector + .Builder( + name = "Following", + defaultWidth = 30.dp, + defaultHeight = 30.dp, + viewportWidth = 30f, + viewportHeight = 30f, + ).apply { + path( + fill = SolidColor(shield), + fillAlpha = 1.0f, + stroke = null, + strokeAlpha = 1.0f, + strokeLineWidth = 1.0f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(27.8f, 12.8f) + lineTo(27.8f, 12.8f) + curveTo(27.8f, 5f, 27.2f, 0f, 24.4f, 0f) + reflectiveCurveTo(15f, 0f, 15f, 0f) + reflectiveCurveTo(8.4f, 0f, 5.6f, 0f) + curveTo(2.8f, 0f, 2.2f, 5f, 2.2f, 12.8f) + verticalLineToRelative(0f) + lineToRelative(0f, 0f) + curveToRelative(0f, 0f, 0f, 0f, 0f, 0f) + curveTo(2.2f, 24.9f, 15f, 30f, 15f, 30f) + reflectiveCurveTo(27.8f, 24.9f, 27.8f, 12.8f) + curveTo(27.8f, 12.8f, 27.8f, 12.8f, 27.8f, 12.8f) + lineTo(27.8f, 12.8f) + close() + } + path( + fill = SolidColor(figure), + fillAlpha = 1.0f, + stroke = SolidColor(shield), + strokeAlpha = 1.0f, + strokeLineWidth = 0.5f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(15.1f, 24f) + lineToRelative(-0.5f, -0.2f) + curveToRelative(-0.2f, -0.1f, -4.5f, -2f, -6.8f, -6.4f) + curveToRelative(-0.3f, -0.6f, -0.1f, -1.4f, 0.6f, -1.7f) + curveToRelative(0.6f, -0.3f, 1.4f, -0.1f, 1.7f, 0.6f) + curveToRelative(1.4f, 2.8f, 3.9f, 4.4f, 5f, 4.9f) + curveToRelative(1.1f, -0.6f, 3.6f, -2.2f, 5f, -4.9f) + curveToRelative(0.3f, -0.6f, 1.1f, -0.9f, 1.7f, -0.6f) + curveToRelative(0.6f, 0.3f, 0.9f, 1.1f, 0.6f, 1.7f) + curveToRelative(-2.2f, 4.4f, -6.6f, 6.3f, -6.8f, 6.4f) + lineTo(15.1f, 24f) + close() + } + path( + fill = SolidColor(figure), + fillAlpha = 1.0f, + stroke = SolidColor(shield), + strokeAlpha = 1.0f, + strokeLineWidth = 0.5f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1.0f, + pathFillType = PathFillType.NonZero, + ) { + moveTo(15f, 15f) + curveToRelative(-2.9f, 0f, -5.2f, -2.3f, -5.2f, -5.2f) + reflectiveCurveToRelative(2.3f, -5.2f, 5.2f, -5.2f) + reflectiveCurveToRelative(5.2f, 2.3f, 5.2f, 5.2f) + reflectiveCurveTo(17.8f, 15f, 15f, 15f) + close() + moveTo(15f, 7.2f) + curveToRelative(-1.4f, 0f, -2.6f, 1.2f, -2.6f, 2.6f) + reflectiveCurveToRelative(1.2f, 2.6f, 2.6f, 2.6f) + reflectiveCurveToRelative(2.6f, -1.2f, 2.6f, -2.6f) + reflectiveCurveTo(16.4f, 7.2f, 15f, 7.2f) + close() + } + }.build() From 2af730e5f783a8ca6090554e494cfdb1cca614e3 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 23:46:29 +0000 Subject: [PATCH 13/14] feat: give the Following badge a vivid accent shield with a white figure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tying the badge to the tonal-button palette (secondaryContainer) made it read too dark against profile photos. Match the original badge look instead — a vivid shield with a white figure — recoloured to the accent: shield = primary, figure = onPrimary. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index a2ad634813..d3ed0d849a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -66,9 +66,10 @@ fun AmethystIcon(iconSize: Dp) { @Composable fun FollowingIcon(modifier: Modifier) { - // Match the FilledTonalButton palette: shield = secondaryContainer, figure = onSecondaryContainer. - val shield = MaterialTheme.colorScheme.secondaryContainer - val figure = MaterialTheme.colorScheme.onSecondaryContainer + // Match the previous badge look — a vivid accent shield with a white figure — recoloured to the + // selected accent: shield = primary, figure = onPrimary. + val shield = MaterialTheme.colorScheme.primary + val figure = MaterialTheme.colorScheme.onPrimary val icon = remember(shield, figure) { following(shield, figure) } Icon( imageVector = icon, From 011b2ee862746d2915e7ec13e962a33b6faa9b32 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 23:58:41 +0000 Subject: [PATCH 14/14] fix: use the accent's deep tone for the Following shield MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dark-theme primary is a pale pastel, so the follow shield read washed out versus the original dark #7F2EFF. Use the accent's deep tone (its light-theme primary) in both themes — carried by inversePrimary in the dark scheme — so the shield stays a dark, saturated accent with a white figure, matching the original badge's depth while still following the selected accent. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69 --- .../com/vitorpamplona/amethyst/ui/note/Icons.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index d3ed0d849a..29feeb08aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size19Modifier import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.Size30Modifier import com.vitorpamplona.amethyst.ui.theme.grayText +import com.vitorpamplona.amethyst.ui.theme.isLight import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.subtleButton @@ -66,11 +67,13 @@ fun AmethystIcon(iconSize: Dp) { @Composable fun FollowingIcon(modifier: Modifier) { - // Match the previous badge look — a vivid accent shield with a white figure — recoloured to the - // selected accent: shield = primary, figure = onPrimary. - val shield = MaterialTheme.colorScheme.primary - val figure = MaterialTheme.colorScheme.onPrimary - val icon = remember(shield, figure) { following(shield, figure) } + // Deep, saturated accent shield + white figure, like the original #7F2EFF badge. Use the accent's + // deep tone (its light-theme primary) in both themes: dark-theme `primary` is a pale pastel, so + // the shield would read washed out — inversePrimary carries the deep tone in the dark scheme, + // while `primary` already is it in light. + val scheme = MaterialTheme.colorScheme + val shield = if (scheme.isLight) scheme.primary else scheme.inversePrimary + val icon = remember(shield) { following(shield, Color.White) } Icon( imageVector = icon, contentDescription = stringRes(id = R.string.following),