Improving the performance and UI of Zap notification messages.

pull/380/head
Vitor Pamplona 2023-04-25 09:21:12 -04:00
rodzic a5728daeb0
commit 99861facc9
5 zmienionych plików z 116 dodań i 59 usunięć

Wyświetl plik

@ -691,11 +691,22 @@ class Account(
}
event.plainContent(loggedIn.privKey!!, pubkeyToUse.toByteArray())
} else if (event is LnZapRequestEvent && loggedIn.privKey != null) {
LnZapRequestEvent.checkForPrivateZap(event, loggedIn.privKey!!)?.content()
} else {
event?.content()
}
}
fun decryptZapContentAuthor(note: Note): Event? {
val event = note.event
return if (event is LnZapRequestEvent && loggedIn.privKey != null) {
LnZapRequestEvent.checkForPrivateZap(event, loggedIn.privKey!!)
} else {
null
}
}
fun addDontTranslateFrom(languageCode: String) {
dontTranslateFrom = dontTranslateFrom.plus(languageCode)
liveLanguages.invalidateData()

Wyświetl plik

@ -19,7 +19,7 @@ open class Event(
@SerializedName("created_at") val createdAt: Long,
val kind: Int,
val tags: List<List<String>>,
var content: String,
val content: String,
val sig: HexKey
) : EventInterface {
override fun id(): HexKey = id

Wyświetl plik

@ -149,9 +149,9 @@ class LnZapRequestEvent(
}
fun checkForPrivateZap(zaprequest: Event, loggedInUserPrivKey: ByteArray): Event? {
val anonTag = zaprequest.tags.firstOrNull { t -> t.count() >= 2 && t[0] == "anon" }
if (anonTag != null && anonTag.size > 1) {
val encnote = anonTag?.elementAt(1)
val anonTag = zaprequest.tags.firstOrNull { t -> t.size >= 2 && t[0] == "anon" }
if (anonTag != null) {
val encnote = anonTag[1]
if (encnote != null && encnote != "") {
try {
val note = decryptPrivateZapMessage(encnote, loggedInUserPrivKey, zaprequest.pubKey.toByteArray())

Wyświetl plik

@ -6,6 +6,7 @@ import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@ -36,10 +37,7 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.NostrAccountDataSource
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
import com.vitorpamplona.amethyst.service.model.Event
import com.vitorpamplona.amethyst.service.model.LnZapEvent
import com.vitorpamplona.amethyst.service.model.LnZapRequestEvent
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
@ -86,9 +84,11 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
.combinedClickable(
onClick = {
if (noteEvent is ChannelMessageEvent) {
note.channel()?.let {
navController.navigate("Channel/${it.idHex}")
}
note
.channel()
?.let {
navController.navigate("Channel/${it.idHex}")
}
} else if (noteEvent is PrivateDmEvent) {
val replyAuthorBase =
(note.event as? PrivateDmEvent)
@ -140,16 +140,7 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
)
}
for (i in multiSetCard.zapEvents) {
var decryptedContent = (i.value.event as LnZapEvent).zapRequest?.let {
LnZapRequestEvent.checkForPrivateZap(it, NostrAccountDataSource.account.loggedIn.privKey!!)
}
if (decryptedContent != null) {
(i.key.event as Event).content = decryptedContent.content
i.key.author = LocalCache.getOrCreateUser(decryptedContent.pubKey)
}
}
AuthorGallery(multiSetCard.zapEvents.keys, navController, account, accountViewModel, "zap")
AuthorGalleryZaps(multiSetCard.zapEvents, navController, account, accountViewModel)
}
}
@ -222,12 +213,11 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
}
@Composable
fun AuthorGallery(
authorNotes: Collection<Note>,
fun AuthorGalleryZaps(
authorNotes: Map<Note, Note>,
navController: NavController,
account: Account,
accountViewModel: AccountViewModel,
kind: String = "nonzap"
accountViewModel: AccountViewModel
) {
val accountState by account.userProfile().live().follows.observeAsState()
val accountUser = accountState?.user ?: return
@ -235,38 +225,92 @@ fun AuthorGallery(
Column(modifier = Modifier.padding(start = 10.dp)) {
FlowRow() {
authorNotes.forEach {
if (it.event?.content() != "" && kind == "zap") {
Row(Modifier.fillMaxWidth()) {
FastNoteAuthorPicture(
note = it,
navController = navController,
userAccount = accountUser,
size = 35.dp
)
}
} else {
Row() {
FastNoteAuthorPicture(
note = it,
navController = navController,
userAccount = accountUser,
size = 35.dp
)
}
AuthorPictureAndComment(it.key, it.value, navController, accountUser, accountViewModel)
}
}
}
}
@Composable
private fun AuthorPictureAndComment(
zapRequest: Note,
zapEvent: Note,
navController: NavController,
accountUser: User,
accountViewModel: AccountViewModel
) {
var content by remember { mutableStateOf<Pair<User, String?>>(Pair(zapRequest.author!!, null)) }
LaunchedEffect(key1 = zapRequest.idHex) {
(zapRequest.event as? LnZapRequestEvent)?.let {
val decryptedContent = accountViewModel.decryptZap(zapRequest)
if (decryptedContent != null) {
val author = LocalCache.getOrCreateUser(decryptedContent.pubKey)
content = Pair(author, decryptedContent.content)
} else {
if (!zapRequest.event?.content().isNullOrBlank()) {
content = Pair(zapRequest.author!!, zapRequest.event?.content())
}
if (it.event?.content() != "" && kind == "zap") {
Row(Modifier.fillMaxWidth()) {
it.event?.let {
TranslatableRichTextViewer(
content = it.content(),
canPreview = true,
tags = null,
backgroundColor = MaterialTheme.colors.background,
accountViewModel = accountViewModel,
navController = navController
)
}
}
}
}
}
AuthorPictureAndComment(content.first, content.second, navController, accountUser, accountViewModel)
}
@Composable
private fun AuthorPictureAndComment(
author: User,
comment: String?,
navController: NavController,
accountUser: User,
accountViewModel: AccountViewModel
) {
val modifier = if (!comment.isNullOrBlank()) {
Modifier.fillMaxWidth()
} else {
Modifier
}
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
FastNoteAuthorPicture(
author = author,
navController = navController,
userAccount = accountUser,
size = 35.dp
)
if (!comment.isNullOrBlank()) {
Spacer(modifier = Modifier.width(5.dp))
TranslatableRichTextViewer(
content = comment,
canPreview = false,
tags = null,
modifier = Modifier.weight(1f),
backgroundColor = MaterialTheme.colors.background,
accountViewModel = accountViewModel,
navController = navController
)
}
}
}
@Composable
fun AuthorGallery(
authorNotes: Collection<Note>,
navController: NavController,
account: Account,
accountViewModel: AccountViewModel
) {
val accountState by account.userProfile().live().follows.observeAsState()
val accountUser = accountState?.user ?: return
Column(modifier = Modifier.padding(start = 10.dp)) {
FlowRow() {
authorNotes.forEach {
val author = it.author
if (author != null) {
AuthorPictureAndComment(author, null, navController, accountUser, accountViewModel)
}
}
}
@ -275,15 +319,12 @@ fun AuthorGallery(
@Composable
fun FastNoteAuthorPicture(
note: Note,
author: User,
navController: NavController,
userAccount: User,
size: Dp,
pictureModifier: Modifier = Modifier
) {
// can't be null if here
val author = note.author ?: return
val userState by author.live().metadata.observeAsState()
val user = userState?.user ?: return

Wyświetl plik

@ -14,6 +14,7 @@ import com.vitorpamplona.amethyst.model.AccountState
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver
import com.vitorpamplona.amethyst.service.model.Event
import com.vitorpamplona.amethyst.service.model.LnZapEvent
import com.vitorpamplona.amethyst.service.model.PayInvoiceErrorResponse
import com.vitorpamplona.amethyst.service.model.ReportEvent
@ -164,6 +165,10 @@ class AccountViewModel(private val account: Account) : ViewModel() {
return account.decryptContent(note)
}
fun decryptZap(note: Note): Event? {
return account.decryptZapContentAuthor(note)
}
fun hide(user: User) {
account.hideUser(user.pubkeyHex)
}