- Moves zaps from a Map<Request,Response> to a List<CustomClass> to avoid recompositions due to the use of the unstable Pair object
- Creates the class ZapAmountCommentNotification to be used instead of the unstable Triple class.
This commit is contained in:
@@ -22,6 +22,7 @@ import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Bolt
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
@@ -47,10 +48,12 @@ import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.model.UserMetadata
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapRequestEvent
|
||||
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
|
||||
import com.vitorpamplona.amethyst.ui.screen.MultiSetCard
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
|
||||
@@ -58,7 +61,6 @@ import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
||||
import com.vitorpamplona.amethyst.ui.theme.overPictureBackground
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -92,48 +94,32 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
|
||||
}
|
||||
}
|
||||
|
||||
val columnModifier = Modifier
|
||||
.drawBehind {
|
||||
drawRect(backgroundColor.value)
|
||||
}
|
||||
.padding(
|
||||
start = 12.dp,
|
||||
end = 12.dp,
|
||||
top = 10.dp
|
||||
)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
routeFor(baseNote, accountViewModel.userProfile())?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
)
|
||||
.fillMaxWidth()
|
||||
|
||||
val zapEvents by remember { derivedStateOf { multiSetCard.zapEvents } }
|
||||
val boostEvents by remember { derivedStateOf { multiSetCard.boostEvents } }
|
||||
val likeEvents by remember { derivedStateOf { multiSetCard.likeEvents } }
|
||||
|
||||
val hasZapEvents by remember { derivedStateOf { multiSetCard.zapEvents.isNotEmpty() } }
|
||||
val hasBoostEvents by remember { derivedStateOf { multiSetCard.boostEvents.isNotEmpty() } }
|
||||
val hasLikeEvents by remember { derivedStateOf { multiSetCard.likeEvents.isNotEmpty() } }
|
||||
val columnModifier = remember(backgroundColor.value) {
|
||||
Modifier
|
||||
.drawBehind {
|
||||
drawRect(backgroundColor.value)
|
||||
}
|
||||
.padding(
|
||||
start = 12.dp,
|
||||
end = 12.dp,
|
||||
top = 10.dp
|
||||
)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
routeFor(baseNote, accountViewModel.userProfile())?.let { nav(it) }
|
||||
}
|
||||
},
|
||||
onLongClick = { popupExpanded = true }
|
||||
)
|
||||
.fillMaxWidth()
|
||||
}
|
||||
|
||||
Column(modifier = columnModifier) {
|
||||
if (hasZapEvents) {
|
||||
RenderZapGallery(zapEvents, backgroundColor, nav, accountViewModel)
|
||||
}
|
||||
Galeries(multiSetCard, backgroundColor, nav, accountViewModel)
|
||||
|
||||
if (hasBoostEvents) {
|
||||
RenderBoostGallery(boostEvents, backgroundColor, nav, accountViewModel)
|
||||
}
|
||||
|
||||
if (hasLikeEvents) {
|
||||
RenderLikeGallery(likeEvents, backgroundColor, nav, accountViewModel)
|
||||
}
|
||||
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Spacer(modifier = Modifier.width(65.dp))
|
||||
Row(remember { Modifier.fillMaxWidth() }) {
|
||||
Spacer(modifier = remember { Modifier.width(65.dp) })
|
||||
|
||||
NoteCompose(
|
||||
baseNote = baseNote,
|
||||
@@ -150,6 +136,34 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Galeries(
|
||||
multiSetCard: MultiSetCard,
|
||||
backgroundColor: MutableState<Color>,
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val zapEvents by remember { derivedStateOf { multiSetCard.zapEvents } }
|
||||
val boostEvents by remember { derivedStateOf { multiSetCard.boostEvents } }
|
||||
val likeEvents by remember { derivedStateOf { multiSetCard.likeEvents } }
|
||||
|
||||
val hasZapEvents by remember { derivedStateOf { multiSetCard.zapEvents.isNotEmpty() } }
|
||||
val hasBoostEvents by remember { derivedStateOf { multiSetCard.boostEvents.isNotEmpty() } }
|
||||
val hasLikeEvents by remember { derivedStateOf { multiSetCard.likeEvents.isNotEmpty() } }
|
||||
|
||||
if (hasZapEvents) {
|
||||
RenderZapGallery(zapEvents, backgroundColor, nav, accountViewModel)
|
||||
}
|
||||
|
||||
if (hasBoostEvents) {
|
||||
RenderBoostGallery(boostEvents, backgroundColor, nav, accountViewModel)
|
||||
}
|
||||
|
||||
if (hasLikeEvents) {
|
||||
RenderLikeGallery(likeEvents, backgroundColor, nav, accountViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderLikeGallery(
|
||||
likeEvents: ImmutableList<Note>,
|
||||
@@ -157,7 +171,7 @@ fun RenderLikeGallery(
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Row(remember { Modifier.fillMaxWidth() }) {
|
||||
Box(
|
||||
modifier = remember {
|
||||
Modifier
|
||||
@@ -183,12 +197,12 @@ fun RenderLikeGallery(
|
||||
|
||||
@Composable
|
||||
fun RenderZapGallery(
|
||||
zapEvents: ImmutableMap<Note, Note?>,
|
||||
zapEvents: ImmutableList<CombinedZap>,
|
||||
backgroundColor: MutableState<Color>,
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Row(remember { Modifier.fillMaxWidth() }) {
|
||||
Box(
|
||||
modifier = remember {
|
||||
Modifier
|
||||
@@ -250,7 +264,7 @@ fun RenderBoostGallery(
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun AuthorGalleryZaps(
|
||||
authorNotes: ImmutableMap<Note, Note?>,
|
||||
authorNotes: ImmutableList<CombinedZap>,
|
||||
backgroundColor: MutableState<Color>,
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
@@ -258,12 +272,19 @@ fun AuthorGalleryZaps(
|
||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||
FlowRow() {
|
||||
authorNotes.forEach {
|
||||
AuthorPictureAndComment(it.key, it.value, backgroundColor, nav, accountViewModel)
|
||||
AuthorPictureAndComment(it.request, it.response, backgroundColor, nav, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class ZapAmountCommentNotification(
|
||||
val user: User?,
|
||||
val comment: String?,
|
||||
val amount: String?
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun AuthorPictureAndComment(
|
||||
zapRequest: Note,
|
||||
@@ -272,7 +293,15 @@ private fun AuthorPictureAndComment(
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
var content by remember { mutableStateOf<Triple<User?, String?, String?>>(Triple(zapRequest.author, null, null)) }
|
||||
var content by remember {
|
||||
mutableStateOf(
|
||||
ZapAmountCommentNotification(
|
||||
user = zapRequest.author,
|
||||
comment = null,
|
||||
amount = null
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = zapRequest.idHex, key2 = zapEvent?.idHex) {
|
||||
launch(Dispatchers.Default) {
|
||||
@@ -281,32 +310,34 @@ private fun AuthorPictureAndComment(
|
||||
val amount = (zapEvent?.event as? LnZapEvent)?.amount
|
||||
if (decryptedContent != null) {
|
||||
val newAuthor = LocalCache.getOrCreateUser(decryptedContent.pubKey)
|
||||
content = Triple(newAuthor, decryptedContent.content.ifBlank { null }, showAmountAxis(amount))
|
||||
content = ZapAmountCommentNotification(newAuthor, decryptedContent.content.ifBlank { null }, showAmountAxis(amount))
|
||||
} else {
|
||||
if (!zapRequest.event?.content().isNullOrBlank() || amount != null) {
|
||||
content = Triple(zapRequest.author, zapRequest.event?.content()?.ifBlank { null }, showAmountAxis(amount))
|
||||
content = ZapAmountCommentNotification(zapRequest.author, zapRequest.event?.content()?.ifBlank { null }, showAmountAxis(amount))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content.first?.let {
|
||||
content.let {
|
||||
val route by remember {
|
||||
derivedStateOf {
|
||||
"User/${it.pubkeyHex}"
|
||||
"User/${it.user?.pubkeyHex}"
|
||||
}
|
||||
}
|
||||
|
||||
AuthorPictureAndComment(
|
||||
author = it,
|
||||
comment = content.second,
|
||||
amount = content.third,
|
||||
route = route,
|
||||
backgroundColor = backgroundColor,
|
||||
nav = nav,
|
||||
accountViewModel = accountViewModel
|
||||
)
|
||||
it.user?.let { user ->
|
||||
AuthorPictureAndComment(
|
||||
author = user,
|
||||
comment = it.comment,
|
||||
amount = it.amount,
|
||||
route = route,
|
||||
backgroundColor = backgroundColor,
|
||||
nav = nav,
|
||||
accountViewModel = accountViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,12 +372,19 @@ private fun AuthorPictureAndComment(
|
||||
)
|
||||
|
||||
amount?.let {
|
||||
Box(modifier = Modifier.fillMaxSize().clip(shape = CircleShape), contentAlignment = Alignment.BottomCenter) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(shape = CircleShape),
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
val backgroundColor = MaterialTheme.colors.overPictureBackground
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.drawBehind { drawRect(backgroundColor) },
|
||||
modifier = remember {
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.drawBehind { drawRect(backgroundColor) }
|
||||
},
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
Text(
|
||||
@@ -424,17 +462,20 @@ fun FastNoteAuthorPicture(
|
||||
pictureModifier: Modifier = Modifier,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val userState by author.live().metadata.observeAsState()
|
||||
val profilePicture by remember(userState) {
|
||||
derivedStateOf {
|
||||
userState?.user?.profilePicture()
|
||||
}
|
||||
var profilePicture by remember {
|
||||
mutableStateOf(author.info?.picture)
|
||||
}
|
||||
|
||||
val authorPubKey = remember {
|
||||
author.pubkeyHex
|
||||
}
|
||||
|
||||
WatchUserMetadata(author) {
|
||||
if (it.picture != profilePicture) {
|
||||
profilePicture = it.picture
|
||||
}
|
||||
}
|
||||
|
||||
UserPicture(
|
||||
userHex = authorPubKey,
|
||||
userPicture = profilePicture,
|
||||
@@ -443,3 +484,15 @@ fun FastNoteAuthorPicture(
|
||||
accountViewModel = accountViewModel
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WatchUserMetadata(userBase: User, onMetadataChanges: (UserMetadata) -> Unit) {
|
||||
val userState by userBase.live().metadata.observeAsState()
|
||||
LaunchedEffect(key1 = userState) {
|
||||
launch(Dispatchers.Default) {
|
||||
userState?.user?.info?.let {
|
||||
onMetadataChanges(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,12 +64,12 @@ import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.actions.NewPostView
|
||||
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -188,7 +188,7 @@ private fun ReactionDetailGallery(
|
||||
if (hasReactions) {
|
||||
Row(verticalAlignment = CenterVertically, modifier = Modifier.padding(start = 10.dp, top = 5.dp)) {
|
||||
Column() {
|
||||
val zapEvents by remember(zapsState) { derivedStateOf { baseNote.zaps.toImmutableMap() } }
|
||||
val zapEvents by remember(zapsState) { derivedStateOf { baseNote.zaps.mapNotNull { it.value?.let { zapEvent -> CombinedZap(it.key, zapEvent) } }.toImmutableList() } }
|
||||
val boostEvents by remember(boostsState) { derivedStateOf { baseNote.boosts.toImmutableList() } }
|
||||
val likeEvents by remember(reactionsState) { derivedStateOf { baseNote.reactions.toImmutableList() } }
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
|
||||
@Immutable
|
||||
abstract class Card() {
|
||||
@@ -33,8 +32,8 @@ class NoteCard(val note: Note) : Card() {
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class ZapUserSetCard(val user: User, val zapEvents: ImmutableMap<Note, Note>) : Card() {
|
||||
val createdAt = zapEvents.maxOf { it.value.createdAt() ?: 0 }
|
||||
class ZapUserSetCard(val user: User, val zapEvents: ImmutableList<CombinedZap>) : Card() {
|
||||
val createdAt = zapEvents.maxOf { it.createdAt() ?: 0 }
|
||||
override fun createdAt(): Long {
|
||||
return createdAt
|
||||
}
|
||||
@@ -42,15 +41,15 @@ class ZapUserSetCard(val user: User, val zapEvents: ImmutableMap<Note, Note>) :
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class MultiSetCard(val note: Note, val boostEvents: ImmutableList<Note>, val likeEvents: ImmutableList<Note>, val zapEvents: ImmutableMap<Note, Note>) : Card() {
|
||||
class MultiSetCard(val note: Note, val boostEvents: ImmutableList<Note>, val likeEvents: ImmutableList<Note>, val zapEvents: ImmutableList<CombinedZap>) : Card() {
|
||||
val maxCreatedAt = maxOf(
|
||||
zapEvents.maxOfOrNull { it.value.createdAt() ?: 0 } ?: 0,
|
||||
zapEvents.maxOfOrNull { it.createdAt() ?: 0 } ?: 0,
|
||||
likeEvents.maxOfOrNull { it.createdAt() ?: 0 } ?: 0,
|
||||
boostEvents.maxOfOrNull { it.createdAt() ?: 0 } ?: 0
|
||||
)
|
||||
|
||||
val minCreatedAt = minOf(
|
||||
zapEvents.minOfOrNull { it.value.createdAt() ?: Long.MAX_VALUE } ?: Long.MAX_VALUE,
|
||||
zapEvents.minOfOrNull { it.createdAt() ?: Long.MAX_VALUE } ?: Long.MAX_VALUE,
|
||||
likeEvents.minOfOrNull { it.createdAt() ?: Long.MAX_VALUE } ?: Long.MAX_VALUE,
|
||||
boostEvents.minOfOrNull { it.createdAt() ?: Long.MAX_VALUE } ?: Long.MAX_VALUE
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
@@ -25,7 +26,6 @@ import com.vitorpamplona.amethyst.ui.dal.FeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -132,8 +132,8 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
}
|
||||
|
||||
// val reactionCards = reactionsPerEvent.map { LikeSetCard(it.key, it.value) }
|
||||
val zapsPerUser = mutableMapOf<User, MutableMap<Note, Note>>()
|
||||
val zapsPerEvent = mutableMapOf<Note, MutableMap<Note, Note>>()
|
||||
val zapsPerUser = mutableMapOf<User, MutableList<CombinedZap>>()
|
||||
val zapsPerEvent = mutableMapOf<Note, MutableList<CombinedZap>>()
|
||||
notes
|
||||
.filter { it.event is LnZapEvent }
|
||||
.forEach { zapEvent ->
|
||||
@@ -143,27 +143,23 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
if (zapRequest != null) {
|
||||
// var newZapRequestEvent = LocalCache.checkPrivateZap(zapRequest.event as Event)
|
||||
// zapRequest.event = newZapRequestEvent
|
||||
zapsPerEvent.getOrPut(zappedPost, { mutableMapOf() }).put(zapRequest, zapEvent)
|
||||
zapsPerEvent.getOrPut(zappedPost, { mutableListOf() }).add(CombinedZap(zapRequest, zapEvent))
|
||||
}
|
||||
} else {
|
||||
val event = (zapEvent.event as LnZapEvent)
|
||||
val author = event.zappedAuthor().mapNotNull {
|
||||
LocalCache.checkGetOrCreateUser(
|
||||
it
|
||||
)
|
||||
}.firstOrNull()
|
||||
val author = event.zappedAuthor().firstNotNullOfOrNull {
|
||||
LocalCache.users[it] // don't create user if it doesn't exist
|
||||
}
|
||||
if (author != null) {
|
||||
val zapRequest = author.zaps.filter { it.value == zapEvent }.keys.firstOrNull()
|
||||
if (zapRequest != null) {
|
||||
zapsPerUser.getOrPut(author, { mutableMapOf() })
|
||||
.put(zapRequest, zapEvent)
|
||||
zapsPerUser.getOrPut(author, { mutableListOf() })
|
||||
.add(CombinedZap(zapRequest, zapEvent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// val zapCards = zapsPerEvent.map { ZapSetCard(it.key, it.value) }
|
||||
|
||||
val boostsPerEvent = mutableMapOf<Note, MutableList<Note>>()
|
||||
notes
|
||||
.filter { it.event is RepostEvent }
|
||||
@@ -178,9 +174,9 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
val multiCards = allBaseNotes.map { baseNote ->
|
||||
val boostsInCard = boostsPerEvent[baseNote] ?: emptyList()
|
||||
val reactionsInCard = reactionsPerEvent[baseNote] ?: emptyList()
|
||||
val zapsInCard = zapsPerEvent[baseNote] ?: emptyMap()
|
||||
val zapsInCard = zapsPerEvent[baseNote] ?: emptyList()
|
||||
|
||||
val singleList = (boostsInCard + zapsInCard.values + reactionsInCard)
|
||||
val singleList = (boostsInCard + zapsInCard.map { it.response } + reactionsInCard)
|
||||
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
||||
.reversed()
|
||||
|
||||
@@ -189,7 +185,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
baseNote,
|
||||
boostsInCard.filter { it in chunk }.toImmutableList(),
|
||||
reactionsInCard.filter { it in chunk }.toImmutableList(),
|
||||
zapsInCard.filter { it.value in chunk }.toImmutableMap()
|
||||
zapsInCard.filter { it.response in chunk }.toImmutableList()
|
||||
)
|
||||
}
|
||||
}.flatten()
|
||||
@@ -197,7 +193,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
val userZaps = zapsPerUser.map {
|
||||
ZapUserSetCard(
|
||||
it.key,
|
||||
it.value.toImmutableMap()
|
||||
it.value.toImmutableList()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -346,3 +342,9 @@ fun <T> equalImmutableLists(list1: ImmutableList<T>, list2: ImmutableList<T>): B
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class CombinedZap(val request: Note, val response: Note) {
|
||||
fun createdAt() = response.createdAt()
|
||||
fun idHex() = response.idHex
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user