diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/FollowSetState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/FollowSetState.kt index 85977a43c..f2d096405 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/FollowSetState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/FollowSetState.kt @@ -20,22 +20,25 @@ */ package com.vitorpamplona.amethyst.model.nip51Lists.followSets -import androidx.compose.ui.util.fastAny import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.quartz.nip01Core.core.value import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class FollowSetState( @@ -44,20 +47,24 @@ class FollowSetState( val scope: CoroutineScope, ) { val user = cache.getOrCreateUser(signer.pubKey) + private val isActive = MutableStateFlow(false) suspend fun getFollowSetNotes() = withContext(Dispatchers.Default) { val followSetNotes = LocalCache.getFollowSetNotesFor(user) - Log.d(this.javaClass.simpleName, "Number of follow sets: ${followSetNotes.size}") + Log.d(this@FollowSetState.javaClass.simpleName, "Number of follow sets: ${followSetNotes.size}") return@withContext followSetNotes } private fun getFollowSetNotesFlow() = flow { - val followSetNotes = getFollowSetNotes() - val followSets = followSetNotes.map { mapNoteToFollowSet(it) } - emit(followSets) - }.flowOn(Dispatchers.IO) + while (isActive.value) { + val followSetNotes = getFollowSetNotes() + val followSets = followSetNotes.map { mapNoteToFollowSet(it) } + emit(followSets) + delay(1000) + } + }.flowOn(Dispatchers.Default) val profilesFlow = getFollowSetNotesFlow() @@ -65,27 +72,25 @@ class FollowSetState( it.flatMapTo(mutableSetOf()) { it.profiles }.toSet() }.stateIn(scope, SharingStarted.Eagerly, emptySet()) - fun isUserInFollowSets(user: User): Boolean = - runBlocking(scope.coroutineContext) { - LocalCache.getFollowSetNotesFor(user).fastAny { it -> - val listEvent = it.event as PeopleListEvent - val isInPublicSets = - listEvent - .publicPeople() - .fastAny { it.toTagArray().value() == user.pubkeyHex } - val isInPrivateSets = - listEvent - .privatePeople(signer) - ?.fastAny { it.toTagArray().value() == user.pubkeyHex } ?: false - - isInPublicSets || isInPrivateSets - } - } - fun mapNoteToFollowSet(note: Note): FollowSet = FollowSet .mapEventToSet( event = note.event as PeopleListEvent, signer, ) + + fun isUserInFollowSets(user: User): Boolean = profilesFlow.value.contains(user.pubkeyHex) + + init { + isActive.update { true } + scope.launch(Dispatchers.Default) { + getFollowSetNotesFlow() + .onCompletion { + isActive.update { false } + }.catch { + Log.e(this@FollowSetState.javaClass.simpleName, "Error on flow collection: ${it.message}") + isActive.update { false } + }.collect {} + } + } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt index 68b7956ba..f155da664 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.model.serverList import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListState +import com.vitorpamplona.amethyst.model.nip51Lists.followSets.FollowSetState import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState import com.vitorpamplona.amethyst.model.nip51Lists.hashtagLists.HashtagListState import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState @@ -37,6 +38,7 @@ import kotlinx.coroutines.flow.stateIn class MergedFollowListsState( val kind3List: FollowListState, + val followSetList: FollowSetState, val hashtagList: HashtagListState, val geohashList: GeohashListState, val communityList: CommunityListState, @@ -44,12 +46,13 @@ class MergedFollowListsState( ) { fun mergeLists( kind3: FollowListState.Kind3Follows, + followSetProfiles: Set, hashtags: Set, geohashes: Set, community: Set, ): FollowListState.Kind3Follows = FollowListState.Kind3Follows( - kind3.authors, + kind3.authors + followSetProfiles, kind3.authorsPlusMe, kind3.hashtags + hashtags, kind3.geotags + geohashes, @@ -59,15 +62,17 @@ class MergedFollowListsState( val flow: StateFlow = combine( kind3List.flow, + followSetList.profilesFlow, hashtagList.flow, geohashList.flow, communityList.flow, - ) { kind3, hashtag, geohash, community -> - mergeLists(kind3, hashtag, geohash, community) + ) { kind3, followSet, hashtag, geohash, community -> + mergeLists(kind3, followSet, hashtag, geohash, community) }.onStart { emit( mergeLists( kind3List.flow.value, + followSetList.profilesFlow.value, hashtagList.flow.value, geohashList.flow.value, communityList.flow.value, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt index b2ece59d3..99045a72e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt @@ -411,6 +411,8 @@ fun observeUserIsFollowing( ): State { // Subscribe in the relay for changes in the metadata of this user. UserFinderFilterAssemblerSubscription(user1, accountViewModel) + val isUserInFollowSets = accountViewModel.account.followSetsState.isUserInFollowSets(user2) + println("Is ${user2.toBestDisplayName()} in a Follow set? $isUserInFollowSets") // Subscribe in the LocalCache for changes that arrive in the device val flow = @@ -420,14 +422,13 @@ fun observeUserIsFollowing( .follows.stateFlow .sample(1000) .mapLatest { userState -> - userState.user.isFollowing(user2) || - accountViewModel.account.isUserInFollowSets(user2) + userState.user.isFollowing(user2) || isUserInFollowSets }.distinctUntilChanged() .flowOn(Dispatchers.Default) } return flow.collectAsStateWithLifecycle( - user1.isFollowing(user2) || accountViewModel.account.isUserInFollowSets(user2), + user1.isFollowing(user2) || isUserInFollowSets, ) }