diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt
index fcd6310c2b..1555ab0bc6 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt
@@ -139,7 +139,7 @@ fun MessagesPager(
// same state holder, so the two surfaces cannot disagree.
headerContent =
if (tabs[page].resource == R.string.new_requests) {
- { ChannelInvitesSection(accountViewModel) }
+ { ChannelInvitesSection(accountViewModel, nav) }
} else {
null
},
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/ChannelInvitesSection.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/ChannelInvitesSection.kt
index caf6d6c1bb..68c1ab9b9e 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/ChannelInvitesSection.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/ChannelInvitesSection.kt
@@ -21,12 +21,12 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Card
-import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
@@ -35,15 +35,32 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
+import androidx.compose.ui.text.style.TextOverflow
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelInvite
+import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
import com.vitorpamplona.amethyst.model.LocalCache
-import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName
+import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel
+import com.vitorpamplona.amethyst.ui.layouts.NoteComposeLayout
+import com.vitorpamplona.amethyst.ui.navigation.navs.INav
+import com.vitorpamplona.amethyst.ui.note.DisplayBlankAuthor
+import com.vitorpamplona.amethyst.ui.note.UserPicture
+import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
+import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
+import com.vitorpamplona.amethyst.ui.theme.DividerThickness
+import com.vitorpamplona.amethyst.ui.theme.Size10dp
+import com.vitorpamplona.amethyst.ui.theme.Size55Modifier
+import com.vitorpamplona.amethyst.ui.theme.Size55dp
+import com.vitorpamplona.amethyst.ui.theme.Size5dp
+import com.vitorpamplona.amethyst.ui.theme.UserNameRowHeight
+import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
+import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
import com.vitorpamplona.quartz.nip29RelayGroups.GroupId
@@ -60,6 +77,7 @@ import com.vitorpamplona.quartz.nip29RelayGroups.GroupId
@Composable
fun ChannelInvitesSection(
accountViewModel: AccountViewModel,
+ nav: INav,
modifier: Modifier = Modifier,
) {
val invites by accountViewModel.feedStates.channelInvites.flow
@@ -69,48 +87,94 @@ fun ChannelInvitesSection(
Column(modifier) {
invites.forEach { invite ->
- ChannelInviteCard(invite, accountViewModel)
+ ChannelInviteCard(invite, accountViewModel, nav)
+ HorizontalDivider(thickness = DividerThickness)
}
}
}
+/**
+ * One pending add, drawn as a feed row instead of a floating Material card: the actor is the row's
+ * author — picture, name and time in the usual note header — and "added you to X" is the row's content,
+ * so the prompt reads like the reply/mention notifications it sits next to. The three choices take the
+ * reactions slot, which spans the full width and therefore fits "Add to Messages" without wrapping.
+ */
@Composable
fun ChannelInviteCard(
invite: BuzzChannelInvite,
accountViewModel: AccountViewModel,
+ nav: INav,
) {
- val channel = remember(invite.channelId, invite.relay) { LocalCache.getOrCreateRelayGroupChannel(GroupId(invite.channelId, invite.relay)) }
+ val baseChannel =
+ remember(invite.channelId, invite.relay) {
+ LocalCache.getOrCreateRelayGroupChannel(GroupId(invite.channelId, invite.relay))
+ }
+
+ // Metadata only — the same observer the channel rows use. It resolves the name a stranger's add
+ // arrives without, and never opens the channel's message subscription (which is the whole point of
+ // holding the invite back until the viewer answers).
+ val channelState by observeChannel(baseChannel, accountViewModel)
+ val channel = channelState?.channel as? RelayGroupChannel ?: baseChannel
val actorUser = remember(invite.actor) { invite.actor?.let { LocalCache.getOrCreateUser(it) } }
- val actorName = actorUser?.let { observeUserName(it, accountViewModel).value }
- Card(
- colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
- modifier = Modifier.fillMaxWidth().padding(horizontal = 10.dp, vertical = 5.dp),
- ) {
- Column(Modifier.padding(12.dp)) {
- Text(
- text = stringRes(R.string.channel_invite_title, channel.toBestDisplayName()),
- style = MaterialTheme.typography.bodyLarge,
- fontWeight = FontWeight.Bold,
- )
- Text(
+ // A pending invite is by definition unanswered, so it always carries the new-item wash rather than
+ // fading with a last-read marker: it is a standing question, not a dated event.
+ val backgroundColor =
+ MaterialTheme.colorScheme.newItemBackgroundColor
+ .compositeOver(MaterialTheme.colorScheme.background)
+
+ NoteComposeLayout(
+ modifier = Modifier.drawBehind { drawRect(backgroundColor) }.fillMaxWidth(),
+ authorPicture = {
+ Box(Size55Modifier, contentAlignment = Alignment.BottomEnd) {
+ if (actorUser != null) {
+ UserPicture(actorUser, Size55dp, accountViewModel = accountViewModel, nav = nav)
+ } else {
+ DisplayBlankAuthor(Size55dp, accountViewModel = accountViewModel)
+ }
+ }
+ },
+ firstRow = {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(Size5dp),
+ modifier = UserNameRowHeight,
+ ) {
// Who did it matters: the relay reports a self-join with the same event, so naming the
// actor is what tells "I joined this" apart from "a stranger put me here".
- text =
- stringRes(
- R.string.channel_invite_body,
- actorName ?: stringRes(R.string.channel_invite_unknown_actor),
- invite.relay.displayUrl(),
- ),
- style = MaterialTheme.typography.bodySmall,
- modifier = Modifier.padding(top = 4.dp),
- )
+ if (actorUser != null) {
+ UsernameDisplay(actorUser, Modifier.weight(1f), accountViewModel = accountViewModel)
+ } else {
+ Text(
+ text = stringRes(R.string.channel_invite_unknown_actor),
+ fontWeight = FontWeight.Bold,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ modifier = Modifier.weight(1f),
+ )
+ }
+ TimeAgo(invite.createdAt)
+ }
+ },
+ secondRow = {},
+ noteContent = {
+ Text(text = stringRes(R.string.channel_invite_title, channel.toBestDisplayName()))
+
+ Text(
+ text = invite.relay.displayUrl(),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.placeholderText,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+ },
+ reactionsRow = {
Row(
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier.fillMaxWidth().padding(top = 6.dp),
+ modifier = Modifier.fillMaxWidth().padding(horizontal = Size10dp),
) {
// Leave is separate from Ignore on purpose: Ignore is a local display choice that leaves
// you in the roster, Leave is the kind-9022 that actually removes you from the channel.
@@ -120,10 +184,12 @@ fun ChannelInviteCard(
TextButton(onClick = { accountViewModel.dismissChannelInvite(invite.channelId) }) {
Text(stringRes(R.string.channel_invite_ignore))
}
+ // Accepting *is* `addRelayGroupToMessages`, the same call behind the channel top bar's
+ // "Add to Messages", so it carries that label rather than a second word for one action.
TextButton(onClick = { accountViewModel.acceptChannelInvite(channel) }) {
- Text(stringRes(R.string.channel_invite_accept), fontWeight = FontWeight.Bold)
+ Text(stringRes(R.string.add_to_messages), fontWeight = FontWeight.Bold)
}
}
- }
- }
+ },
+ )
}
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt
index 627984e45c..d2882fe543 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt
@@ -246,7 +246,7 @@ internal fun SingleNotificationsBody(
ObserveInboxRelayListAndDisplayIfNotFound(accountViewModel, nav)
// "X added you to #channel" prompts sit above the feed rather than inside it: they are a
// standing decision, not a dated event, so they must not scroll away into history.
- ChannelInvitesSection(accountViewModel)
+ ChannelInvitesSection(accountViewModel, nav)
},
)
}
diff --git a/amethyst/src/main/res/values-cs/strings.xml b/amethyst/src/main/res/values-cs/strings.xml
index 9f2709970e..21594a1f84 100644
--- a/amethyst/src/main/res/values-cs/strings.xml
+++ b/amethyst/src/main/res/values-cs/strings.xml
@@ -2563,9 +2563,7 @@
Oblíbené relaye
Zatím žádné zprávy
Přidáno do %1$s
- %1$s vás přidal do tohoto kanálu na %2$s. Zobrazit ho ve Zprávách?
Někdo
- Zobrazit
Ignorovat
Opustit
Připojte se k této skupině pro odesílání zpráv.
diff --git a/amethyst/src/main/res/values-de-rDE/strings.xml b/amethyst/src/main/res/values-de-rDE/strings.xml
index 7f06367211..4435dd9629 100644
--- a/amethyst/src/main/res/values-de-rDE/strings.xml
+++ b/amethyst/src/main/res/values-de-rDE/strings.xml
@@ -2472,9 +2472,7 @@
Beliebte Relays
Noch keine Nachrichten
Zu %1$s hinzugefügt
- %1$s hat dich auf %2$s zu diesem Kanal hinzugefügt. In Nachrichten anzeigen?
Jemand
- Anzeigen
Ignorieren
Verlassen
Tritt dieser Gruppe bei, um Nachrichten zu senden.
diff --git a/amethyst/src/main/res/values-hi-rIN/strings.xml b/amethyst/src/main/res/values-hi-rIN/strings.xml
index 43264dc3d3..d6a4b6334f 100644
--- a/amethyst/src/main/res/values-hi-rIN/strings.xml
+++ b/amethyst/src/main/res/values-hi-rIN/strings.xml
@@ -2473,9 +2473,7 @@
लोकप्रिय पुनःप्रसारक
कोई सन्देश नहीं अब तक
%1$s में जोडा गया
- %1$s ने आपको इस प्रणाली में जोडा %2$s पर। क्या इसे सन्देशों में दिखाया जाए।
कोई व्यक्ति
- दिखाएँ
उपेक्षा करें
छोडें
इस समूह से जुडें सन्देशों को भेजने के लिए।
diff --git a/amethyst/src/main/res/values-nl-rNL/strings.xml b/amethyst/src/main/res/values-nl-rNL/strings.xml
index 389eae2ccd..22a28884e1 100644
--- a/amethyst/src/main/res/values-nl-rNL/strings.xml
+++ b/amethyst/src/main/res/values-nl-rNL/strings.xml
@@ -2467,9 +2467,7 @@
Populaire relays
Nog geen berichten
Toegevoegd aan %1$s
- %1$s heeft je toegevoegd aan dit kanaal op %2$s. In Berichten tonen?
Iemand
- Tonen
Negeren
Verlaten
Neem deel aan deze groep om berichten te sturen.
diff --git a/amethyst/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml
index 50ee2469df..98950f5e02 100644
--- a/amethyst/src/main/res/values-pl-rPL/strings.xml
+++ b/amethyst/src/main/res/values-pl-rPL/strings.xml
@@ -2565,9 +2565,7 @@ Zaplanowane posty z innych kont nie zostaną opublikowane, dopóki to konto jest
Popularne transmitery
Brak wiadomości
Dodano do %1$s
- %1$s dodał Cię do tego kanału na %2$s. Pokazać go w wiadomościach?
Ktoś
- Pokaż
Ignoruj
Wyjdź
Dołącz do tej grupy, aby wysyłać wiadomości.
diff --git a/amethyst/src/main/res/values-pt-rBR/strings.xml b/amethyst/src/main/res/values-pt-rBR/strings.xml
index c2c6fa8353..26efddbc9d 100644
--- a/amethyst/src/main/res/values-pt-rBR/strings.xml
+++ b/amethyst/src/main/res/values-pt-rBR/strings.xml
@@ -2473,9 +2473,7 @@
Relays populares
Nenhuma mensagem ainda
Adicionado a %1$s
- %1$s adicionou você a este canal em %2$s. Mostrar em Mensagens?
Alguém
- Mostrar
Ignorar
Sair
Entre neste grupo para enviar mensagens.
diff --git a/amethyst/src/main/res/values-sl-rSI/strings.xml b/amethyst/src/main/res/values-sl-rSI/strings.xml
index 5265d4ba5a..23c0485bed 100644
--- a/amethyst/src/main/res/values-sl-rSI/strings.xml
+++ b/amethyst/src/main/res/values-sl-rSI/strings.xml
@@ -2544,9 +2544,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem
Popularni releji
Ni sporočil
Dodano v: %1$s
- %1$s vas je dodal v ta kanal na %2$s. Želite to prikazati med sporočili?
Nekdo
- Prikaži
Prezri
Zapusti
Pridružite se tej skupini, da boste lahko pošiljali sporočila.
diff --git a/amethyst/src/main/res/values-sv-rSE/strings.xml b/amethyst/src/main/res/values-sv-rSE/strings.xml
index 6f5ee3cbd0..0adb501ce0 100644
--- a/amethyst/src/main/res/values-sv-rSE/strings.xml
+++ b/amethyst/src/main/res/values-sv-rSE/strings.xml
@@ -2475,9 +2475,7 @@
Populära reläer
Inga meddelanden ännu
Tillagd i %1$s
- %1$s lade till dig i den här kanalen på %2$s. Visa den i Meddelanden?
Någon
- Visa
Ignorera
Lämna
Gå med i den här gruppen för att skicka meddelanden.
diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml
index 53b93fb4a1..d5cf87e6a4 100644
--- a/amethyst/src/main/res/values/strings.xml
+++ b/amethyst/src/main/res/values/strings.xml
@@ -2702,9 +2702,7 @@
Popular relays
No messages yet
Added to %1$s
- %1$s added you to this channel on %2$s. Show it in Messages?
Someone
- Show
Ignore
Leave
Join this group to send messages.