Fixes top bar lists not updating when following communities and hashtags.

This commit is contained in:
Vitor Pamplona
2024-05-06 11:32:14 -04:00
parent fe7b9b7930
commit fbd88bdeab
@@ -95,7 +95,6 @@ import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
import com.vitorpamplona.amethyst.service.NostrThreadDataSource import com.vitorpamplona.amethyst.service.NostrThreadDataSource
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
import com.vitorpamplona.amethyst.service.NostrVideoDataSource import com.vitorpamplona.amethyst.service.NostrVideoDataSource
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.Client
import com.vitorpamplona.amethyst.service.relays.RelayPool import com.vitorpamplona.amethyst.service.relays.RelayPool
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
@@ -112,7 +111,6 @@ import com.vitorpamplona.amethyst.ui.note.UserCompose
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.ui.note.types.LongCommunityHeader import com.vitorpamplona.amethyst.ui.note.types.LongCommunityHeader
import com.vitorpamplona.amethyst.ui.note.types.ShortCommunityHeader import com.vitorpamplona.amethyst.ui.note.types.ShortCommunityHeader
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DislayGeoTagHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.DislayGeoTagHeader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.GeoHashActionOptions import com.vitorpamplona.amethyst.ui.screen.loggedIn.GeoHashActionOptions
@@ -139,12 +137,15 @@ import com.vitorpamplona.quartz.events.ContactListEvent
import com.vitorpamplona.quartz.events.MuteListEvent import com.vitorpamplona.quartz.events.MuteListEvent
import com.vitorpamplona.quartz.events.PeopleListEvent import com.vitorpamplona.quartz.events.PeopleListEvent
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.Job import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable
@@ -621,111 +622,93 @@ class FollowListViewModel(val account: Account) : ViewModel() {
ResourceName(R.string.follow_list_mute_list), ResourceName(R.string.follow_list_mute_list),
CodeNameType.HARDCODED, CodeNameType.HARDCODED,
) )
val defaultLists = persistentListOf(kind3Follow, globalFollow, muteListFollow)
private var _kind3GlobalPeopleRoutes = @OptIn(ExperimentalCoroutinesApi::class)
MutableStateFlow<ImmutableList<CodeName>>(emptyList<CodeName>().toPersistentList()) val livePeopleListsFlow: Flow<List<CodeName>> =
val kind3GlobalPeopleRoutes = _kind3GlobalPeopleRoutes.asStateFlow() LocalCache.live.newEventBundles.transformLatest { newNotes ->
val hasNewList =
private var _kind3GlobalPeople = newNotes.any {
MutableStateFlow<ImmutableList<CodeName>>(emptyList<CodeName>().toPersistentList()) it.event?.pubKey() == account.userProfile().pubkeyHex &&
val kind3GlobalPeople = _kind3GlobalPeople.asStateFlow() (
it.event is PeopleListEvent ||
fun refresh() { it.event is MuteListEvent ||
viewModelScope.launch(Dispatchers.Default) { refreshFollows() } it.event is ContactListEvent
} )
private suspend fun refreshFollows() {
checkNotInMainThread()
val newFollowLists =
LocalCache.addressables
.mapNotNull { _, addressableNote ->
val event = (addressableNote.event as? PeopleListEvent)
// Has to have an list
if (
event != null &&
event.pubKey == account.userProfile().pubkeyHex &&
(event.tags.size > 1 || event.content.length > 50)
) {
CodeName(event.address().toTag(), PeopleListName(addressableNote), CodeNameType.PEOPLE_LIST)
} else {
null
}
} }
.sortedBy { it.name.name() }
val communities = if (hasNewList) {
account.userProfile().cachedFollowingCommunitiesSet().mapNotNull { val newFollowLists =
LocalCache.checkGetOrCreateAddressableNote(it)?.let { communityNote -> LocalCache.addressables
CodeName( .mapNotNull { _, addressableNote ->
"Community/${communityNote.idHex}", val event = (addressableNote.event as? PeopleListEvent)
CommunityName(communityNote), // Has to have an list
CodeNameType.ROUTE, if (
) event != null &&
} event.pubKey == account.userProfile().pubkeyHex &&
} (event.tags.size > 1 || event.content.length > 50)
) {
val hashtags = CodeName(event.address().toTag(), PeopleListName(addressableNote), CodeNameType.PEOPLE_LIST)
account.userProfile().cachedFollowingTagSet().map { } else {
CodeName("Hashtag/$it", HashtagName(it), CodeNameType.ROUTE) null
} }
val geotags =
account.userProfile().cachedFollowingGeohashSet().map {
CodeName("Geohash/$it", GeoHashName(it), CodeNameType.ROUTE)
}
val routeList = (communities + hashtags + geotags).sortedBy { it.name.name() }
val kind3GlobalPeopleRouteList =
listOf(listOf(kind3Follow, globalFollow), newFollowLists, routeList, listOf(muteListFollow))
.flatten()
.toImmutableList()
if (!equalImmutableLists(_kind3GlobalPeopleRoutes.value, kind3GlobalPeopleRouteList)) {
_kind3GlobalPeopleRoutes.emit(kind3GlobalPeopleRouteList)
}
val kind3GlobalPeopleList =
listOf(listOf(kind3Follow, globalFollow), newFollowLists, listOf(muteListFollow))
.flatten()
.toImmutableList()
if (!equalImmutableLists(_kind3GlobalPeople.value, kind3GlobalPeopleList)) {
_kind3GlobalPeople.emit(kind3GlobalPeopleList)
}
}
var collectorJob: Job? = null
init {
Log.d("Init", "App Top Bar")
refresh()
collectorJob =
viewModelScope.launch(Dispatchers.IO) {
LocalCache.live.newEventBundles.collect { newNotes ->
checkNotInMainThread()
if (
newNotes.any {
it.event?.pubKey() == account.userProfile().pubkeyHex &&
(
it.event is PeopleListEvent ||
it.event is MuteListEvent ||
it.event is ContactListEvent
)
} }
) { .sortedBy { it.name.name() }
refresh()
emit(newFollowLists)
}
}
@OptIn(ExperimentalCoroutinesApi::class)
val liveKind3FollowsFlow: Flow<List<CodeName>> =
account.userProfile().flow().follows.stateFlow.transformLatest {
val communities =
it.user.cachedFollowingCommunitiesSet().mapNotNull {
LocalCache.checkGetOrCreateAddressableNote(it)?.let { communityNote ->
CodeName(
"Community/${communityNote.idHex}",
CommunityName(communityNote),
CodeNameType.ROUTE,
)
} }
} }
}
}
override fun onCleared() { val hashtags =
collectorJob?.cancel() it.user.cachedFollowingTagSet().map {
Log.d("Init", "OnCleared: ${this.javaClass.simpleName}") CodeName("Hashtag/$it", HashtagName(it), CodeNameType.ROUTE)
super.onCleared() }
}
val geotags =
it.user.cachedFollowingGeohashSet().map {
CodeName("Geohash/$it", GeoHashName(it), CodeNameType.ROUTE)
}
emit(
(communities + hashtags + geotags).sortedBy { it.name.name() },
)
}
private val _kind3GlobalPeopleRoutes =
combineTransform(livePeopleListsFlow, liveKind3FollowsFlow) { myLivePeopleListsFlow, myLiveKind3FollowsFlow ->
emit(
listOf(listOf(kind3Follow, globalFollow), myLivePeopleListsFlow, myLiveKind3FollowsFlow, listOf(muteListFollow))
.flatten()
.toImmutableList(),
)
}
val kind3GlobalPeopleRoutes = _kind3GlobalPeopleRoutes.stateIn(viewModelScope, SharingStarted.Eagerly, defaultLists)
private val _kind3GlobalPeople =
combineTransform(livePeopleListsFlow, liveKind3FollowsFlow) { myLivePeopleListsFlow, myLiveKind3FollowsFlow ->
emit(
listOf(listOf(kind3Follow, globalFollow), myLivePeopleListsFlow, listOf(muteListFollow))
.flatten()
.toImmutableList(),
)
}
val kind3GlobalPeople = _kind3GlobalPeople.stateIn(viewModelScope, SharingStarted.Eagerly, defaultLists)
class Factory(val account: Account) : ViewModelProvider.Factory { class Factory(val account: Account) : ViewModelProvider.Factory {
override fun <FollowListViewModel : ViewModel> create(modelClass: Class<FollowListViewModel>): FollowListViewModel { override fun <FollowListViewModel : ViewModel> create(modelClass: Class<FollowListViewModel>): FollowListViewModel {