mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 16:57:39 +00:00
Revert "feat: modernize reaction and zap cards into activity cards"
This reverts commit 11b991ef50.
This commit is contained in:
@@ -90,7 +90,6 @@ import com.vitorpamplona.amethyst.ui.note.elements.Reward
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.ShowForkInformation
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.StaleRelayHint
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo
|
||||
import com.vitorpamplona.amethyst.ui.note.types.ActivityActionChip
|
||||
import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay
|
||||
import com.vitorpamplona.amethyst.ui.note.types.DisplayBlockedRelayList
|
||||
import com.vitorpamplona.amethyst.ui.note.types.DisplayBroadcastRelayList
|
||||
@@ -1737,22 +1736,18 @@ fun FirstUserInfoRow(
|
||||
null
|
||||
}
|
||||
|
||||
Row(Modifier.weight(1f), verticalAlignment = CenterVertically) {
|
||||
if (zapSender != null) {
|
||||
if (showAuthorPicture) {
|
||||
UserPicture(zapSender, Size25dp, accountViewModel = accountViewModel, nav = nav)
|
||||
Spacer(HalfPadding)
|
||||
}
|
||||
UsernameDisplay(zapSender, Modifier.weight(1f, fill = false), textColor = textColor, accountViewModel = accountViewModel)
|
||||
} else if (showAuthorPicture) {
|
||||
NoteAuthorPicture(baseNote, Size25dp, accountViewModel = accountViewModel, nav = nav)
|
||||
if (zapSender != null) {
|
||||
if (showAuthorPicture) {
|
||||
UserPicture(zapSender, Size25dp, accountViewModel = accountViewModel, nav = nav)
|
||||
Spacer(HalfPadding)
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f, fill = false), textColor = textColor, accountViewModel = accountViewModel)
|
||||
} else {
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f, fill = false), textColor = textColor, accountViewModel = accountViewModel)
|
||||
}
|
||||
|
||||
ActivityActionChip(baseNote, accountViewModel, nav)
|
||||
UsernameDisplay(zapSender, Modifier.weight(1f), textColor = textColor, accountViewModel = accountViewModel)
|
||||
} else if (showAuthorPicture) {
|
||||
NoteAuthorPicture(baseNote, Size25dp, accountViewModel = accountViewModel, nav = nav)
|
||||
Spacer(HalfPadding)
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor, accountViewModel = accountViewModel)
|
||||
} else {
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor, accountViewModel = accountViewModel)
|
||||
}
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.Cashu
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.LikedIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmountInteger
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size16Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size19Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.bitcoinColor
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.claimedSatsTotal
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
import androidx.compose.material3.Icon as Material3Icon
|
||||
|
||||
/**
|
||||
* Inline "activity" chip for the author header of reaction and zap cards:
|
||||
* the action (emoji, or amount → recipient) renders next to the actor's name,
|
||||
* so the card reads as "Alice ❤️" / "Alice ⚡ 500 → Bob" with the target post
|
||||
* quoted below. Renders nothing for other kinds.
|
||||
*/
|
||||
@Composable
|
||||
fun ActivityActionChip(
|
||||
baseNote: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
when (val event = baseNote.event) {
|
||||
is ReactionEvent -> {
|
||||
Spacer(HalfPadding)
|
||||
ReactionActionChip(event.content)
|
||||
}
|
||||
|
||||
is LnZapEvent -> {
|
||||
Spacer(HalfPadding)
|
||||
AmountToRecipientChip(
|
||||
amount = showAmountInteger(event.amount),
|
||||
recipient = event.zappedAuthor().firstOrNull(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
) {
|
||||
ZapIcon(Size19Modifier, MaterialTheme.colorScheme.bitcoinColor)
|
||||
}
|
||||
}
|
||||
|
||||
is NutzapEvent -> {
|
||||
Spacer(HalfPadding)
|
||||
AmountToRecipientChip(
|
||||
amount = showAmount(BigDecimal(event.claimedSatsTotal())),
|
||||
recipient = event.linkedPubKeys().firstOrNull(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
) {
|
||||
Material3Icon(
|
||||
imageVector = CustomHashTagIcons.Cashu,
|
||||
contentDescription = null,
|
||||
modifier = Size16Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReactionActionChip(reactionType: String) {
|
||||
if (reactionType.startsWith(":")) {
|
||||
val url = reactionType.removePrefix(":").substringAfter(":")
|
||||
InLineIconRenderer(
|
||||
persistentListOf(CustomEmoji.ImageUrlType(url)),
|
||||
style = SpanStyle(color = MaterialTheme.colorScheme.onBackground),
|
||||
maxLines = 1,
|
||||
fontSize = 16.sp,
|
||||
)
|
||||
} else {
|
||||
when (reactionType) {
|
||||
"+" -> LikedIcon(Size19Modifier)
|
||||
"-" ->
|
||||
Text(
|
||||
text = "👎",
|
||||
maxLines = 1,
|
||||
fontSize = 16.sp,
|
||||
)
|
||||
|
||||
else ->
|
||||
Text(
|
||||
text = reactionType,
|
||||
maxLines = 1,
|
||||
fontSize = 16.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AmountToRecipientChip(
|
||||
amount: String,
|
||||
recipient: HexKey?,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
icon: @Composable () -> Unit,
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
icon()
|
||||
|
||||
Text(
|
||||
text = amount,
|
||||
color = MaterialTheme.colorScheme.bitcoinColor,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 14.sp,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
||||
recipient?.let {
|
||||
Icon(
|
||||
symbol = MaterialSymbols.AutoMirrored.ArrowForwardIos,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.bitcoinColor,
|
||||
modifier = Size16Modifier,
|
||||
)
|
||||
UserPicture(it, Size20dp, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,23 +20,23 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.claimedSatsTotal
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Renders a NIP-61 nutzap (kind 9321) as an activity card, like lightning zaps.
|
||||
* Renders a NIP-61 nutzap (kind 9321) as a transfer card, like lightning zaps.
|
||||
* Unlike kind 9735 receipts, the nutzap is signed by the sender, so [Note.author]
|
||||
* is already the right person to attribute; the amount and recipient render in
|
||||
* the card header (ActivityActionChip). The body is the comment, when present,
|
||||
* over the quoted target post.
|
||||
* is already the right person to attribute.
|
||||
*/
|
||||
@Composable
|
||||
fun RenderNutzap(
|
||||
@@ -48,10 +48,25 @@ fun RenderNutzap(
|
||||
) {
|
||||
val nutzapEvent = note.event as? NutzapEvent ?: return
|
||||
|
||||
nutzapEvent.content.ifBlank { null }?.let {
|
||||
CrossfadeToDisplayComment(it, backgroundColor, nav, accountViewModel)
|
||||
Spacer(StdVertSpacer)
|
||||
}
|
||||
val recipientKey = nutzapEvent.linkedPubKeys().firstOrNull() ?: return
|
||||
|
||||
RenderActionTarget(note, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
RenderZappedPost(note, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
|
||||
val card =
|
||||
remember(note) {
|
||||
ZapAmountCommentNotification(
|
||||
user = note.author,
|
||||
comment = nutzapEvent.content.ifBlank { null },
|
||||
amount = showAmount(BigDecimal(nutzapEvent.claimedSatsTotal())),
|
||||
zapNote = note,
|
||||
)
|
||||
}
|
||||
|
||||
TransferCard(
|
||||
card,
|
||||
recipientKey,
|
||||
backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ fun RenderOnchainZap(
|
||||
val sender = note.author?.pubkeyHex ?: event.pubKey
|
||||
val recipient = event.recipient() ?: return
|
||||
|
||||
RenderActionTarget(note, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
RenderZappedPost(note, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
val sats = event.claimedAmountInSats() ?: 0L
|
||||
val txid = event.txid()
|
||||
val message = event.content.takeIf { it.isNotBlank() }
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
@@ -35,7 +38,25 @@ fun RenderReaction(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
// The reaction emoji renders in the card header (ActivityActionChip);
|
||||
// the body is just the post being reacted to, framed as a quote.
|
||||
RenderActionTarget(note, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
note.replyTo?.lastOrNull()?.let {
|
||||
NoteCompose(
|
||||
it,
|
||||
modifier = Modifier,
|
||||
isBoostedNote = true,
|
||||
makeItShort = true,
|
||||
unPackReply = ReplyRenderType.NONE,
|
||||
quotesLeft = quotesLeft - 1,
|
||||
parentBackgroundColor = backgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
// Reposts have trash in their contents.
|
||||
val refactorReactionText = if (note.event?.content == "+") "❤" else note.event?.content ?: ""
|
||||
|
||||
Text(
|
||||
text = refactorReactionText,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -55,32 +55,30 @@ import com.vitorpamplona.amethyst.ui.theme.Size24Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.SpacedBy5dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.ui.theme.bitcoinColor
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* Shows the post a reaction or zap targets, framed as a quote so it reads as
|
||||
* subordinate to the activity card around it.
|
||||
* Shows the post a zap targets above the transfer card, mirroring how
|
||||
* reactions and reposts embed their target.
|
||||
*/
|
||||
@Composable
|
||||
fun RenderActionTarget(
|
||||
actionNote: Note,
|
||||
fun RenderZappedPost(
|
||||
zapNote: Note,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
actionNote.replyTo?.lastOrNull()?.let {
|
||||
zapNote.replyTo?.lastOrNull()?.let {
|
||||
NoteCompose(
|
||||
it,
|
||||
modifier = MaterialTheme.colorScheme.replyModifier,
|
||||
isQuotedNote = true,
|
||||
modifier = Modifier,
|
||||
isBoostedNote = true,
|
||||
makeItShort = true,
|
||||
unPackReply = ReplyRenderType.NONE,
|
||||
quotesLeft = quotesLeft - 1,
|
||||
@@ -99,19 +97,22 @@ fun RenderLnZap(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
if (note.event !is LnZapEvent) return
|
||||
val zapEvent = note.event as? LnZapEvent ?: return
|
||||
|
||||
RenderZappedPost(note, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
|
||||
// The amount and sender render in the card header (ActivityActionChip plus
|
||||
// the zap-sender attribution); the body is the zap comment, when present,
|
||||
// over the quoted target post.
|
||||
val card by parseAuthorCommentAndAmount(note, accountViewModel)
|
||||
|
||||
card.comment?.let {
|
||||
CrossfadeToDisplayComment(it, backgroundColor, nav, accountViewModel)
|
||||
Spacer(StdVertSpacer)
|
||||
}
|
||||
val destinationKey = zapEvent.zappedAuthor().firstOrNull() ?: return
|
||||
|
||||
RenderActionTarget(note, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
TransferCard(
|
||||
card,
|
||||
destinationKey,
|
||||
backgroundColor,
|
||||
Modifier,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-9
@@ -124,7 +124,6 @@ import com.vitorpamplona.amethyst.ui.note.elements.ShowForkInformation
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo
|
||||
import com.vitorpamplona.amethyst.ui.note.observeEdits
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.note.types.ActivityActionChip
|
||||
import com.vitorpamplona.amethyst.ui.note.types.AudioHeader
|
||||
import com.vitorpamplona.amethyst.ui.note.types.AudioTrackHeader
|
||||
import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay
|
||||
@@ -554,14 +553,10 @@ private fun FullBleedNoteCompose(
|
||||
|
||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(Modifier.weight(1f), verticalAlignment = Alignment.CenterVertically) {
|
||||
if (zapSender != null) {
|
||||
UsernameDisplay(zapSender, Modifier.weight(1f, fill = false), accountViewModel = accountViewModel)
|
||||
} else {
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f, fill = false), accountViewModel = accountViewModel)
|
||||
}
|
||||
|
||||
ActivityActionChip(baseNote, accountViewModel, nav)
|
||||
if (zapSender != null) {
|
||||
UsernameDisplay(zapSender, Modifier.weight(1f), accountViewModel = accountViewModel)
|
||||
} else {
|
||||
NoteUsernameDisplay(baseNote, Modifier.weight(1f), accountViewModel = accountViewModel)
|
||||
}
|
||||
|
||||
if (isDraft) {
|
||||
|
||||
Reference in New Issue
Block a user