mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 08:47:33 +00:00
feat(concord): show the community pill on Concord notifications
Extract the Messages row's highlighted community chip into a shared ConcordCommunityPill (secondaryContainer, group icon, 20-char cap) and render it in NoteCompose's header markers for any Concord-gathered note, so a Concord message surfaced in Notifications names its community and taps through to the channel list — the same chip, wherever the message appears. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CzJ2Cwo8tg4oZq43oRa3ig
This commit is contained in:
@@ -58,6 +58,7 @@ 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.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.HeaderPill
|
||||
@@ -75,6 +76,7 @@ import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.layouts.GenericRepostLayout
|
||||
import com.vitorpamplona.amethyst.ui.layouts.NoteComposeLayout
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.DisplayZapSplits
|
||||
@@ -200,6 +202,7 @@ import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay
|
||||
import com.vitorpamplona.amethyst.ui.note.types.observeZapSender
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderChatClip
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordCommunityPill
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.RenderPublicChatChannelHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.PodcastTrailerListItem
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.ExerciseTemplateDisplay
|
||||
@@ -1907,6 +1910,16 @@ fun FirstUserInfoRow(
|
||||
PrivateRumorMark(accountViewModel)
|
||||
}
|
||||
|
||||
// A Concord message (e.g. surfaced in Notifications) names its parent community with the same
|
||||
// highlighted chip the Messages row uses, tapping through to that community's channel list.
|
||||
val concordChannel = remember(baseNote) { baseNote.inGatherers?.firstNotNullOfOrNull { it as? ConcordChannel } }
|
||||
concordChannel?.communityName?.let { communityName ->
|
||||
ConcordCommunityPill(
|
||||
communityName = communityName,
|
||||
onClick = { nav.nav(Route.ConcordServer(concordChannel.channelId.communityId)) },
|
||||
)
|
||||
}
|
||||
|
||||
if (isPinned) {
|
||||
PinnedMark()
|
||||
}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
|
||||
/**
|
||||
* A tappable chip naming the Concord community a message belongs to. Unlike the muted note-header
|
||||
* markers (PoW/OTS/location), this is a first-class navigation entry point, so it keeps a strong
|
||||
* `secondaryContainer` highlight. Shared by the Messages row and the Notifications feed so a Concord
|
||||
* message reads the same wherever it surfaces. The name is hard-capped so a long title can't crowd
|
||||
* the row.
|
||||
*/
|
||||
@Composable
|
||||
fun ConcordCommunityPill(
|
||||
communityName: String,
|
||||
onClick: () -> Unit,
|
||||
maxChars: Int = 20,
|
||||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(6.dp),
|
||||
color = MaterialTheme.colorScheme.secondaryContainer,
|
||||
modifier = Modifier.clickable(onClick = onClick),
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(3.dp),
|
||||
modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp),
|
||||
) {
|
||||
Icon(
|
||||
symbol = MaterialSymbols.Group,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
modifier = Modifier.size(11.dp),
|
||||
)
|
||||
Text(
|
||||
text = if (communityName.length > maxChars) communityName.take(maxChars).trimEnd() + "…" else communityName,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-7
@@ -85,6 +85,7 @@ import com.vitorpamplona.amethyst.ui.note.elements.ToggleableTimeAgoText
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.marmotGroupLastReadRoute
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.RoomNameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordCommunityPill
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.rememberConcordImageModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.LoadEphemeralChatChannel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ConcordServerRoomNote
|
||||
@@ -461,10 +462,9 @@ private fun ConcordRoomCompose(
|
||||
channel.communityName?.let { communityName ->
|
||||
Spacer(Modifier.width(6.dp))
|
||||
// The chip names the parent community and, when tapped, opens that community's
|
||||
// channel list — the "chip that opens the Concord Channel" entry point. Cap the
|
||||
// name so a long community title can't crowd out the channel name on the row.
|
||||
RelayNameChip(
|
||||
label = communityName.ellipsize(20),
|
||||
// channel list — the "chip that opens the Concord Channel" entry point.
|
||||
ConcordCommunityPill(
|
||||
communityName = communityName,
|
||||
onClick = { nav.nav(Route.ConcordServer(channel.channelId.communityId)) },
|
||||
)
|
||||
}
|
||||
@@ -604,9 +604,6 @@ private fun RelayNameChip(
|
||||
}
|
||||
}
|
||||
|
||||
/** Hard-caps [this] to [max] characters, appending an ellipsis when it was longer. */
|
||||
private fun String.ellipsize(max: Int): String = if (length > max) take(max).trimEnd() + "…" else this
|
||||
|
||||
@Composable
|
||||
private fun ChannelTitleWithLabelInfo(
|
||||
channelName: String,
|
||||
|
||||
Reference in New Issue
Block a user