Remove map in FollowSetFeedFilter, in favor of retrieving note from cache if modification is needed. Amend FollowSet to carry the address of the note. Add Refreshable for the Lists screen.

This commit is contained in:
KotlinGeekDev
2025-03-31 21:31:50 +01:00
parent 28093256e7
commit 7d90b9f87b
3 changed files with 57 additions and 23 deletions
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.dal
import android.util.Log
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.FollowSet
import kotlinx.coroutines.launch
import kotlin.coroutines.cancellation.CancellationException
@@ -30,12 +29,10 @@ import kotlin.coroutines.cancellation.CancellationException
class FollowSetFeedFilter(
val account: Account,
) : FeedFilter<FollowSet>() {
private val followSetEventPairs: MutableMap<AddressableNote, FollowSet> = mutableMapOf()
override fun feedKey(): String = account.userProfile().pubkeyHex
override fun feed(): List<FollowSet> {
val userFollowSets = account.userProfile().followSets
val userFollowSets = account.userProfile().followSetNotes
if (userFollowSets.isEmpty()) {
account.scope.launch {
try {
@@ -47,14 +44,7 @@ class FollowSetFeedFilter(
}
}
}
updateFollowSetEventPairs(userFollowSets)
return followSetEventPairs.values.toList()
}
private fun updateFollowSetEventPairs(notes: Set<AddressableNote>) {
notes.forEach { note ->
val noteAndSetPair = note to account.mapNoteToFollowSet(note)
followSetEventPairs.putIfAbsent(noteAndSetPair.first, noteAndSetPair.second)
}
val followSets = userFollowSets.map { account.mapNoteToFollowSet(it) }
return followSets
}
}
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists
import android.util.Log
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -42,6 +43,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -60,6 +62,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
import com.vitorpamplona.amethyst.ui.feeds.FeedError
import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.navigation.TopBarWithBackButton
import com.vitorpamplona.amethyst.ui.screen.NostrUserFollowSetFeedViewModel
@@ -71,6 +74,9 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.quartz.nip51Lists.PeopleListEvent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Composable
fun ListsScreen(
@@ -83,6 +89,7 @@ fun ListsScreen(
factory = NostrUserFollowSetFeedViewModel.Factory(accountViewModel.account),
)
val currentCoroutineScope = rememberCoroutineScope()
val lifeCycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifeCycleOwner) {
@@ -109,6 +116,17 @@ fun ListsScreen(
refresh = {
followSetsViewModel.invalidateData()
},
openItem = {
currentCoroutineScope.launch(Dispatchers.IO) {
val note = followSetsViewModel.getFollowSetAddressable(it, accountViewModel.account)
if (note != null) {
val event = note.event as PeopleListEvent
println("Found list, with title: ${event.nameOrTitle()}")
} else {
println("No corresponding note found for this list.")
}
}
},
accountViewModel,
nav,
)
@@ -118,6 +136,7 @@ fun ListsScreen(
fun CustomListsScreen(
followSetState: FollowSetState,
refresh: () -> Unit,
openItem: (identifier: String) -> Unit,
accountViewModel: AccountViewModel,
nav: INav,
) {
@@ -130,7 +149,11 @@ fun CustomListsScreen(
TopBarWithBackButton(stringRes(R.string.my_lists), nav::popBack)
},
) {
Column(Modifier.padding(it).fillMaxHeight()) {
Column(
Modifier
.padding(it)
.fillMaxHeight(),
) {
when (followSetState) {
FollowSetState.Loading -> LoadingFeed()
@@ -139,6 +162,7 @@ fun CustomListsScreen(
FollowListLoaded(
loadedFeedState = followSetFeed,
onRefresh = refresh,
onItemClick = openItem,
)
}
@@ -164,16 +188,26 @@ fun FollowListLoaded(
modifier: Modifier = Modifier,
loadedFeedState: List<FollowSet>,
onRefresh: () -> Unit = {},
onItemClick: (String) -> Unit = {},
) {
Log.d("FollowSetComposable", "FollowListLoaded: Follow Set size: ${loadedFeedState.size}")
val listState = rememberLazyListState()
LazyColumn(
state = listState,
contentPadding = FeedPadding,
RefresheableBox(
onRefresh = onRefresh,
) {
itemsIndexed(loadedFeedState, key = { _, item -> item.title }) { index, set ->
CustomListItem(followSet = set)
LazyColumn(
state = listState,
contentPadding = FeedPadding,
) {
itemsIndexed(loadedFeedState, key = { _, item -> item.identifierTag }) { index, set ->
CustomListItem(
followSet = set,
onFollowSetClick = {
onItemClick(set.identifierTag)
},
)
}
}
}
}
@@ -182,10 +216,12 @@ fun FollowListLoaded(
fun CustomListItem(
modifier: Modifier = Modifier,
followSet: FollowSet,
onFollowSetClick: () -> Unit,
) {
Row(
modifier =
modifier
.clickable(onClick = onFollowSetClick)
.border(
width = Dp.Hairline,
color = Color.Gray,
@@ -261,15 +297,19 @@ fun CustomListItem(
private fun ListItemPreview() {
val sampleFollowSet =
FollowSet(
visibility = ListVisibility.Mixed,
identifierTag = "00001-2222",
title = "Sample List Title",
description = "Sample List Description",
visibility = ListVisibility.Mixed,
emptySet(),
)
ThemeComparisonColumn {
CustomListItem(
modifier = Modifier,
sampleFollowSet,
onFollowSetClick = {
println("follow set: ${sampleFollowSet.identifierTag}")
},
)
}
}
@@ -26,9 +26,10 @@ import com.vitorpamplona.quartz.nip51Lists.PeopleListEvent
@Stable
data class FollowSet(
val visibility: ListVisibility,
val identifierTag: String,
val title: String,
val description: String?,
val visibility: ListVisibility,
val profileList: Set<String>,
) : NostrList(listVisibility = visibility, content = profileList) {
companion object {
@@ -36,6 +37,7 @@ data class FollowSet(
event: PeopleListEvent,
signer: NostrSigner,
): FollowSet {
val address = event.address()
val dTag = event.dTag()
val listTitle = event.nameOrTitle() ?: dTag
val listDescription = event.description() ?: ""
@@ -44,16 +46,18 @@ data class FollowSet(
event.privateTaggedUsers(signer) { userList -> privateFollows.addAll(userList) }
return if (publicFollows.isEmpty() && privateFollows.isNotEmpty()) {
FollowSet(
visibility = ListVisibility.Private,
identifierTag = address.toValue(),
title = listTitle,
description = listDescription,
visibility = ListVisibility.Private,
profileList = privateFollows.toSet(),
)
} else if (publicFollows.isNotEmpty() && privateFollows.isEmpty()) {
FollowSet(
visibility = ListVisibility.Public,
identifierTag = address.toValue(),
title = listTitle,
description = listDescription,
visibility = ListVisibility.Public,
profileList = publicFollows.toSet(),
)
} else {