mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-11-10 17:16:46 +01:00
Replace first hack with a better solution for determining a follow.
Add FollowSetState to MergedFollowListsState and modify it to take into account users from follow sets when displaying a user's follows feed.
This commit is contained in:
@@ -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 {
|
||||
while (isActive.value) {
|
||||
val followSetNotes = getFollowSetNotes()
|
||||
val followSets = followSetNotes.map { mapNoteToFollowSet(it) }
|
||||
emit(followSets)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
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 {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String>,
|
||||
hashtags: Set<String>,
|
||||
geohashes: Set<String>,
|
||||
community: Set<CommunityTag>,
|
||||
): 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<FollowListState.Kind3Follows> =
|
||||
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,
|
||||
|
||||
@@ -411,6 +411,8 @@ fun observeUserIsFollowing(
|
||||
): State<Boolean> {
|
||||
// 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,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user