Replaced compose dropdown with a custom implementation based on context menu
This commit is contained in:
parent
37348a5dfc
commit
f9ccf87030
@ -28,6 +28,7 @@ object AppIcons {
|
|||||||
const val LOCK = "lock.svg"
|
const val LOCK = "lock.svg"
|
||||||
const val LOGO = "logo.svg"
|
const val LOGO = "logo.svg"
|
||||||
const val MERGE = "merge.svg"
|
const val MERGE = "merge.svg"
|
||||||
|
const val MESSAGE = "message.svg"
|
||||||
const val MORE_VERT = "more_vert.svg"
|
const val MORE_VERT = "more_vert.svg"
|
||||||
const val OPEN = "open.svg"
|
const val OPEN = "open.svg"
|
||||||
const val PERSON = "person.svg"
|
const val PERSON = "person.svg"
|
||||||
|
@ -7,7 +7,10 @@ import androidx.compose.foundation.Image
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
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.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
@ -192,7 +195,7 @@ fun ExtendedMenuButton(
|
|||||||
title: String,
|
title: String,
|
||||||
icon: Painter,
|
icon: Painter,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
extendedListItems: List<DropDownContentData>,
|
extendedListItems: List<ContextMenuElement>,
|
||||||
) {
|
) {
|
||||||
var showDropDownMenu by remember { mutableStateOf(false) }
|
var showDropDownMenu by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
@ -229,31 +232,36 @@ fun ExtendedMenuButton(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
DropdownMenu(
|
||||||
modifier = Modifier
|
items = { extendedListItems }
|
||||||
.fillMaxHeight()
|
|
||||||
.ignoreKeyEvents(),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.ignoreKeyEvents(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
|
||||||
Icon(
|
Icon(
|
||||||
painterResource(AppIcons.EXPAND_MORE),
|
painterResource(AppIcons.EXPAND_MORE),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = MaterialTheme.colors.onBackground,
|
tint = MaterialTheme.colors.onBackground,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
DropdownMenu(
|
}
|
||||||
onDismissRequest = {
|
|
||||||
showDropDownMenu = false
|
// DropdownMenu(
|
||||||
},
|
// onDismissRequest = {
|
||||||
content = {
|
// showDropDownMenu = false
|
||||||
for (item in extendedListItems) {
|
// },
|
||||||
DropDownContent(item, onDismiss = { showDropDownMenu = false })
|
// content = {
|
||||||
}
|
// for (item in extendedListItems) {
|
||||||
},
|
// DropDownContent(item, onDismiss = { showDropDownMenu = false })
|
||||||
expanded = showDropDownMenu,
|
// }
|
||||||
)
|
// },
|
||||||
|
// expanded = showDropDownMenu,
|
||||||
|
// )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,8 @@ fun LazyListScope.submodules(
|
|||||||
items(submodules, key = { it.first }) { submodule ->
|
items(submodules, key = { it.first }) { submodule ->
|
||||||
Submodule(
|
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(
|
private fun Submodule(
|
||||||
submodulePair: Pair<String, SubmoduleStatus>,
|
submodulePair: Pair<String, SubmoduleStatus>,
|
||||||
onInitializeModule: () -> Unit,
|
onInitializeModule: () -> Unit,
|
||||||
|
onOpenSubmoduleInTab: () -> Unit,
|
||||||
) {
|
) {
|
||||||
ContextMenu(
|
ContextMenu(
|
||||||
items = {
|
items = {
|
||||||
submoduleContextMenuItems(
|
submoduleContextMenuItems(
|
||||||
submodulePair.second,
|
submodulePair.second,
|
||||||
onInitializeModule = onInitializeModule
|
onInitializeModule = onInitializeModule,
|
||||||
|
onOpenSubmoduleInTab = onOpenSubmoduleInTab,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
@ -13,9 +13,11 @@ import androidx.compose.ui.awt.awtEventOrNull
|
|||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
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.graphics.painter.Painter
|
||||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||||
import androidx.compose.ui.input.pointer.*
|
import androidx.compose.ui.input.pointer.*
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
import androidx.compose.ui.window.Popup
|
import androidx.compose.ui.window.Popup
|
||||||
import androidx.compose.ui.window.PopupPositionProvider
|
import androidx.compose.ui.window.PopupPositionProvider
|
||||||
@ -36,6 +38,13 @@ fun ContextMenu(items: () -> List<ContextMenuElement>, function: @Composable ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DropdownMenu(items: () -> List<ContextMenuElement>, function: @Composable () -> Unit) {
|
||||||
|
Box(modifier = Modifier.dropdownMenu(items), propagateMinConstraints = true) {
|
||||||
|
function()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun Modifier.contextMenu(items: () -> List<ContextMenuElement>): Modifier {
|
private fun Modifier.contextMenu(items: () -> List<ContextMenuElement>): Modifier {
|
||||||
@ -66,6 +75,51 @@ private fun Modifier.contextMenu(items: () -> List<ContextMenuElement>): Modifie
|
|||||||
lastMouseEventState.x,
|
lastMouseEventState.x,
|
||||||
lastMouseEventState.y,
|
lastMouseEventState.y,
|
||||||
items(),
|
items(),
|
||||||
|
onDismissRequest = { setLastMouseEventState(null) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun Modifier.dropdownMenu(items: () -> List<ContextMenuElement>): Modifier {
|
||||||
|
val (lastMouseEventState, setLastMouseEventState) = remember { mutableStateOf<MouseEvent?>(null) }
|
||||||
|
val (offset, setOffset) = remember { mutableStateOf<Offset?>(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) })
|
onDismissRequest = { setLastMouseEventState(null) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ fun pullContextMenuItems(
|
|||||||
onPullWith: () -> Unit,
|
onPullWith: () -> Unit,
|
||||||
onFetchAll: () -> Unit,
|
onFetchAll: () -> Unit,
|
||||||
isPullWithRebaseDefault: Boolean,
|
isPullWithRebaseDefault: Boolean,
|
||||||
): List<DropDownContentData> {
|
): List<ContextMenuElement> {
|
||||||
val pullWithText = if (isPullWithRebaseDefault) {
|
val pullWithText = if (isPullWithRebaseDefault) {
|
||||||
"Pull with merge"
|
"Pull with merge"
|
||||||
} else {
|
} else {
|
||||||
@ -12,11 +12,11 @@ fun pullContextMenuItems(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return mutableListOf(
|
return mutableListOf(
|
||||||
DropDownContentData(
|
ContextMenuElement.ContextTextEntry(
|
||||||
label = pullWithText,
|
label = pullWithText,
|
||||||
onClick = onPullWith,
|
onClick = onPullWith,
|
||||||
),
|
),
|
||||||
DropDownContentData(
|
ContextMenuElement.ContextTextEntry(
|
||||||
label = "Fetch all",
|
label = "Fetch all",
|
||||||
onClick = onFetchAll,
|
onClick = onFetchAll,
|
||||||
),
|
),
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
package com.jetpackduba.gitnuro.ui.context_menu
|
package com.jetpackduba.gitnuro.ui.context_menu
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
fun pushContextMenuItems(
|
fun pushContextMenuItems(
|
||||||
onPushWithTags: () -> Unit,
|
onPushWithTags: () -> Unit,
|
||||||
onForcePush: () -> Unit,
|
onForcePush: () -> Unit,
|
||||||
): List<DropDownContentData> {
|
): List<ContextMenuElement> {
|
||||||
return mutableListOf(
|
return mutableListOf(
|
||||||
DropDownContentData(
|
ContextMenuElement.ContextTextEntry(
|
||||||
label = "Push including tags",
|
label = "Push including tags",
|
||||||
onClick = onPushWithTags,
|
onClick = onPushWithTags,
|
||||||
),
|
),
|
||||||
DropDownContentData(
|
ContextMenuElement.ContextTextEntry(
|
||||||
label = "Force push",
|
label = "Force push",
|
||||||
onClick = onForcePush,
|
onClick = onForcePush,
|
||||||
),
|
),
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package com.jetpackduba.gitnuro.ui.context_menu
|
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(
|
fun stashContextMenuItems(
|
||||||
onStashWithMessage: () -> Unit,
|
onStashWithMessage: () -> Unit,
|
||||||
): List<DropDownContentData> {
|
): List<ContextMenuElement> {
|
||||||
return mutableListOf(
|
return mutableListOf(
|
||||||
DropDownContentData(
|
ContextMenuElement.ContextTextEntry(
|
||||||
label = "Stash with message",
|
label = "Stash with message",
|
||||||
onClick = onStashWithMessage,
|
onClick = onStashWithMessage,
|
||||||
|
icon = { painterResource(AppIcons.MESSAGE) }
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
1
src/main/resources/message.svg
Normal file
1
src/main/resources/message.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 4h16v12H5.17L4 17.17V4m0-2c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H4zm2 10h12v2H6v-2zm0-3h12v2H6V9zm0-3h12v2H6V6z"/></svg>
|
After Width: | Height: | Size: 300 B |
Loading…
Reference in New Issue
Block a user