From df442bf7b52e4ba5995e7964892f094557766c35 Mon Sep 17 00:00:00 2001 From: nrobi144 Date: Fri, 24 Jul 2026 11:51:51 +0300 Subject: [PATCH] =?UTF-8?q?fix(desktop):=20discoverable=20note=20moderatio?= =?UTF-8?q?n=20=E2=80=94=20right-click=20menu=20+=20=E2=8B=AE=20overflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manual testing showed the note moderation actions were hard to find: - Provide LocalDesktopIAccount on MainContent's own (non-null) provider so every deck/feed/profile/settings surface reliably resolves the account. - Add a right-click ContextMenuArea on feed notes: Mute user / Report… / Copy text (moderation items for other authors on a writeable account). - Swap the note action-row Share icon for a MoreVert (⋮) overflow — the menu it opens already carries copy/broadcast + mute/report, matching the profile ⋮. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../vitorpamplona/amethyst/desktop/Main.kt | 1 + .../amethyst/desktop/ui/FeedScreen.kt | 75 ++++++++++++++----- .../amethyst/desktop/ui/NoteActions.kt | 6 +- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt index 3a48e2fadf..ef8a01e648 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt @@ -2051,6 +2051,7 @@ fun MainContent( CompositionLocalProvider( LocalRelayCategories provides relayCategories, LocalBlossomServers provides iAccount.blossomServerList.flow, + com.vitorpamplona.amethyst.desktop.model.LocalDesktopIAccount provides iAccount, com.vitorpamplona.amethyst.desktop.ui.relay.LocalAccountRelays provides accountRelays, com.vitorpamplona.amethyst.desktop.ui.deck.LocalDesktopCache provides localCache, com.vitorpamplona.amethyst.desktop.ui.deck.LocalRelayManager provides relayManager, diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt index a9c3b5a1e0..4919a63ca4 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt @@ -28,6 +28,8 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.ContextMenuArea +import androidx.compose.foundation.ContextMenuItem import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.TooltipArea import androidx.compose.foundation.background @@ -202,32 +204,71 @@ fun FeedNoteCard( forceReveal: Boolean = false, ) { val event = note.event ?: return + val moderationAccount = com.vitorpamplona.amethyst.desktop.model.LocalDesktopIAccount.current + val ctxScope = rememberCoroutineScope() + var showReportDialog by remember(note.idHex) { mutableStateOf(false) } + val canModerate = moderationAccount != null && moderationAccount.isWriteable() && event.pubKey != moderationAccount.pubKey + SpamCheckedNoteRender( note = note, localCache = localCache, forceReveal = forceReveal, ) { - FeedNoteCardBody( - note = note, - event = event, - relayManager = relayManager, - localCache = localCache, - account = account, - nwcConnection = nwcConnection, - onReply = onReply, - onZapFeedback = onZapFeedback, - onNavigateToProfile = onNavigateToProfile, - onNavigateToThread = onNavigateToThread, - onImageClick = onImageClick, - onMediaClick = onMediaClick, - onHashtagClick = onHashtagClick, - followedUsers = followedUsers, - myPubKeyHex = myPubKeyHex, - onFollow = onFollow, + // Right-click context menu (Compose Desktop). Mute/Report are only added + // for other authors on a writeable account; Copy is always available. + ContextMenuArea(items = { + buildList { + add(ContextMenuItem("Copy text") { copyTextToClipboard(event.content) }) + if (canModerate && moderationAccount != null) { + add(ContextMenuItem("Mute user") { ctxScope.launch { moderationAccount.hideUser(event.pubKey) } }) + add(ContextMenuItem("Report…") { showReportDialog = true }) + } + } + }) { + FeedNoteCardBody( + note = note, + event = event, + relayManager = relayManager, + localCache = localCache, + account = account, + nwcConnection = nwcConnection, + onReply = onReply, + onZapFeedback = onZapFeedback, + onNavigateToProfile = onNavigateToProfile, + onNavigateToThread = onNavigateToThread, + onImageClick = onImageClick, + onMediaClick = onMediaClick, + onHashtagClick = onHashtagClick, + followedUsers = followedUsers, + myPubKeyHex = myPubKeyHex, + onFollow = onFollow, + ) + } + } + + if (showReportDialog && moderationAccount != null) { + com.vitorpamplona.amethyst.desktop.ui.note.ReportNoteDialog( + onDismiss = { showReportDialog = false }, + onReport = { type, comment -> + ctxScope.launch { moderationAccount.reportEvent(event, type, comment) } + }, + onBlockAndReport = { type, comment -> + ctxScope.launch { + moderationAccount.reportEvent(event, type, comment) + moderationAccount.hideUser(event.pubKey) + } + }, ) } } +private fun copyTextToClipboard(text: String) { + java.awt.Toolkit + .getDefaultToolkit() + .systemClipboard + .setContents(java.awt.datatransfer.StringSelection(text), null) +} + @Composable private fun FeedNoteCardBody( note: Note, diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt index 7a52fb1d08..1667a3e6a1 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NoteActions.kt @@ -1311,7 +1311,7 @@ fun NoteActionsRow( ) } - // Share menu + // Overflow menu: copy / broadcast / share links + mute / report. val shareMenuState = rememberShareMenuState() Box { IconButton( @@ -1319,8 +1319,8 @@ fun NoteActionsRow( modifier = Modifier.size(32.dp), ) { Icon( - MaterialSymbols.Share, - contentDescription = "Share", + MaterialSymbols.MoreVert, + contentDescription = "More actions", tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.size(18.dp), )