feat(marmot): show member pictures and names when group has no name
Marmot groups without a configured display name now fall back to the NIP-17 strategy: a stacked avatar of the members and a comma-separated list of their first names. Applied to both the group list row and the chat top app bar. NonClickableUserPictures and DisplayUserSetAsSubject get List<HexKey> overloads so the renderers can be reused without dragging Marmot through ChatroomKey (which is also a NIP-17 dedup key — different Marmot groups can share the same member set).
This commit is contained in:
@@ -231,19 +231,28 @@ fun NonClickableUserPictures(
|
||||
room: ChatroomKey,
|
||||
size: Dp,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
NonClickableUserPictures(room.users.toList(), size, accountViewModel)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NonClickableUserPictures(
|
||||
userHexList: List<HexKey>,
|
||||
size: Dp,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
Box(Modifier.size(size), contentAlignment = Alignment.TopEnd) {
|
||||
when (room.users.size) {
|
||||
when (userHexList.size) {
|
||||
0 -> {}
|
||||
|
||||
1 -> {
|
||||
LoadUser(baseUserHex = room.users.first(), accountViewModel) {
|
||||
LoadUser(baseUserHex = userHexList.first(), accountViewModel) {
|
||||
it?.let { BaseUserPicture(it, size, accountViewModel, outerModifier = Modifier) }
|
||||
}
|
||||
}
|
||||
|
||||
2 -> {
|
||||
val userList = room.users.toList()
|
||||
val userList = userHexList
|
||||
|
||||
LoadUser(baseUserHex = userList[0], accountViewModel) {
|
||||
it?.let {
|
||||
@@ -268,7 +277,7 @@ fun NonClickableUserPictures(
|
||||
}
|
||||
|
||||
3 -> {
|
||||
val userList = room.users.toList()
|
||||
val userList = userHexList
|
||||
|
||||
LoadUser(baseUserHex = userList[0], accountViewModel) {
|
||||
it?.let {
|
||||
@@ -303,7 +312,7 @@ fun NonClickableUserPictures(
|
||||
}
|
||||
|
||||
else -> {
|
||||
val userList = room.users.toList()
|
||||
val userList = userHexList
|
||||
|
||||
LoadUser(baseUserHex = userList[0], accountViewModel) {
|
||||
it?.let {
|
||||
|
||||
+34
-6
@@ -21,7 +21,9 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
@@ -35,12 +37,16 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.DisplayUserSetAsSubject
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -56,6 +62,8 @@ fun MarmotGroupChatScreen(
|
||||
}
|
||||
val displayName by chatroom.displayName.collectAsStateWithLifecycle()
|
||||
val memberCount by chatroom.memberCount.collectAsStateWithLifecycle()
|
||||
val members by chatroom.members.collectAsStateWithLifecycle()
|
||||
val memberPubkeys = remember(members) { members.map { it.pubkey } }
|
||||
|
||||
DisappearingScaffold(
|
||||
isInvertedLayout = true,
|
||||
@@ -70,19 +78,39 @@ fun MarmotGroupChatScreen(
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Column(
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.clickable {
|
||||
nav.nav(Route.MarmotGroupInfo(nostrGroupId))
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(displayName ?: "Marmot Group")
|
||||
if (memberCount > 0) {
|
||||
Text(
|
||||
text = "$memberCount members",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
if (memberPubkeys.isNotEmpty()) {
|
||||
NonClickableUserPictures(
|
||||
userHexList = memberPubkeys,
|
||||
size = 36.dp,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
}
|
||||
Column {
|
||||
if (!displayName.isNullOrBlank()) {
|
||||
Text(displayName!!)
|
||||
} else if (memberPubkeys.isNotEmpty()) {
|
||||
DisplayUserSetAsSubject(
|
||||
userList = memberPubkeys,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
} else {
|
||||
Text("Marmot Group")
|
||||
}
|
||||
if (memberCount > 0) {
|
||||
Text(
|
||||
text = "$memberCount members",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
|
||||
+37
-8
@@ -65,7 +65,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.DisplayUserSetAsSubject
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -179,6 +181,7 @@ fun MarmotGroupListScreen(
|
||||
MarmotGroupListItem(
|
||||
groupId = groupId,
|
||||
chatroom = chatroom,
|
||||
accountViewModel = accountViewModel,
|
||||
onClick = {
|
||||
nav.nav(Route.MarmotGroupChat(groupId))
|
||||
},
|
||||
@@ -213,10 +216,13 @@ private fun loadGroupList(
|
||||
fun MarmotGroupListItem(
|
||||
groupId: HexKey,
|
||||
chatroom: MarmotGroupChatroom,
|
||||
accountViewModel: AccountViewModel,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val displayName by chatroom.displayName.collectAsStateWithLifecycle()
|
||||
val unread by chatroom.unreadCount.collectAsStateWithLifecycle()
|
||||
val members by chatroom.members.collectAsStateWithLifecycle()
|
||||
val memberPubkeys = remember(members) { members.map { it.pubkey } }
|
||||
val newestMessage = chatroom.newestMessage
|
||||
|
||||
Row(
|
||||
@@ -225,17 +231,40 @@ fun MarmotGroupListItem(
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = displayName ?: "Group ${groupId.take(8)}...",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = if (unread > 0) FontWeight.Bold else FontWeight.Normal,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
if (memberPubkeys.isNotEmpty()) {
|
||||
NonClickableUserPictures(
|
||||
userHexList = memberPubkeys,
|
||||
size = 55.dp,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
}
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
if (!displayName.isNullOrBlank()) {
|
||||
Text(
|
||||
text = displayName!!,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = if (unread > 0) FontWeight.Bold else FontWeight.Normal,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
} else if (memberPubkeys.isNotEmpty()) {
|
||||
DisplayUserSetAsSubject(
|
||||
userList = memberPubkeys,
|
||||
accountViewModel = accountViewModel,
|
||||
fontWeight = if (unread > 0) FontWeight.Bold else FontWeight.Normal,
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = "Group ${groupId.take(8)}...",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = if (unread > 0) FontWeight.Bold else FontWeight.Normal,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
if (newestMessage != null) {
|
||||
Text(
|
||||
text = newestMessage.event?.content ?: "",
|
||||
|
||||
+8
@@ -69,7 +69,15 @@ fun DisplayUserSetAsSubject(
|
||||
fontWeight: FontWeight = FontWeight.Bold,
|
||||
) {
|
||||
val userList = remember(room) { room.users.toList() }
|
||||
DisplayUserSetAsSubject(userList, accountViewModel, fontWeight)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DisplayUserSetAsSubject(
|
||||
userList: List<HexKey>,
|
||||
accountViewModel: AccountViewModel,
|
||||
fontWeight: FontWeight = FontWeight.Bold,
|
||||
) {
|
||||
if (userList.size == 1) {
|
||||
// Regular Design
|
||||
Row {
|
||||
|
||||
Reference in New Issue
Block a user