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 321e2b118..3a76d9e14 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/Main.kt @@ -98,6 +98,7 @@ import com.vitorpamplona.amethyst.desktop.ui.deck.SinglePaneLayout import com.vitorpamplona.amethyst.desktop.ui.deck.SinglePaneState import com.vitorpamplona.amethyst.desktop.ui.deck.Workspace import com.vitorpamplona.amethyst.desktop.ui.deck.WorkspaceManager +import com.vitorpamplona.amethyst.desktop.ui.deck.param import com.vitorpamplona.amethyst.desktop.ui.media.LocalAwtWindow import com.vitorpamplona.amethyst.desktop.ui.media.LocalIsImmersiveFullscreen import com.vitorpamplona.amethyst.desktop.ui.media.LocalWindowState @@ -256,15 +257,7 @@ fun main() { deckState.columns.value.map { col -> Workspace.WorkspaceColumn( typeKey = col.type.typeKey(), - param = - when (col.type) { - is DeckColumnType.Hashtag -> col.type.tag - is DeckColumnType.Editor -> col.type.draftSlug - is DeckColumnType.Article -> col.type.addressTag - is DeckColumnType.Profile -> col.type.pubKeyHex - is DeckColumnType.Thread -> col.type.noteId - else -> null - }, + param = col.type.param(), width = col.width, ) } diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/AppDrawer.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/AppDrawer.kt index be80058d0..5a004bba4 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/AppDrawer.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/AppDrawer.kt @@ -155,6 +155,16 @@ fun DeckColumnType.requiresInput(): Boolean = else -> false } +fun DeckColumnType.param(): String? = + when (this) { + is DeckColumnType.Profile -> pubKeyHex + is DeckColumnType.Thread -> noteId + is DeckColumnType.Hashtag -> tag + is DeckColumnType.Editor -> draftSlug + is DeckColumnType.Article -> addressTag + else -> null + } + val LAUNCHABLE_SCREENS: List = listOf( DeckColumnType.HomeFeed, @@ -189,7 +199,6 @@ private class AppDrawerState { var activeTab by mutableStateOf(AppDrawerTab.SCREENS) var hashtagInput by mutableStateOf("") var awaitingHashtag by mutableStateOf(false) - private var consumed by mutableStateOf(false) val filteredScreens: List by derivedStateOf { if (searchQuery.isBlank()) { @@ -223,17 +232,22 @@ private class AppDrawerState { } } - fun moveSelection(delta: Int) { - val size = filteredScreens.size - if (size > 0) selectedIndex = (selectedIndex + delta).coerceIn(0, size - 1) + fun switchTab(tab: AppDrawerTab) { + activeTab = tab + selectedIndex = 0 } - fun moveSelectionUnified( + fun moveSelection( delta: Int, - wsCount: Int, + wsCount: Int = 0, ) { - val total = wsCount + filteredScreens.size - if (total > 0) selectedIndex = (selectedIndex + delta).coerceIn(0, total - 1) + val size = + when { + isSearching -> wsCount + filteredScreens.size + activeTab == AppDrawerTab.WORKSPACES -> wsCount + else -> filteredScreens.size + } + if (size > 0) selectedIndex = (selectedIndex + delta).coerceIn(0, size - 1) } fun select( @@ -241,12 +255,10 @@ private class AppDrawerState { onSelectScreen: (DeckColumnType) -> Unit, onDismiss: () -> Unit, ) { - if (consumed) return if (screen.requiresInput()) { awaitingHashtag = true hashtagInput = "" } else { - consumed = true onSelectScreen(screen) onDismiss() } @@ -258,21 +270,29 @@ private class AppDrawerState { onSwitchWorkspace: (Workspace) -> Unit, onDismiss: () -> Unit, ) { - if (consumed) return - if (!isSearching) { - // Tab-based: only screens use Enter - filteredScreens.getOrNull(selectedIndex)?.let { select(it, onSelectScreen, onDismiss) } - return - } - // Unified: workspaces first, then screens - val wsCount = filteredWs.size - if (selectedIndex < wsCount) { - consumed = true - onSwitchWorkspace(filteredWs[selectedIndex]) - onDismiss() + if (isSearching) { + // Unified: workspaces first, then screens + val wsCount = filteredWs.size + if (selectedIndex < wsCount) { + onSwitchWorkspace(filteredWs[selectedIndex]) + onDismiss() + } else { + val screenIdx = selectedIndex - wsCount + filteredScreens.getOrNull(screenIdx)?.let { select(it, onSelectScreen, onDismiss) } + } } else { - val screenIdx = selectedIndex - wsCount - filteredScreens.getOrNull(screenIdx)?.let { select(it, onSelectScreen, onDismiss) } + when (activeTab) { + AppDrawerTab.SCREENS -> { + filteredScreens.getOrNull(selectedIndex)?.let { select(it, onSelectScreen, onDismiss) } + } + + AppDrawerTab.WORKSPACES -> { + filteredWs.getOrNull(selectedIndex)?.let { + onSwitchWorkspace(it) + onDismiss() + } + } + } } } @@ -280,8 +300,7 @@ private class AppDrawerState { onSelectScreen: (DeckColumnType) -> Unit, onDismiss: () -> Unit, ) { - if (consumed || hashtagInput.isBlank()) return - consumed = true + if (hashtagInput.isBlank()) return onSelectScreen(DeckColumnType.Hashtag(hashtagInput.removePrefix("#").trim())) onDismiss() } @@ -329,20 +348,12 @@ fun AppDrawer( } Key.DirectionDown -> { - if (state.isSearching) { - state.moveSelectionUnified(1, filteredWs.size) - } else { - state.moveSelection(1) - } + state.moveSelection(1, filteredWs.size) true } Key.DirectionUp -> { - if (state.isSearching) { - state.moveSelectionUnified(-1, filteredWs.size) - } else { - state.moveSelection(-1) - } + state.moveSelection(-1, filteredWs.size) true } @@ -419,7 +430,7 @@ fun AppDrawer( AppDrawerTab.entries.forEach { tab -> Tab( selected = state.activeTab == tab, - onClick = { state.activeTab = tab }, + onClick = { state.switchTab(tab) }, text = { Text( tab.name.lowercase().replaceFirstChar { it.uppercase() }, @@ -704,7 +715,13 @@ private fun WorkspacesGrid( editTarget = ws showEditor = true }, - onDelete = { workspaceManager.deleteWorkspace(ws.id) }, + onDelete = { + val wasActive = index == activeIndex + workspaceManager.deleteWorkspace(ws.id) + if (wasActive) { + onSwitchWorkspace(workspaceManager.activeWorkspace) + } + }, canDelete = workspaces.size > 1, ) } @@ -1082,8 +1099,14 @@ private fun UnifiedSearchResults( onDismiss() } }, - onEdit = { /* not supported in search results */ }, - onDelete = { workspaceManager.deleteWorkspace(ws.id) }, + onEdit = { /* edit via Workspaces tab */ }, + onDelete = { + val wasActive = wsIdx == activeIndex + workspaceManager.deleteWorkspace(ws.id) + if (wasActive) { + onSwitchWorkspace(workspaceManager.activeWorkspace) + } + }, canDelete = allWorkspaces.size > 1, ) } diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckState.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckState.kt index 6d932c685..653042d2a 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckState.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/DeckState.kt @@ -221,15 +221,7 @@ class DeckState( "id" to col.id, "type" to col.type.typeKey(), "width" to col.width, - "param" to - when (col.type) { - is DeckColumnType.Profile -> col.type.pubKeyHex - is DeckColumnType.Thread -> col.type.noteId - is DeckColumnType.Hashtag -> col.type.tag - is DeckColumnType.Editor -> col.type.draftSlug - is DeckColumnType.Article -> col.type.addressTag - else -> null - }, + "param" to col.type.param(), ) } DesktopPreferences.deckColumns = mapper.writeValueAsString(data) diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/WorkspaceManager.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/WorkspaceManager.kt index f8ebd1e8e..d4edbd1e9 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/WorkspaceManager.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/deck/WorkspaceManager.kt @@ -63,15 +63,7 @@ class WorkspaceManager( columns.map { col -> Workspace.WorkspaceColumn( typeKey = col.type.typeKey(), - param = - when (col.type) { - is DeckColumnType.Profile -> col.type.pubKeyHex - is DeckColumnType.Thread -> col.type.noteId - is DeckColumnType.Hashtag -> col.type.tag - is DeckColumnType.Editor -> col.type.draftSlug - is DeckColumnType.Article -> col.type.addressTag - else -> null - }, + param = col.type.param(), width = col.width, ) },