Improves starting value of flows

This commit is contained in:
Vitor Pamplona
2025-07-02 12:51:08 -04:00
parent bb55aea4a4
commit ce7965d00e
18 changed files with 101 additions and 42 deletions
@@ -68,7 +68,7 @@ class PrivateStorageRelayListState(
.stateIn(
scope,
SharingStarted.Eagerly,
emptySet(),
normalizePrivateOutboxRelayListWithBackup(getPrivateOutboxRelayListNote()),
)
fun saveRelayList(
@@ -62,7 +62,7 @@ class FollowListState(
@OptIn(ExperimentalCoroutinesApi::class)
private val innerFlow: Flow<Kind3Follows> =
getFollowListFlow().transformLatest {
emit(buildKind3Follows(it.user.latestContactList))
emit(buildKind3Follows(it.user.latestContactList ?: settings.backupContactList))
}
val flow =
@@ -29,7 +29,6 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsFeedFlo
import com.vitorpamplona.amethyst.model.topNavFeeds.aroundMe.AroundMeFeedFlow
import com.vitorpamplona.amethyst.model.topNavFeeds.global.GlobalFeedFlow
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.NoteFeedFlow
import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.author.AuthorsByOutboxTopNavFilter
import com.vitorpamplona.amethyst.model.topNavFeeds.unknown.UnknownFeedFlow
import com.vitorpamplona.amethyst.service.location.LocationState
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -80,6 +79,6 @@ class FeedTopNavFilterState(
.stateIn(
scope,
SharingStarted.Eagerly,
AuthorsByOutboxTopNavFilter(emptySet()),
loadFlowsFor(feedFilterListName.value).startValue(),
)
}
@@ -26,5 +26,7 @@ import kotlinx.coroutines.flow.FlowCollector
interface IFeedFlowsType {
fun flow(): Flow<IFeedTopNavFilter>
fun startValue(): IFeedTopNavFilter
suspend fun startValue(collector: FlowCollector<IFeedTopNavFilter>)
}
@@ -50,7 +50,9 @@ class AllFollowsFeedFlow(
override fun flow() = allFollows.map(::convert)
override fun startValue(): AllFollowsByOutboxTopNavFilter = convert(allFollows.value)
override suspend fun startValue(collector: FlowCollector<IFeedTopNavFilter>) {
collector.emit(convert(allFollows.value))
collector.emit(startValue())
}
}
@@ -49,7 +49,9 @@ class AroundMeFeedFlow(
override fun flow() = location.map(::convert)
override fun startValue(): LocationTopNavFilter = convert(location.value)
override suspend fun startValue(collector: FlowCollector<IFeedTopNavFilter>) {
collector.emit(convert(location.value))
collector.emit(startValue())
}
}
@@ -34,7 +34,9 @@ class GlobalFeedFlow(
override fun flow() = MutableStateFlow(default)
override fun startValue(): GlobalTopNavFilter = default
override suspend fun startValue(collector: FlowCollector<IFeedTopNavFilter>) {
collector.emit(default)
collector.emit(startValue())
}
}
@@ -49,17 +49,51 @@ class NoteFeedFlow(
val signer: NostrSigner,
val allFollowRelays: StateFlow<Set<NormalizedRelayUrl>>,
) : IFeedFlowsType {
fun process(noteEvent: Event): IFeedTopNavFilter =
when (noteEvent) {
is PeopleListEvent -> {
if (noteEvent.dTag() == PeopleListEvent.Companion.BLOCK_LIST_D_TAG) {
MutedAuthorsByOutboxTopNavFilter(noteEvent.publicAndCachedPrivateUsersAndWords().users)
} else {
AuthorsByOutboxTopNavFilter(noteEvent.publicAndCachedPrivateUsersAndWords().users)
}
}
is MuteListEvent -> {
MutedAuthorsByOutboxTopNavFilter(noteEvent.publicAndCachedUsersAndWords().users)
}
is FollowListEvent -> {
AuthorsByOutboxTopNavFilter(noteEvent.pubKeys().toSet())
}
is CommunityListEvent -> {
AllCommunitiesTopNavFilter(noteEvent.publicAndCachedPrivateCommunityIds().toSet())
}
is HashtagListEvent -> {
HashtagTopNavFilter(noteEvent.publicAndCachedPrivateHashtags(), allFollowRelays)
}
is GeohashListEvent -> {
LocationTopNavFilter(noteEvent.publicAndCachedPrivateGeohash(), allFollowRelays)
}
is CommunityDefinitionEvent -> {
SingleCommunityTopNavFilter(
community = noteEvent.addressTag(),
authors = noteEvent.moderatorKeys().toSet().ifEmpty { null },
relays = noteEvent.relayUrls().toSet(),
)
}
else -> AuthorsByOutboxTopNavFilter(emptySet())
}
suspend fun FlowCollector<IFeedTopNavFilter>.process(noteEvent: Event) {
when (noteEvent) {
is PeopleListEvent -> {
if (noteEvent.dTag() == PeopleListEvent.Companion.BLOCK_LIST_D_TAG) {
emit(MutedAuthorsByOutboxTopNavFilter(noteEvent.publicUsersAndWords().users))
emit(MutedAuthorsByOutboxTopNavFilter(noteEvent.publicAndCachedPrivateUsersAndWords().users))
noteEvent.publicAndPrivateUsersAndWords(signer)?.let {
emit(MutedAuthorsByOutboxTopNavFilter(it.users))
}
} else {
emit(AuthorsByOutboxTopNavFilter(noteEvent.publicUsersAndWords().users))
emit(AuthorsByOutboxTopNavFilter(noteEvent.publicAndCachedPrivateUsersAndWords().users))
noteEvent.publicAndPrivateUsersAndWords(signer)?.let {
emit(AuthorsByOutboxTopNavFilter(it.users))
@@ -67,7 +101,7 @@ class NoteFeedFlow(
}
}
is MuteListEvent -> {
emit(MutedAuthorsByOutboxTopNavFilter(noteEvent.publicUsersAndWords().users))
emit(MutedAuthorsByOutboxTopNavFilter(noteEvent.publicAndCachedUsersAndWords().users))
noteEvent.publicAndPrivateUsersAndWords(signer)?.let {
emit(MutedAuthorsByOutboxTopNavFilter(it.users))
@@ -99,13 +133,18 @@ class NoteFeedFlow(
}
}
is CommunityDefinitionEvent -> {
SingleCommunityTopNavFilter(
community = noteEvent.addressTag(),
authors = noteEvent.moderatorKeys().toSet().ifEmpty { null },
relays = noteEvent.relayUrls().toSet(),
emit(
SingleCommunityTopNavFilter(
community = noteEvent.addressTag(),
authors = noteEvent.moderatorKeys().toSet().ifEmpty { null },
relays = noteEvent.relayUrls().toSet(),
),
)
}
else -> AuthorsByOutboxTopNavFilter(emptySet())
else ->
emit(
AuthorsByOutboxTopNavFilter(emptySet()),
)
}
}
@@ -120,10 +159,19 @@ class NoteFeedFlow(
}
}
override fun startValue(): IFeedTopNavFilter {
val noteEvent = metadataFlow.value?.note?.event
if (noteEvent == null) {
return AuthorsByOutboxTopNavFilter(emptySet())
} else {
return process(noteEvent)
}
}
override suspend fun startValue(collector: FlowCollector<IFeedTopNavFilter>) {
val noteEvent = metadataFlow.value?.note?.event
if (noteEvent == null) {
AuthorsByOutboxTopNavFilter(emptySet())
collector.emit(AuthorsByOutboxTopNavFilter(emptySet()))
} else {
collector.process(noteEvent)
}
@@ -30,8 +30,11 @@ class UnknownFeedFlow(
) : IFeedFlowsType {
override fun flow() = MutableStateFlow(UnknownTopNavFilter(feedName))
// empty feed
override fun startValue(): UnknownTopNavFilter = UnknownTopNavFilter(feedName)
// empty feed
override suspend fun startValue(collector: FlowCollector<IFeedTopNavFilter>) {
collector.emit(UnknownTopNavFilter(feedName))
collector.emit(startValue())
}
}
@@ -56,7 +56,7 @@ val HomePostsByGeohashKinds =
fun filterHomePostsByGeohashes(
relay: NormalizedRelayUrl,
geotags: Set<String>,
since: Long,
since: Long?,
): List<RelayBasedFilter> {
if (geotags.isEmpty()) return emptyList()
@@ -30,7 +30,7 @@ val CommentKinds = listOf(CommentEvent.KIND)
fun filterHomePostsByScopes(
relay: NormalizedRelayUrl,
scopesToLoad: Set<String>,
since: Long,
since: Long?,
): List<RelayBasedFilter> {
if (scopesToLoad.isEmpty()) return emptyList()
@@ -27,7 +27,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip01Core.f
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip22Comments.filterHomePostsByScopes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.nip72Communities.filterHomePostsFromAllCommunities
import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlin.collections.flatten
fun filterHomePostsByAllFollows(
@@ -36,29 +35,26 @@ fun filterHomePostsByAllFollows(
): List<RelayBasedFilter> {
if (followsSet.set.isEmpty()) return emptyList()
val defaultSince = TimeUtils.oneWeekAgo()
return followsSet.set.flatMap {
val since = since?.get(it.key)?.time ?: defaultSince
val relay = it.key
return followsSet.set.flatMap { (relay, filter) ->
val since = since?.get(relay)?.time
listOfNotNull(
it.value.authors?.let {
filter.authors?.let {
filterHomePostsByAuthors(relay, it, since)
},
it.value.geotags?.let {
filter.geotags?.let {
filterHomePostsByGeohashes(relay, it, since)
},
it.value.geotagScopes?.let {
filter.geotagScopes?.let {
filterHomePostsByScopes(relay, it, since)
},
it.value.hashtags?.let {
filter.hashtags?.let {
filterHomePostsByHashtags(relay, it, since)
},
it.value.hashtagScopes?.let {
filter.hashtagScopes?.let {
filterHomePostsByScopes(relay, it, since)
},
it.value.communities?.let {
filter.communities?.let {
filterHomePostsFromAllCommunities(relay, it, since)
},
).flatten()
@@ -44,7 +44,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
class HomeOutboxEventsEoseManager(
@@ -95,7 +94,7 @@ class HomeOutboxEventsEoseManager(
}
},
key.scope.launch(Dispatchers.Default) {
key.followRelayFlow().sample(2000).collectLatest {
key.followRelayFlow().collectLatest {
invalidateFilters()
}
},
@@ -41,19 +41,19 @@ class MuteListEvent(
) : GeneralListEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
override fun dTag() = FIXED_D_TAG
fun publicUsersAndWords() =
PeopleListEvent.UsersAndWords(
filterTagList("p", tags),
filterTagList("word", tags),
fun publicAndCachedUsersAndWords() =
UsersAndWords(
filterTagList("p", cachedPrivateTags()),
filterTagList("word", cachedPrivateTags()),
)
fun publicAndPrivateUsersAndWords(
signer: NostrSigner,
onReady: (PeopleListEvent.UsersAndWords) -> Unit,
onReady: (UsersAndWords) -> Unit,
) {
privateTagsOrEmpty(signer) {
onReady(
PeopleListEvent.UsersAndWords(
UsersAndWords(
filterTagList("p", it),
filterTagList("word", it),
),
@@ -44,10 +44,10 @@ class PeopleListEvent(
val words: Set<String> = setOf(),
)
fun publicUsersAndWords() =
fun publicAndCachedPrivateUsersAndWords() =
UsersAndWords(
filterTagList("p", tags),
filterTagList("word", tags),
filterTagList("p", cachedPrivateTags()),
filterTagList("word", cachedPrivateTags()),
)
fun publicAndPrivateUsersAndWords(
@@ -46,6 +46,8 @@ class HashtagListEvent(
fun publicHashtags() = tags.mapNotNull(HashtagTag::parse)
fun publicAndCachedPrivateHashtags() = publicHashtags().toSet() + (publicAndPrivateHashtagCache ?: emptySet())
fun publicAndPrivateHashtag(
signer: NostrSigner,
onReady: (Set<String>) -> Unit,
@@ -47,6 +47,8 @@ class GeohashListEvent(
fun publicGeohashes() = tags.mapNotNull(GeoHashTag::parse)
fun publicAndCachedPrivateGeohash() = publicGeohashes().toSet() + (publicAndPrivateGeohashCache ?: emptySet())
fun publicAndPrivateGeohash(
signer: NostrSigner,
onReady: (Set<String>) -> Unit,
@@ -54,6 +54,8 @@ class CommunityListEvent(
fun publicCommunityIds() = tags.mapNotNull(ATag::parseAddressId)
fun publicAndCachedPrivateCommunityIds() = publicCommunityIds() + (publicAndPrivateAddressCache?.map { it.addressId } ?: emptyList())
fun publicAndPrivateCommunities(
signer: NostrSigner,
onReady: (Set<AddressHint>) -> Unit,