From f9ccf87030852312adcf71f842476b261f7985f1 Mon Sep 17 00:00:00 2001 From: Abdelilah El Aissaoui Date: Sat, 25 Mar 2023 14:07:38 +0100 Subject: [PATCH] Replaced compose dropdown with a custom implementation based on context menu --- .../kotlin/com/jetpackduba/gitnuro/Icons.kt | 1 + .../kotlin/com/jetpackduba/gitnuro/ui/Menu.kt | 56 +++++++++++-------- .../com/jetpackduba/gitnuro/ui/SidePanel.kt | 7 ++- .../gitnuro/ui/context_menu/ContextMenu.kt | 54 ++++++++++++++++++ .../ui/context_menu/PullContextMenu.kt | 6 +- .../ui/context_menu/PushContextMenu.kt | 9 +-- .../ui/context_menu/StashContextMenu.kt | 9 +-- src/main/resources/message.svg | 1 + 8 files changed, 104 insertions(+), 39 deletions(-) create mode 100644 src/main/resources/message.svg diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/Icons.kt b/src/main/kotlin/com/jetpackduba/gitnuro/Icons.kt index af0d1d2..5f726c6 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/Icons.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/Icons.kt @@ -28,6 +28,7 @@ object AppIcons { const val LOCK = "lock.svg" const val LOGO = "logo.svg" const val MERGE = "merge.svg" + const val MESSAGE = "message.svg" const val MORE_VERT = "more_vert.svg" const val OPEN = "open.svg" const val PERSON = "person.svg" diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt index dd9a460..46b0ae3 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt @@ -7,7 +7,10 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.* +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -192,7 +195,7 @@ fun ExtendedMenuButton( title: String, icon: Painter, onClick: () -> Unit, - extendedListItems: List, + extendedListItems: List, ) { var showDropDownMenu by remember { mutableStateOf(false) } @@ -229,31 +232,36 @@ fun ExtendedMenuButton( ) } - Box( - modifier = Modifier - .fillMaxHeight() - .ignoreKeyEvents(), - contentAlignment = Alignment.Center, + DropdownMenu( + items = { extendedListItems } ) { + Box( + modifier = Modifier + .fillMaxHeight() + .ignoreKeyEvents(), + contentAlignment = Alignment.Center, + ) { - Icon( - painterResource(AppIcons.EXPAND_MORE), - contentDescription = null, - tint = MaterialTheme.colors.onBackground, - modifier = Modifier.size(16.dp) - ) + Icon( + painterResource(AppIcons.EXPAND_MORE), + contentDescription = null, + tint = MaterialTheme.colors.onBackground, + modifier = Modifier.size(16.dp) + ) - DropdownMenu( - onDismissRequest = { - showDropDownMenu = false - }, - content = { - for (item in extendedListItems) { - DropDownContent(item, onDismiss = { showDropDownMenu = false }) - } - }, - expanded = showDropDownMenu, - ) + } + +// DropdownMenu( +// onDismissRequest = { +// showDropDownMenu = false +// }, +// content = { +// for (item in extendedListItems) { +// DropDownContent(item, onDismiss = { showDropDownMenu = false }) +// } +// }, +// expanded = showDropDownMenu, +// ) } } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/SidePanel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/SidePanel.kt index 7ab4320..79e9c34 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/SidePanel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/SidePanel.kt @@ -321,7 +321,8 @@ fun LazyListScope.submodules( items(submodules, key = { it.first }) { submodule -> Submodule( submodule, - onInitializeModule = { submodulesViewModel.initializeSubmodule(submodule.first) } + onInitializeModule = { submodulesViewModel.initializeSubmodule(submodule.first) }, + onOpenSubmoduleInTab = { submodulesViewModel.onOpenSubmoduleInTab(submodule.first) }, ) } } @@ -464,12 +465,14 @@ private fun Stash( private fun Submodule( submodulePair: Pair, onInitializeModule: () -> Unit, + onOpenSubmoduleInTab: () -> Unit, ) { ContextMenu( items = { submoduleContextMenuItems( submodulePair.second, - onInitializeModule = onInitializeModule + onInitializeModule = onInitializeModule, + onOpenSubmoduleInTab = onOpenSubmoduleInTab, ) } ) { diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/ContextMenu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/ContextMenu.kt index 4513b73..4323421 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/ContextMenu.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/ContextMenu.kt @@ -13,9 +13,11 @@ import androidx.compose.ui.awt.awtEventOrNull import androidx.compose.ui.draw.shadow import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.pointer.* +import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.unit.* import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupPositionProvider @@ -36,6 +38,13 @@ fun ContextMenu(items: () -> List, function: @Composable () } } +@Composable +fun DropdownMenu(items: () -> List, function: @Composable () -> Unit) { + Box(modifier = Modifier.dropdownMenu(items), propagateMinConstraints = true) { + function() + } +} + @OptIn(ExperimentalComposeUiApi::class) @Composable private fun Modifier.contextMenu(items: () -> List): Modifier { @@ -66,6 +75,51 @@ private fun Modifier.contextMenu(items: () -> List): Modifie lastMouseEventState.x, lastMouseEventState.y, items(), + onDismissRequest = { setLastMouseEventState(null) } + ) + } + + return mod +} + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +private fun Modifier.dropdownMenu(items: () -> List): Modifier { + val (lastMouseEventState, setLastMouseEventState) = remember { mutableStateOf(null) } + val (offset, setOffset) = remember { mutableStateOf(null) } + val mod = this + .onGloballyPositioned { layoutCoordinates -> + val offsetToRoot = layoutCoordinates.localToRoot(Offset.Zero) + println(offsetToRoot) + + val offsetToBottomOfComponent = offsetToRoot.copy(y = offsetToRoot.y + layoutCoordinates.size.height) + setOffset(offsetToBottomOfComponent) + } + .pointerInput(Unit) { + while (true) { + val lastMouseEvent = awaitPointerEventScope { awaitFirstDownEvent() } + val mouseEvent = lastMouseEvent.awtEventOrNull + + if (mouseEvent != null) { + if (lastMouseEvent.button.isPrimary) { + val currentCheck = System.currentTimeMillis() + if (lastCheck != 0L && currentCheck - lastCheck < MIN_TIME_BETWEEN_POPUPS) { + println("IGNORE POPUP TRIGGERED!") + } else { + lastCheck = currentCheck + + setLastMouseEventState(mouseEvent) + } + } + } + } + } + + if (offset != null && lastMouseEventState != null) { + showPopup( + offset.x.toInt(), + offset.y.toInt(), + items(), onDismissRequest = { setLastMouseEventState(null) }) } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PullContextMenu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PullContextMenu.kt index 4bfbf28..2f14b49 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PullContextMenu.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PullContextMenu.kt @@ -4,7 +4,7 @@ fun pullContextMenuItems( onPullWith: () -> Unit, onFetchAll: () -> Unit, isPullWithRebaseDefault: Boolean, -): List { +): List { val pullWithText = if (isPullWithRebaseDefault) { "Pull with merge" } else { @@ -12,11 +12,11 @@ fun pullContextMenuItems( } return mutableListOf( - DropDownContentData( + ContextMenuElement.ContextTextEntry( label = pullWithText, onClick = onPullWith, ), - DropDownContentData( + ContextMenuElement.ContextTextEntry( label = "Fetch all", onClick = onFetchAll, ), diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PushContextMenu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PushContextMenu.kt index 68e6a70..00d93b5 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PushContextMenu.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/PushContextMenu.kt @@ -1,18 +1,15 @@ package com.jetpackduba.gitnuro.ui.context_menu -import androidx.compose.foundation.ExperimentalFoundationApi - -@OptIn(ExperimentalFoundationApi::class) fun pushContextMenuItems( onPushWithTags: () -> Unit, onForcePush: () -> Unit, -): List { +): List { return mutableListOf( - DropDownContentData( + ContextMenuElement.ContextTextEntry( label = "Push including tags", onClick = onPushWithTags, ), - DropDownContentData( + ContextMenuElement.ContextTextEntry( label = "Force push", onClick = onForcePush, ), diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/StashContextMenu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/StashContextMenu.kt index 03591a5..65fc0bc 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/StashContextMenu.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/StashContextMenu.kt @@ -1,15 +1,16 @@ package com.jetpackduba.gitnuro.ui.context_menu -import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.ui.res.painterResource +import com.jetpackduba.gitnuro.AppIcons -@OptIn(ExperimentalFoundationApi::class) fun stashContextMenuItems( onStashWithMessage: () -> Unit, -): List { +): List { return mutableListOf( - DropDownContentData( + ContextMenuElement.ContextTextEntry( label = "Stash with message", onClick = onStashWithMessage, + icon = { painterResource(AppIcons.MESSAGE) } ), ) } diff --git a/src/main/resources/message.svg b/src/main/resources/message.svg new file mode 100644 index 0000000..f843f12 --- /dev/null +++ b/src/main/resources/message.svg @@ -0,0 +1 @@ + \ No newline at end of file