From 0c3711ea150bc2d3c9035fda6c60b759cf55ecd3 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 18 Jun 2026 03:54:14 +0000 Subject: [PATCH] feat(ui): modernize the quote/repost choice popup Replace the bare row of three flat primary-coloured buttons in the boost/quote/fork popup with the same card-and-pill treatment used by the reaction and zap popups: an elevated surfaceVariant card holding pill chips, each with a coloured leading icon (repost, quote, fork) next to its label and the soft outline the zap rails use, so the three action popups read as one family. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_016a27kWKUcpADUC1KhXHRpV --- .../amethyst/ui/note/ReactionsRow.kt | 169 +++++++++++++----- 1 file changed, 123 insertions(+), 46 deletions(-) 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 9573f040ac..bc628bdb96 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 @@ -44,6 +44,7 @@ import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement @@ -59,8 +60,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ElevatedCard @@ -1618,7 +1617,6 @@ private fun BoostTypeChoicePopup( ) } -@OptIn(ExperimentalLayoutApi::class) @Composable private fun BoostTypeChoicePopup( baseNote: Note, @@ -1642,52 +1640,81 @@ private fun BoostTypeChoicePopup( enter = popupAnimationEnter, exit = popupAnimationExit, ) { - FlowRow { - Button( - modifier = Modifier.padding(horizontal = 3.dp), - onClick = { - if (accountViewModel.isWriteable()) { - accountViewModel.boost(baseNote) - visibilityState.targetState = false - } else { - onRepost() - visibilityState.targetState = false - } - }, - shape = ButtonBorder, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text(stringRes(R.string.boost), color = Color.White, textAlign = TextAlign.Center) - } - - Button( - modifier = Modifier.padding(horizontal = 3.dp), - onClick = onQuote, - shape = ButtonBorder, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text(stringRes(R.string.quote), color = Color.White, textAlign = TextAlign.Center) - } - + BoostTypeChoicePopupContent( // removes the option to fork for now because we do not have screens for // LongForm, Wiki and NIP posting. - if (baseNote.event is TextNoteEvent) { - Button( - modifier = Modifier.padding(horizontal = 3.dp), + showFork = baseNote.event is TextNoteEvent, + onBoost = { + if (accountViewModel.isWriteable()) { + accountViewModel.boost(baseNote) + } else { + onRepost() + } + visibilityState.targetState = false + }, + onQuote = { + onQuote() + visibilityState.targetState = false + }, + onFork = { + onFork() + visibilityState.targetState = false + }, + ) + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun BoostTypeChoicePopupContent( + showFork: Boolean, + onBoost: () -> Unit, + onQuote: () -> Unit, + onFork: () -> Unit, +) { + Box(HalfPadding, contentAlignment = Center) { + ElevatedCard( + shape = SmallBorder, + elevation = CardDefaults.elevatedCardElevation(defaultElevation = 8.dp), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant), + ) { + FlowRow( + modifier = Modifier.padding(horizontal = 5.dp, vertical = 5.dp), + horizontalArrangement = Arrangement.Center, + verticalArrangement = Arrangement.Center, + itemVerticalAlignment = CenterVertically, + ) { + BoostActionChip( + label = stringRes(R.string.boost), + onClick = onBoost, + ) { tint -> + RepostedIcon(Size18Modifier, tint) + } + + BoostActionChip( + label = stringRes(R.string.quote), + onClick = onQuote, + ) { tint -> + Icon( + symbol = MaterialSymbols.FormatQuote, + contentDescription = null, + modifier = Size18Modifier, + tint = tint, + ) + } + + if (showFork) { + BoostActionChip( + label = stringRes(R.string.fork), onClick = onFork, - shape = ButtonBorder, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text(stringRes(R.string.fork), color = Color.White, textAlign = TextAlign.Center) + ) { tint -> + Icon( + symbol = MaterialSymbols.EditNote, + contentDescription = null, + modifier = Size18Modifier, + tint = tint, + ) } } } @@ -1695,6 +1722,56 @@ private fun BoostTypeChoicePopup( } } +/** + * A single quote/repost action rendered as a pill: a coloured leading icon next + * to its label, wrapped in the same soft-outlined surface the zap rails use so + * the popups read as one family. + */ +@Composable +private fun BoostActionChip( + label: String, + onClick: () -> Unit, + icon: @Composable (Color) -> Unit, +) { + Surface( + shape = ButtonBorder, + color = MaterialTheme.colorScheme.surfaceVariant, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant), + modifier = Modifier.padding(horizontal = 4.dp, vertical = 6.dp), + ) { + Row( + modifier = + Modifier + .clip(ButtonBorder) + .clickable(onClick = onClick) + .padding(horizontal = 12.dp, vertical = 8.dp), + verticalAlignment = CenterVertically, + ) { + icon(MaterialTheme.colorScheme.primary) + Spacer(Modifier.width(6.dp)) + Text( + text = label, + color = MaterialTheme.colorScheme.onSurface, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Center, + ) + } + } +} + +@Preview +@Composable +fun BoostTypeChoicePopupPreview() { + ThemeComparisonColumn { + BoostTypeChoicePopupContent( + showFork = true, + onBoost = {}, + onQuote = {}, + onFork = {}, + ) + } +} + val popupAnimationEnter: EnterTransition = slideInVertically( animationSpec = defaultTweenIntOffsetSpec,