mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 16:14:40 +00:00
Basic (ugly) rendering of Zap events when quoted inside of posts.
This commit is contained in:
@@ -422,7 +422,7 @@ data class ZapAmountCommentNotification(
|
||||
@Composable
|
||||
private fun ParseAuthorCommentAndAmount(
|
||||
zapRequest: Note,
|
||||
zapEvent: Note?,
|
||||
zapEvent: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
onReady: @Composable (MutableState<ZapAmountCommentNotification>) -> Unit,
|
||||
) {
|
||||
@@ -437,7 +437,7 @@ private fun ParseAuthorCommentAndAmount(
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = zapRequest.idHex, key2 = zapEvent?.idHex) {
|
||||
LaunchedEffect(key1 = zapRequest.idHex, key2 = zapEvent.idHex) {
|
||||
accountViewModel.decryptAmountMessage(zapRequest, zapEvent) { newState ->
|
||||
if (newState != null) {
|
||||
content.value = newState
|
||||
|
||||
@@ -117,6 +117,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityChatMessage
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLiveChessChallenge
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLiveChessGameEnd
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLnZap
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLongFormContent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderNIP90ContentDiscoveryResponse
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderNIP90Status
|
||||
@@ -210,6 +211,7 @@ import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessa
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
|
||||
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.hasZapSplitSetup
|
||||
import com.vitorpamplona.quartz.nip58Badges.BadgeAwardEvent
|
||||
import com.vitorpamplona.quartz.nip58Badges.BadgeDefinitionEvent
|
||||
@@ -793,6 +795,10 @@ private fun RenderNoteRow(
|
||||
RenderBadgeAward(baseNote, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is LnZapEvent -> {
|
||||
RenderLnZap(baseNote, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is FhirResourceEvent -> {
|
||||
RenderFhirResource(baseNote, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowForwardIos
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
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.tooling.preview.Preview
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapIcon
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
||||
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.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.ui.theme.bitcoinColor
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun RenderLnZap(
|
||||
note: Note,
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val zapEvent = note.event as? LnZapEvent ?: return
|
||||
|
||||
val card by parseAuthorCommentAndAmount(note, accountViewModel)
|
||||
|
||||
val destinationKey = zapEvent.zappedAuthor().firstOrNull() ?: return
|
||||
|
||||
TransferCard(
|
||||
card,
|
||||
destinationKey,
|
||||
backgroundColor,
|
||||
Modifier,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun parseAuthorCommentAndAmount(
|
||||
zapEventNote: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
) = produceState(
|
||||
ZapAmountCommentNotification(
|
||||
user = null,
|
||||
comment = null,
|
||||
amount = null,
|
||||
),
|
||||
zapEventNote,
|
||||
) {
|
||||
val newState = accountViewModel.innerDecryptAmountMessage(zapEventNote)
|
||||
value = newState ?: ZapAmountCommentNotification(
|
||||
user = null,
|
||||
comment = null,
|
||||
amount = null,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TransferCardPreview() {
|
||||
var user1: User? = null
|
||||
var user2: User? = null
|
||||
|
||||
runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
user1 = LocalCache.getOrCreateUser("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c")
|
||||
user2 = LocalCache.getOrCreateUser("ca89cb11f1c75d5b6622268ff43d2288ea8b2cb5b9aa996ff9ff704fc904b78b")
|
||||
}
|
||||
}
|
||||
|
||||
ThemeComparisonColumn {
|
||||
TransferCard(
|
||||
transfer =
|
||||
ZapAmountCommentNotification(
|
||||
user = user1,
|
||||
comment = "This is a comment",
|
||||
amount = "100",
|
||||
),
|
||||
toUser = user2!!.pubkeyHex,
|
||||
backgroundColor = remember { mutableStateOf(Color.Transparent) },
|
||||
accountViewModel = mockAccountViewModel(),
|
||||
nav = EmptyNav(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TransferCard(
|
||||
transfer: ZapAmountCommentNotification,
|
||||
toUser: String,
|
||||
backgroundColor: MutableState<Color>,
|
||||
modifier: Modifier = Modifier,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = SpacedBy5dp,
|
||||
) {
|
||||
transfer.user?.let {
|
||||
UserPicture(it, Size25dp, Modifier, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
ZapIcon(
|
||||
Size24Modifier,
|
||||
MaterialTheme.colorScheme.bitcoinColor,
|
||||
)
|
||||
|
||||
// Amount Display
|
||||
Text(
|
||||
text = transfer.amount ?: "",
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
color = MaterialTheme.colorScheme.bitcoinColor,
|
||||
)
|
||||
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Outlined.ArrowForwardIos,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.bitcoinColor,
|
||||
modifier = Size20Modifier,
|
||||
)
|
||||
}
|
||||
|
||||
UserPicture(toUser, Size25dp, Modifier, accountViewModel, nav)
|
||||
|
||||
// Optional Message (conditionally displayed)
|
||||
transfer.comment?.let { message ->
|
||||
Spacer(StdHorzSpacer)
|
||||
CrossfadeToDisplayComment(message, backgroundColor, accountViewModel = accountViewModel, nav = nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-26
@@ -617,9 +617,14 @@ class AccountViewModel(
|
||||
|
||||
val decryptedInfo =
|
||||
mapNotNullAsync(myList) { next ->
|
||||
val info = innerDecryptAmountMessage(next.first, next.second)
|
||||
if (info != null) {
|
||||
DecryptedInfo(next.first, next.second, info)
|
||||
val zap = next.second
|
||||
if (zap != null) {
|
||||
val info = innerDecryptAmountMessage(next.first, zap)
|
||||
if (info != null) {
|
||||
DecryptedInfo(next.first, zap, info)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@@ -633,7 +638,7 @@ class AccountViewModel(
|
||||
|
||||
fun decryptAmountMessage(
|
||||
zapRequest: Note,
|
||||
zapEvent: Note?,
|
||||
zapEvent: Note,
|
||||
onNewState: (ZapAmountCommentNotification?) -> Unit,
|
||||
) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
@@ -641,35 +646,50 @@ class AccountViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun innerDecryptAmountMessage(
|
||||
suspend fun innerDecryptAmountMessage(zapNote: Note): ZapAmountCommentNotification? {
|
||||
val zapEvent = zapNote.event as? LnZapEvent ?: return null
|
||||
val zapRequest = zapEvent.zapRequest ?: return null
|
||||
|
||||
return innerDecryptAmountMessage(zapRequest, zapEvent)
|
||||
}
|
||||
|
||||
suspend fun innerDecryptAmountMessage(
|
||||
zapRequest: Note,
|
||||
zapEvent: Note?,
|
||||
): ZapAmountCommentNotification? =
|
||||
(zapRequest.event as? LnZapRequestEvent)?.let {
|
||||
val amount = showAmountInteger((zapEvent?.event as? LnZapEvent)?.amount)
|
||||
if (it.isPrivateZap()) {
|
||||
val decryptedContent = account.decryptZapOrNull(it)
|
||||
if (decryptedContent != null) {
|
||||
ZapAmountCommentNotification(
|
||||
LocalCache.checkGetOrCreateUser(decryptedContent.pubKey),
|
||||
decryptedContent.content.ifBlank { null },
|
||||
amount,
|
||||
)
|
||||
} else {
|
||||
ZapAmountCommentNotification(
|
||||
zapRequest.author,
|
||||
null,
|
||||
amount,
|
||||
)
|
||||
}
|
||||
zapEvent: Note,
|
||||
): ZapAmountCommentNotification? {
|
||||
val zapEvent = zapEvent.event as? LnZapEvent ?: return null
|
||||
val zapRequest = zapRequest.event as? LnZapRequestEvent ?: return null
|
||||
return innerDecryptAmountMessage(zapRequest, zapEvent)
|
||||
}
|
||||
|
||||
suspend fun innerDecryptAmountMessage(
|
||||
zapRequestEvent: LnZapRequestEvent,
|
||||
zapEvent: LnZapEvent,
|
||||
): ZapAmountCommentNotification? {
|
||||
val amount = showAmountInteger(zapEvent.amount)
|
||||
return if (zapRequestEvent.isPrivateZap()) {
|
||||
val decryptedContent = account.decryptZapOrNull(zapRequestEvent)
|
||||
if (decryptedContent != null) {
|
||||
ZapAmountCommentNotification(
|
||||
LocalCache.checkGetOrCreateUser(decryptedContent.pubKey),
|
||||
decryptedContent.content.ifBlank { null },
|
||||
amount,
|
||||
)
|
||||
} else {
|
||||
ZapAmountCommentNotification(
|
||||
zapRequest.author,
|
||||
zapRequest.event?.content?.ifBlank { null },
|
||||
account.cache.getOrCreateUser(zapRequestEvent.pubKey),
|
||||
null,
|
||||
amount,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
ZapAmountCommentNotification(
|
||||
account.cache.getOrCreateUser(zapRequestEvent.pubKey),
|
||||
zapRequestEvent.content.ifBlank { null },
|
||||
amount,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun zap(
|
||||
note: Note,
|
||||
|
||||
+4
@@ -147,6 +147,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderHighlight
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderInteractiveStory
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityChatMessage
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderLnZap
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderPinListEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderPoll
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderPostApproval
|
||||
@@ -225,6 +226,7 @@ import com.vitorpamplona.quartz.nip51Lists.relayLists.TrustedRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.relaySets.RelaySetEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.hasZapSplitSetup
|
||||
import com.vitorpamplona.quartz.nip58Badges.BadgeDefinitionEvent
|
||||
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
|
||||
@@ -607,6 +609,8 @@ private fun FullBleedNoteCompose(
|
||||
)
|
||||
} else if (noteEvent is AdvertisedRelayListEvent) {
|
||||
DisplayNIP65RelayList(baseNote, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is LnZapEvent) {
|
||||
RenderLnZap(baseNote, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is SearchRelayListEvent) {
|
||||
DisplaySearchRelayList(baseNote, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is BlockedRelayListEvent) {
|
||||
|
||||
Reference in New Issue
Block a user