fix: show empty Marmot groups in Messages screen
Previously ChatroomListKnownFeedFilter dropped any group whose newestMessage was null, so groups the user just created and groups received via Welcome events without any activity yet never appeared in the Messages list. Emit a stable placeholder Note (carrying the chatroom as a gatherer) per empty group, route it through the existing Marmot row path, and invalidate dmKnown on MarmotGroupList.groupListChanges so newly added or promoted groups rebuild the feed.
This commit is contained in:
+15
@@ -56,6 +56,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.dal.ShortsFeedFilter
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.dal.VideoFeedFilter
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.dal.VideoFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.webBookmarks.dal.WebBookmarkFeedFilter
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.webBookmarks.dal.WebBookmarkFeedFilter
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class AccountFeedContentStates(
|
class AccountFeedContentStates(
|
||||||
val account: Account,
|
val account: Account,
|
||||||
@@ -100,6 +102,19 @@ class AccountFeedContentStates(
|
|||||||
|
|
||||||
val webBookmarks = FeedContentState(WebBookmarkFeedFilter(account), scope, LocalCache)
|
val webBookmarks = FeedContentState(WebBookmarkFeedFilter(account), scope, LocalCache)
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Marmot group list changes (new group, group marked known, group
|
||||||
|
// metadata synced) don't flow through LocalCache.newEventBundles, so
|
||||||
|
// the additive update path can't see them. Force a full feed rebuild
|
||||||
|
// whenever the list changes so empty groups appear and placeholder
|
||||||
|
// rows get replaced by real messages.
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
account.marmotGroupList.groupListChanges.collect {
|
||||||
|
dmKnown.invalidateData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun init() {
|
suspend fun init() {
|
||||||
notificationSummary.initializeSuspend()
|
notificationSummary.initializeSuspend()
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-5
@@ -85,7 +85,11 @@ fun ChatroomHeaderCompose(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
if (baseNote.event != null) {
|
val isEmptyMarmotPlaceholder =
|
||||||
|
baseNote.event == null &&
|
||||||
|
baseNote.inGatherers?.any { it is MarmotGroupChatroom } == true
|
||||||
|
|
||||||
|
if (baseNote.event != null || isEmptyMarmotPlaceholder) {
|
||||||
ChatroomComposeChannelOrUser(baseNote, accountViewModel, nav)
|
ChatroomComposeChannelOrUser(baseNote, accountViewModel, nav)
|
||||||
} else {
|
} else {
|
||||||
val hasEvent by observeNoteHasEvent(baseNote, accountViewModel)
|
val hasEvent by observeNoteHasEvent(baseNote, accountViewModel)
|
||||||
@@ -248,21 +252,27 @@ private fun MarmotGroupRoomCompose(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val authorName by observeUserName(lastMessage.author!!, accountViewModel)
|
|
||||||
val displayName by chatroom.displayName.collectAsStateWithLifecycle()
|
val displayName by chatroom.displayName.collectAsStateWithLifecycle()
|
||||||
val unread by chatroom.unreadCount.collectAsStateWithLifecycle()
|
val unread by chatroom.unreadCount.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
val author = lastMessage.author
|
||||||
val noteEvent = lastMessage.event
|
val noteEvent = lastMessage.event
|
||||||
val description = noteEvent?.content?.take(200)
|
|
||||||
|
|
||||||
val groupName = displayName?.takeIf { it.isNotBlank() } ?: "Group ${chatroom.nostrGroupId.take(8)}"
|
val groupName = displayName?.takeIf { it.isNotBlank() } ?: "Group ${chatroom.nostrGroupId.take(8)}"
|
||||||
|
|
||||||
|
val lastContent =
|
||||||
|
if (author != null && noteEvent != null) {
|
||||||
|
val authorName by observeUserName(author, accountViewModel)
|
||||||
|
"$authorName: ${noteEvent.content.take(200)}"
|
||||||
|
} else {
|
||||||
|
stringRes(R.string.marmot_group_no_messages_yet)
|
||||||
|
}
|
||||||
|
|
||||||
ChannelName(
|
ChannelName(
|
||||||
channelIdHex = chatroom.nostrGroupId,
|
channelIdHex = chatroom.nostrGroupId,
|
||||||
channelPicture = null,
|
channelPicture = null,
|
||||||
channelTitle = { modifier -> ChannelTitleWithLabelInfo(groupName, R.string.marmot_group, modifier) },
|
channelTitle = { modifier -> ChannelTitleWithLabelInfo(groupName, R.string.marmot_group, modifier) },
|
||||||
channelLastTime = lastMessage.createdAt(),
|
channelLastTime = lastMessage.createdAt(),
|
||||||
channelLastContent = "$authorName: $description",
|
channelLastContent = lastContent,
|
||||||
hasNewMessages = unread > 0,
|
hasNewMessages = unread > 0,
|
||||||
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
|
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
|
||||||
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
|
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
|
||||||
|
|||||||
+1
-1
@@ -79,7 +79,7 @@ class ChatroomListKnownFeedFilter(
|
|||||||
|
|
||||||
val marmotGroups =
|
val marmotGroups =
|
||||||
account.marmotGroupList.rooms.mapNotNull { _, chatroom ->
|
account.marmotGroupList.rooms.mapNotNull { _, chatroom ->
|
||||||
chatroom.newestMessage
|
chatroom.newestMessage ?: chatroom.placeholderNote()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (privateMessages + publicChannels + ephemeralChats + marmotGroups).sortedWith(DefaultFeedOrder)
|
return (privateMessages + publicChannels + ephemeralChats + marmotGroups).sortedWith(DefaultFeedOrder)
|
||||||
|
|||||||
@@ -284,6 +284,7 @@
|
|||||||
|
|
||||||
<string name="public_chat">Public Chat</string>
|
<string name="public_chat">Public Chat</string>
|
||||||
<string name="marmot_group">MLS Group</string>
|
<string name="marmot_group">MLS Group</string>
|
||||||
|
<string name="marmot_group_no_messages_yet">No messages yet</string>
|
||||||
<string name="public_chat_title">Public Chat Metadata</string>
|
<string name="public_chat_title">Public Chat Metadata</string>
|
||||||
<string name="public_chat_explainer">Public chats are visible to everyone on Nostr and anyone
|
<string name="public_chat_explainer">Public chats are visible to everyone on Nostr and anyone
|
||||||
can participate on them. They are great for open communities around specific topics.
|
can participate on them. They are great for open communities around specific topics.
|
||||||
|
|||||||
+21
@@ -59,6 +59,27 @@ class MarmotGroupChatroom(
|
|||||||
*/
|
*/
|
||||||
var ownerSentMessage: Boolean = false
|
var ownerSentMessage: Boolean = false
|
||||||
|
|
||||||
|
// Synthetic note used by list views to represent the group when no
|
||||||
|
// messages have been received yet. Lazily created and kept stable so
|
||||||
|
// equality-based feed diffing treats it as the same row across refreshes.
|
||||||
|
private var cachedPlaceholder: Note? = null
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun placeholderNote(): Note {
|
||||||
|
val existing = cachedPlaceholder
|
||||||
|
if (existing != null) return existing
|
||||||
|
val created =
|
||||||
|
Note(placeholderIdHex(nostrGroupId)).apply {
|
||||||
|
addGatherer(this@MarmotGroupChatroom)
|
||||||
|
}
|
||||||
|
cachedPlaceholder = created
|
||||||
|
return created
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun placeholderIdHex(nostrGroupId: HexKey): HexKey = "marmot-empty-$nostrGroupId"
|
||||||
|
}
|
||||||
|
|
||||||
private var changesFlow: WeakReference<MutableSharedFlow<ListChange<Note>>> = WeakReference(null)
|
private var changesFlow: WeakReference<MutableSharedFlow<ListChange<Note>>> = WeakReference(null)
|
||||||
|
|
||||||
fun changesFlow(): MutableSharedFlow<ListChange<Note>> {
|
fun changesFlow(): MutableSharedFlow<ListChange<Note>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user