Removes the Mute List from the All Follows TopNav option

This commit is contained in:
Vitor Pamplona
2025-11-05 10:51:10 -05:00
parent 712965cc8f
commit 59cdb222d5
7 changed files with 68 additions and 43 deletions
@@ -286,8 +286,8 @@ class Account(
val peopleListDecryptionCache = PeopleListDecryptionCache(signer) val peopleListDecryptionCache = PeopleListDecryptionCache(signer)
val blockPeopleList = BlockPeopleListState(signer, cache, peopleListDecryptionCache, scope) val blockPeopleList = BlockPeopleListState(signer, cache, peopleListDecryptionCache, scope)
val peopleListsState = PeopleListsState(signer, cache, peopleListDecryptionCache, scope) val peopleLists = PeopleListsState(signer, cache, peopleListDecryptionCache, scope)
val followListsState = FollowListsState(signer, cache, scope) val followLists = FollowListsState(signer, cache, scope)
val hiddenUsers = HiddenUsersState(muteList.flow, blockPeopleList.flow, scope, settings) val hiddenUsers = HiddenUsersState(muteList.flow, blockPeopleList.flow, scope, settings)
@@ -325,7 +325,7 @@ class Account(
val followsPerRelay = FollowsPerOutboxRelay(kind3FollowList, blockedRelayList, proxyRelayList, cache, scope).flow val followsPerRelay = FollowsPerOutboxRelay(kind3FollowList, blockedRelayList, proxyRelayList, cache, scope).flow
// Merges all follow lists to create a single All Follows feed. // Merges all follow lists to create a single All Follows feed.
val allFollows = MergedFollowListsState(kind3FollowList, peopleListsState, hashtagList, geohashList, communityList, scope) val allFollows = MergedFollowListsState(kind3FollowList, peopleLists, followLists, hashtagList, geohashList, communityList, scope)
val privateDMDecryptionCache = PrivateDMCache(signer) val privateDMDecryptionCache = PrivateDMCache(signer)
val privateZapsDecryptionCache = PrivateZapCache(signer) val privateZapsDecryptionCache = PrivateZapCache(signer)
@@ -1780,8 +1780,8 @@ class Account(
logTime("Account ${userProfile().toBestDisplayName()} newEventBundle Update with ${newNotes.size} new notes") { logTime("Account ${userProfile().toBestDisplayName()} newEventBundle Update with ${newNotes.size} new notes") {
upgradeAttestations() upgradeAttestations()
newNotesPreProcessor.runNew(newNotes) newNotesPreProcessor.runNew(newNotes)
peopleListsState.newNotes(newNotes) peopleLists.newNotes(newNotes)
followListsState.newNotes(newNotes) followLists.newNotes(newNotes)
} }
} }
} }
@@ -1790,8 +1790,8 @@ class Account(
cache.live.deletedEventBundles.collect { deletedNotes -> cache.live.deletedEventBundles.collect { deletedNotes ->
logTime("Account ${userProfile().toBestDisplayName()} deletedEventBundle Update with ${deletedNotes.size} new notes") { logTime("Account ${userProfile().toBestDisplayName()} deletedEventBundle Update with ${deletedNotes.size} new notes") {
newNotesPreProcessor.runDeleted(deletedNotes) newNotesPreProcessor.runDeleted(deletedNotes)
peopleListsState.deletedNotes(deletedNotes) peopleLists.deletedNotes(deletedNotes)
followListsState.deletedNotes(deletedNotes) followLists.deletedNotes(deletedNotes)
} }
} }
} }
@@ -94,10 +94,20 @@ class PeopleListsState(
suspend fun List<PeopleListEvent>.mapToUserIdSet() = this.map { it.userIdSet() }.flattenToSet() suspend fun List<PeopleListEvent>.mapToUserIdSet() = this.map { it.userIdSet() }.flattenToSet()
val allPeopleListProfiles: StateFlow<Set<HexKey>> = suspend fun List<PeopleListEvent>.mapGoodUsersToIdSet() =
this
.mapNotNull {
if (it.dTag() != PeopleListEvent.BLOCK_LIST_D_TAG) {
it.userIdSet()
} else {
null
}
}.flattenToSet()
val allGoodPeopleListProfiles: StateFlow<Set<HexKey>> =
latestLists latestLists
.map { it.mapToUserIdSet() } .map { it.mapGoodUsersToIdSet() }
.onStart { emit(latestLists.value.mapToUserIdSet()) } .onStart { emit(latestLists.value.mapGoodUsersToIdSet()) }
.flowOn(Dispatchers.IO) .flowOn(Dispatchers.IO)
.stateIn(scope, SharingStarted.Eagerly, emptySet()) .stateIn(scope, SharingStarted.Eagerly, emptySet())
@@ -131,8 +141,6 @@ class PeopleListsState(
) )
} }
fun isUserInFollowSets(user: User): Boolean = allPeopleListProfiles.value.contains(user.pubkeyHex)
fun DeletionEvent.hasDeletedAnyPeopleList() = deleteAddressesWithKind(PeopleListEvent.KIND) || deletesAnyEventIn(peopleListsEventIds.value) fun DeletionEvent.hasDeletedAnyPeopleList() = deleteAddressesWithKind(PeopleListEvent.KIND) || deletesAnyEventIn(peopleListsEventIds.value)
fun hasItemInNoteList(notes: Set<Note>): Boolean = fun hasItemInNoteList(notes: Set<Note>): Boolean =
@@ -24,8 +24,10 @@ import androidx.compose.runtime.Immutable
import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState
import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState
import com.vitorpamplona.amethyst.model.nip51Lists.hashtagLists.HashtagListState import com.vitorpamplona.amethyst.model.nip51Lists.hashtagLists.HashtagListState
import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.FollowListsState
import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.PeopleListsState import com.vitorpamplona.amethyst.model.nip51Lists.peopleList.PeopleListsState
import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag
import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId
import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId
@@ -41,7 +43,8 @@ import kotlinx.coroutines.flow.stateIn
class MergedFollowListsState( class MergedFollowListsState(
val kind3List: Kind3FollowListState, val kind3List: Kind3FollowListState,
val followSetList: PeopleListsState, val peopleList: PeopleListsState,
val followList: FollowListsState,
val hashtagList: HashtagListState, val hashtagList: HashtagListState,
val geohashList: GeohashListState, val geohashList: GeohashListState,
val communityList: CommunityListState, val communityList: CommunityListState,
@@ -63,13 +66,14 @@ class MergedFollowListsState(
fun mergeLists( fun mergeLists(
kind3: Kind3FollowListState.Kind3Follows, kind3: Kind3FollowListState.Kind3Follows,
followSetProfiles: Set<String>, peopleListProfiles: Set<String>,
followListProfiles: Set<String>,
hashtags: Set<String>, hashtags: Set<String>,
geohashes: Set<String>, geohashes: Set<String>,
community: Set<CommunityTag>, community: Set<CommunityTag>,
): AllFollows = ): AllFollows =
AllFollows( AllFollows(
authors = kind3.authors + followSetProfiles, authors = kind3.authors + peopleListProfiles + followListProfiles,
hashtags = hashtags, hashtags = hashtags,
geotags = geohashes, geotags = geohashes,
communities = community.mapTo(mutableSetOf()) { it.address.toValue() }, communities = community.mapTo(mutableSetOf()) { it.address.toValue() },
@@ -77,17 +81,29 @@ class MergedFollowListsState(
val flow: StateFlow<AllFollows> = val flow: StateFlow<AllFollows> =
combine( combine(
kind3List.flow, listOf(
followSetList.allPeopleListProfiles, kind3List.flow,
hashtagList.flow, peopleList.allGoodPeopleListProfiles,
geohashList.flow, followList.allPeopleListProfiles,
communityList.flow, hashtagList.flow,
::mergeLists, geohashList.flow,
).onStart { communityList.flow,
),
) { args ->
mergeLists(
args[0] as Kind3FollowListState.Kind3Follows,
args[1] as Set<HexKey>,
args[2] as Set<HexKey>,
args[3] as Set<String>,
args[4] as Set<String>,
args[5] as Set<CommunityTag>,
)
}.onStart {
emit( emit(
mergeLists( mergeLists(
kind3List.flow.value, kind3List.flow.value,
followSetList.allPeopleListProfiles.value, peopleList.allGoodPeopleListProfiles.value,
followList.allPeopleListProfiles.value,
hashtagList.flow.value, hashtagList.flow.value,
geohashList.flow.value, geohashList.flow.value,
communityList.flow.value, communityList.flow.value,
@@ -100,7 +116,8 @@ class MergedFollowListsState(
SharingStarted.Eagerly, SharingStarted.Eagerly,
mergeLists( mergeLists(
kind3List.flow.value, kind3List.flow.value,
followSetList.allPeopleListProfiles.value, peopleList.allGoodPeopleListProfiles.value,
followList.allPeopleListProfiles.value,
hashtagList.flow.value, hashtagList.flow.value,
geohashList.flow.value, geohashList.flow.value,
communityList.flow.value, communityList.flow.value,
@@ -148,14 +148,14 @@ class TopNavFilterState(
val livePeopleListsFlow: Flow<List<FeedDefinition>> = val livePeopleListsFlow: Flow<List<FeedDefinition>> =
combine( combine(
account.peopleListsState.peopleListNotes, account.peopleLists.peopleListNotes,
account.followListsState.followListNotes, account.followLists.followListNotes,
::mergePeopleLists, ::mergePeopleLists,
).onStart { ).onStart {
emit( emit(
mergePeopleLists( mergePeopleLists(
account.peopleListsState.peopleListNotes.value, account.peopleLists.peopleListNotes.value,
account.followListsState.followListNotes.value, account.followLists.followListNotes.value,
), ),
) )
} }
@@ -55,7 +55,7 @@ class PeopleListViewModel : ViewModel() {
selectedDTag selectedDTag
.transformLatest { .transformLatest {
emitAll( emitAll(
account.peopleListsState.selectListFlow(it).flowOn(Dispatchers.IO), account.peopleLists.selectListFlow(it).flowOn(Dispatchers.IO),
) )
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)
@@ -73,23 +73,23 @@ class PeopleListViewModel : ViewModel() {
} }
suspend fun deleteFollowSet() { suspend fun deleteFollowSet() {
account.peopleListsState.deleteFollowSet(selectedDTag.value, account) account.peopleLists.deleteFollowSet(selectedDTag.value, account)
} }
fun loadNote(): AddressableNote? = account.peopleListsState.getPeopleListNote(selectedDTag.value) fun loadNote(): AddressableNote? = account.peopleLists.getPeopleListNote(selectedDTag.value)
suspend fun removeUserFromSet( suspend fun removeUserFromSet(
user: User, user: User,
isPrivate: Boolean, isPrivate: Boolean,
) { ) {
account.peopleListsState.removeUserFromSet(user, isPrivate, selectedDTag.value, account) account.peopleLists.removeUserFromSet(user, isPrivate, selectedDTag.value, account)
} }
suspend fun addUserToSet( suspend fun addUserToSet(
user: User, user: User,
isPrivate: Boolean, isPrivate: Boolean,
) { ) {
account.peopleListsState.addUserToSet(user, selectedDTag.value, isPrivate, account) account.peopleLists.addUserToSet(user, selectedDTag.value, isPrivate, account)
} }
fun hasUserFlow( fun hasUserFlow(
@@ -61,10 +61,10 @@ fun ListOfPeopleListsScreen(
nav: INav, nav: INav,
) { ) {
ListOfPeopleListsScreen( ListOfPeopleListsScreen(
listFlow = accountViewModel.account.peopleListsState.uiListFlow, listFlow = accountViewModel.account.peopleLists.uiListFlow,
addItem = { title: String, description: String? -> addItem = { title: String, description: String? ->
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.addFollowList( accountViewModel.account.peopleLists.addFollowList(
listName = title, listName = title,
listDescription = description, listDescription = description,
account = accountViewModel.account, account = accountViewModel.account,
@@ -76,7 +76,7 @@ fun ListOfPeopleListsScreen(
}, },
renameItem = { followSet, newValue -> renameItem = { followSet, newValue ->
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.renameFollowList( accountViewModel.account.peopleLists.renameFollowList(
newName = newValue, newName = newValue,
peopleList = followSet, peopleList = followSet,
account = accountViewModel.account, account = accountViewModel.account,
@@ -85,7 +85,7 @@ fun ListOfPeopleListsScreen(
}, },
changeItemDescription = { followSet, newDescription -> changeItemDescription = { followSet, newDescription ->
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.modifyFollowSetDescription( accountViewModel.account.peopleLists.modifyFollowSetDescription(
newDescription = newDescription, newDescription = newDescription,
peopleList = followSet, peopleList = followSet,
account = accountViewModel.account, account = accountViewModel.account,
@@ -94,7 +94,7 @@ fun ListOfPeopleListsScreen(
}, },
cloneItem = { followSet, customName, customDescription -> cloneItem = { followSet, customName, customDescription ->
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.cloneFollowSet( accountViewModel.account.peopleLists.cloneFollowSet(
currentPeopleList = followSet, currentPeopleList = followSet,
customCloneName = customName, customCloneName = customName,
customCloneDescription = customDescription, customCloneDescription = customDescription,
@@ -104,7 +104,7 @@ fun ListOfPeopleListsScreen(
}, },
deleteItem = { followSet -> deleteItem = { followSet ->
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.deleteFollowSet( accountViewModel.account.peopleLists.deleteFollowSet(
identifierTag = followSet.identifierTag, identifierTag = followSet.identifierTag,
account = accountViewModel.account, account = accountViewModel.account,
) )
@@ -150,7 +150,7 @@ private fun FollowSetManagementScreenBody(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
) { ) {
val followSetsState by accountViewModel.account.peopleListsState.uiListFlow val followSetsState by accountViewModel.account.peopleLists.uiListFlow
.collectAsStateWithLifecycle() .collectAsStateWithLifecycle()
if (followSetsState.isEmpty()) { if (followSetsState.isEmpty()) {
@@ -168,7 +168,7 @@ private fun FollowSetManagementScreenBody(
userIsPublicMember = list.publicMembers.contains(userToAddOrRemove), userIsPublicMember = list.publicMembers.contains(userToAddOrRemove),
onRemoveUser = { onRemoveUser = {
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.removeUserFromSet( accountViewModel.account.peopleLists.removeUserFromSet(
userToAddOrRemove, userToAddOrRemove,
isPrivate = list.privateMembers.contains(userToAddOrRemove), isPrivate = list.privateMembers.contains(userToAddOrRemove),
list.identifierTag, list.identifierTag,
@@ -178,7 +178,7 @@ private fun FollowSetManagementScreenBody(
}, },
onAddUserToList = { userShouldBePrivate -> onAddUserToList = { userShouldBePrivate ->
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.addUserToSet( accountViewModel.account.peopleLists.addUserToSet(
userToAddOrRemove, userToAddOrRemove,
list.identifierTag, list.identifierTag,
userShouldBePrivate, userShouldBePrivate,
@@ -196,7 +196,7 @@ private fun FollowSetManagementScreenBody(
userName = userToAddOrRemove.toBestDisplayName(), userName = userToAddOrRemove.toBestDisplayName(),
onSetCreate = { setName, memberShouldBePrivate, description -> onSetCreate = { setName, memberShouldBePrivate, description ->
accountViewModel.runIOCatching { accountViewModel.runIOCatching {
accountViewModel.account.peopleListsState.addFollowList( accountViewModel.account.peopleLists.addFollowList(
listName = setName, listName = setName,
listDescription = description, listDescription = description,
isPrivate = memberShouldBePrivate, isPrivate = memberShouldBePrivate,