From 33c97c399198d1b91f679fdbe2adc5b67eb77ffd Mon Sep 17 00:00:00 2001 From: m Date: Sat, 16 May 2026 11:25:46 +1000 Subject: [PATCH] feat(desktop): wire Import Follow List dialog into UI The ImportFollowListDialog composable was already implemented but never rendered. The File menu item set a boolean state that no observer consumed. Render the dialog from MainContent inside the CompositionLocalProvider that supplies LocalNamecoinService, so Namecoin (.bit, d/, id/) identifier resolution works in addition to npub/hex/NIP-05. Also add a left-side launcher in both layouts so the feature is discoverable without using the File menu: - single-pane: NavigationRailItem (PersonAdd icon, 'Import' label) - deck: IconButton in the DeckSidebar next to 'Add Column' --- .../vitorpamplona/amethyst/desktop/Main.kt | 20 ++++++++++++++++++ .../amethyst/desktop/ui/deck/DeckSidebar.kt | 9 ++++++++ .../desktop/ui/deck/SinglePaneLayout.kt | 21 +++++++++++++++++++ 3 files changed, 50 insertions(+) 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 5f192bc270..6e5530e954 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt @@ -96,6 +96,7 @@ import com.vitorpamplona.amethyst.desktop.service.namecoin.LocalNamecoinService import com.vitorpamplona.amethyst.desktop.subscriptions.DesktopRelaySubscriptionsCoordinator import com.vitorpamplona.amethyst.desktop.ui.ComposeNoteDialog import com.vitorpamplona.amethyst.desktop.ui.ConnectingRelaysScreen +import com.vitorpamplona.amethyst.desktop.ui.ImportFollowListDialog import com.vitorpamplona.amethyst.desktop.ui.LoginScreen import com.vitorpamplona.amethyst.desktop.ui.ZapFeedback import com.vitorpamplona.amethyst.desktop.ui.auth.ForceLogoutDialog @@ -628,6 +629,7 @@ fun main() { onShowAppDrawer = { showAppDrawer = true }, replyToNote = replyToNote, showImportFollowListDialog = showImportFollowListDialog, + onShowImportFollowListDialog = { showImportFollowListDialog = true }, onDismissImportFollowListDialog = { showImportFollowListDialog = false }, onRestartApp = { appRestartKey++ }, torManager = torManager, @@ -658,6 +660,7 @@ fun App( onShowAppDrawer: () -> Unit, replyToNote: com.vitorpamplona.quartz.nip01Core.core.Event?, showImportFollowListDialog: Boolean = false, + onShowImportFollowListDialog: () -> Unit = {}, onDismissImportFollowListDialog: () -> Unit = {}, onRestartApp: () -> Unit = {}, torManager: com.vitorpamplona.amethyst.desktop.tor.DesktopTorManager, @@ -1012,7 +1015,21 @@ fun App( com.vitorpamplona.amethyst.desktop.ui.deck.AppDrawerTab.FEEDS onShowAppDrawer() }, + onShowImportFollowListDialog = onShowImportFollowListDialog, ) + + // Import Follow List dialog (triggered from File menu / + // Cmd+Shift+I). Rendered inside this CompositionLocalProvider + // so LocalNamecoinService is available for .bit / d/ / id/ + // identifier resolution. + if (showImportFollowListDialog) { + ImportFollowListDialog( + onDismiss = onDismissImportFollowListDialog, + relayManager = relayManager, + account = account, + localCache = localCache, + ) + } } // Compose dialog @@ -1115,6 +1132,7 @@ fun MainContent( onShowReplyDialog: (com.vitorpamplona.quartz.nip01Core.core.Event) -> Unit, onShowAppDrawer: () -> Unit, onOpenFeedsDrawer: () -> Unit = onShowAppDrawer, + onShowImportFollowListDialog: () -> Unit = {}, ) { val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() @@ -1332,6 +1350,7 @@ fun MainContent( onOpenFeedsDrawer = onOpenFeedsDrawer, onShowComposeDialog = onShowComposeDialog, onShowReplyDialog = onShowReplyDialog, + onShowImportFollowListDialog = onShowImportFollowListDialog, onZapFeedback = onZapFeedback, signerConnectionState = signerConnectionState, lastPingTimeSec = lastPingTimeSec, @@ -1368,6 +1387,7 @@ fun MainContent( deckState.addColumn(DeckColumnType.Settings) } }, + onShowImportFollowListDialog = onShowImportFollowListDialog, signerConnectionState = signerConnectionState, lastPingTimeSec = lastPingTimeSec, torStatus = torStatus, diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckSidebar.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckSidebar.kt index bfe4b9e64c..6cea5f0013 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckSidebar.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckSidebar.kt @@ -56,6 +56,7 @@ fun DeckSidebar( onRemoveAccount: (String) -> Unit, onAddColumn: () -> Unit, onOpenSettings: () -> Unit, + onShowImportFollowListDialog: () -> Unit = {}, signerConnectionState: SignerConnectionState, lastPingTimeSec: Long?, torStatus: TorServiceStatus, @@ -90,6 +91,14 @@ fun DeckSidebar( ) } + IconButton(onClick = onShowImportFollowListDialog) { + Icon( + MaterialSymbols.PersonAdd, + contentDescription = "Import Follow List", + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + Spacer(Modifier.weight(1f)) BunkerHeartbeatIndicator( diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/SinglePaneLayout.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/SinglePaneLayout.kt index 33c8e8df27..9e7fb7d7d9 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/SinglePaneLayout.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/SinglePaneLayout.kt @@ -95,6 +95,7 @@ fun SinglePaneLayout( onOpenFeedsDrawer: () -> Unit = onOpenAppDrawer, onShowComposeDialog: () -> Unit, onShowReplyDialog: (com.vitorpamplona.quartz.nip01Core.core.Event) -> Unit, + onShowImportFollowListDialog: () -> Unit = {}, onZapFeedback: (ZapFeedback) -> Unit, signerConnectionState: SignerConnectionState, lastPingTimeSec: Long?, @@ -178,6 +179,26 @@ fun SinglePaneLayout( ) } + NavigationRailItem( + selected = false, + onClick = onShowImportFollowListDialog, + icon = { + Icon( + MaterialSymbols.PersonAdd, + contentDescription = "Import Follow List", + modifier = Modifier.size(22.dp), + ) + }, + label = { + Text( + "Import", + style = MaterialTheme.typography.labelSmall, + maxLines = 1, + ) + }, + colors = NavigationRailItemDefaults.colors(), + ) + NavigationRailItem( selected = false, onClick = onOpenAppDrawer,