feat: style Messages room-type labels as Concord-style pills

Render the "Public Chat" / "Marmot Group" (and the other room-type)
labels in the Messages list as a muted HeaderPill chip — the same faint
rounded chip the Concord community label uses — instead of plain gray
inline text, so every group kind reads the same way across the screen.
Each type gets a fitting icon (Public, Timer, Lock, Dns, Group).

Also rename the "MLS Group" label to "Marmot Group".
This commit is contained in:
Claude
2026-07-15 13:43:28 +00:00
parent f59b1e5c52
commit c00bd5bc27
6 changed files with 33 additions and 45 deletions
@@ -43,16 +43,14 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel
import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel
@@ -284,7 +282,7 @@ private fun ChannelRoomCompose(
ChannelName(
channelIdHex = channel.idHex,
channelPicture = channelPicture,
channelTitle = { modifier -> ChannelTitleWithLabelInfo(channelName, R.string.public_chat, modifier) },
channelTitle = { modifier -> ChannelTitleWithLabelInfo(channelName, MaterialSymbols.Public, R.string.public_chat, modifier) },
channelLastTime = lastMessage.createdAt(),
channelLastContent = "$authorName: $description",
hasNewMessages = (noteEvent?.createdAt ?: Long.MIN_VALUE) > lastReadTime,
@@ -320,7 +318,7 @@ private fun ChannelRoomCompose(
ChannelName(
channelIdHex = channel.roomId.toKey(),
channelPicture = relayInfo.icon,
channelTitle = { modifier -> ChannelTitleWithLabelInfo(channel.toBestDisplayName(), R.string.ephemeral_relay_chat, modifier) },
channelTitle = { modifier -> ChannelTitleWithLabelInfo(channel.toBestDisplayName(), MaterialSymbols.Timer, R.string.ephemeral_relay_chat, modifier) },
channelLastTime = lastMessage.createdAt(),
channelLastContent = "$authorName: $description",
hasNewMessages = (noteEvent?.createdAt ?: Long.MIN_VALUE) > lastReadTime,
@@ -372,7 +370,7 @@ private fun MarmotGroupRoomCompose(
ChannelName(
channelIdHex = chatroom.nostrGroupId,
channelPicture = channelPicture,
channelTitle = { modifier -> ChannelTitleWithLabelInfo(groupName, R.string.marmot_group, modifier) },
channelTitle = { modifier -> ChannelTitleWithLabelInfo(groupName, MaterialSymbols.Lock, R.string.marmot_group, modifier) },
channelLastTime = lastMessage.createdAt(),
channelLastContent = lastContent,
hasNewMessages = (lastMessage.createdAt() ?: Long.MIN_VALUE) > lastReadTime,
@@ -532,7 +530,7 @@ private fun RelayGroupServerRoomCompose(
ChannelName(
channelIdHex = relay.url,
channelPicture = relayInfo.icon,
channelTitle = { modifier -> ChannelTitleWithLabelInfo(name, R.string.relay_group_server_label, modifier) },
channelTitle = { modifier -> ChannelTitleWithLabelInfo(name, MaterialSymbols.Dns, R.string.relay_group_server_label, modifier) },
channelLastTime = row.newestMessage?.createdAt(),
channelLastContent = lastContent,
hasNewMessages = false,
@@ -578,7 +576,7 @@ private fun ConcordServerRoomCompose(
ChannelName(
channelIdHex = row.communityId,
channelPicture = rememberConcordImageModel(metadata?.icon, accountViewModel),
channelTitle = { modifier -> ChannelTitleWithLabelInfo(name, R.string.concord_server_label, modifier) },
channelTitle = { modifier -> ChannelTitleWithLabelInfo(name, MaterialSymbols.Group, R.string.concord_server_label, modifier) },
channelLastTime = row.newestMessage?.createdAt(),
channelLastContent = lastContent,
hasNewMessages = false,
@@ -629,44 +627,34 @@ private fun RelayNameChip(
}
}
/**
* Renders a Messages row title as the channel name followed by a muted [HeaderPill] naming the room
* type (Public Chat, Marmot Group, ...). The pill mirrors the Concord community chip so every group
* kind reads the same way across the screen: bold name, then a faint rounded chip with a type icon
* and short label. The name yields space to the chip so a long title can't crowd it out.
*/
@Composable
private fun ChannelTitleWithLabelInfo(
channelName: String,
labelIcon: MaterialSymbol,
label: Int,
modifier: Modifier,
) {
val label = stringRes(id = label)
val placeHolderColor = MaterialTheme.colorScheme.placeholderText
val channelNameAndBoostInfo =
remember(channelName) {
buildAnnotatedString {
withStyle(
SpanStyle(
fontWeight = FontWeight.Bold,
),
) {
append(channelName)
}
withStyle(
SpanStyle(
color = placeHolderColor,
fontWeight = FontWeight.Normal,
),
) {
append(" $label")
}
}
}
Text(
text = channelNameAndBoostInfo,
fontWeight = FontWeight.Bold,
modifier = modifier,
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
Text(
text = channelName,
fontWeight = FontWeight.Bold,
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f, fill = false),
)
Spacer(Modifier.width(6.dp))
HeaderPill(
symbol = labelIcon,
text = stringRes(id = label),
)
}
}
@Composable
@@ -597,7 +597,7 @@
<string name="public_chat">Publieke chat</string>
<string name="marmot_group">MLS Group</string>
<string name="marmot_group">Marmot Group</string>
<string name="marmot_group_no_messages_yet">Nog geen berichten</string>
+1 -1
View File
@@ -990,7 +990,7 @@
<string name="relay_chat_explainer">Relay-chats zijn groepen die beheerd worden door een relay. Ze zijn zichtbaar voor iedereen op Nostr en iedereen kan deelnemen. Geschikt voor open communities rond een onderwerp. Sommige groepen zijn tijdelijk, waardoor berichten na verloop van tijd verdwijnen.</string>
<string name="marmot_group">MLS Group</string>
<string name="marmot_group">Marmot Group</string>
<string name="marmot_group_no_messages_yet">Nog geen berichten</string>
+1 -1
View File
@@ -4415,7 +4415,7 @@
Они отлично подходят для открытых сообществ по определённым темам. Некоторые группы эфемерны,
поэтому сообщения исчезают со временем</string>
<string name="marmot_group">MLS Group</string>
<string name="marmot_group">Marmot Group</string>
<string name="marmot_group_no_messages_yet">Сообщений пока нет</string>
+1 -1
View File
@@ -4814,7 +4814,7 @@
Вони чудово підходять для відкритих спільнот за певними темами. Деякі з цих груп є тимчасовими,
і тому повідомлення чату зникають з часом</string>
<string name="marmot_group">MLS Group</string>
<string name="marmot_group">Marmot Group</string>
<string name="marmot_group_no_messages_yet">Повідомлень ще немає</string>
+1 -1
View File
@@ -413,7 +413,7 @@
<string name="public_chat">Public Chat</string>
<string name="new_public_chat">Create a new public chat</string>
<string name="marmot_group">MLS Group</string>
<string name="marmot_group">Marmot 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_explainer">Public chats are visible to everyone on Nostr and anyone