Fixes top bar lists not updating when following communities and hashtags.
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user