Added keybindings labels

This commit is contained in:
Abdelilah El Aissaoui 2024-09-15 21:36:55 +02:00
parent 169ed5af3f
commit b1522fdee6
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
5 changed files with 212 additions and 76 deletions

View File

@ -277,6 +277,7 @@ class App {
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colors.background) .background(MaterialTheme.colors.background)
.onPreviewKeyEvent { .onPreviewKeyEvent {
println(it.toString())
when { when {
it.matchesBinding(KeybindingOption.OPEN_NEW_TAB) -> { it.matchesBinding(KeybindingOption.OPEN_NEW_TAB) -> {
tabsManager.addNewEmptyTab() tabsManager.addNewEmptyTab()

View File

@ -37,7 +37,8 @@ class GetLogUseCase @Inject constructor() {
if (hasUncommittedChanges) if (hasUncommittedChanges)
commitList.addUncommittedChangesGraphCommit(logList.first()) commitList.addUncommittedChangesGraphCommit(logList.first())
// val count = walk.count()
// println("Commits list count is $count")
commitList.source(walk) commitList.source(walk)
commitList.fillTo(commitsLimit) commitList.fillTo(commitsLimit)
} }

View File

@ -142,9 +142,11 @@ private fun baseKeybindings() = mapOf(
), ),
KeybindingOption.CHANGE_CURRENT_TAB_LEFT to listOf( KeybindingOption.CHANGE_CURRENT_TAB_LEFT to listOf(
Keybinding(key = Key.DirectionLeft, alt = true), Keybinding(key = Key.DirectionLeft, alt = true),
Keybinding(key = Key.Tab, control = true, shift = true),
), ),
KeybindingOption.CHANGE_CURRENT_TAB_RIGHT to listOf( KeybindingOption.CHANGE_CURRENT_TAB_RIGHT to listOf(
Keybinding(key = Key.DirectionRight, alt = true), Keybinding(key = Key.DirectionRight, alt = true),
Keybinding(key = Key.Tab, control = true),
), ),
) )
@ -155,10 +157,26 @@ private fun macKeybindings(): Map<KeybindingOption, List<Keybinding>> {
val macBindings = baseKeybindings().toMutableMap() val macBindings = baseKeybindings().toMutableMap()
macBindings.apply { macBindings.apply {
this[KeybindingOption.REFRESH] = listOf( val keysToReplaceControlWithCommand = listOf(
Keybinding(key = Key.F5), KeybindingOption.REFRESH,
Keybinding(meta = true, key = Key.R), KeybindingOption.PULL,
KeybindingOption.PUSH,
KeybindingOption.BRANCH_CREATE,
KeybindingOption.STASH,
KeybindingOption.STASH_POP,
KeybindingOption.OPEN_REPOSITORY,
KeybindingOption.OPEN_NEW_TAB,
KeybindingOption.CLOSE_CURRENT_TAB,
) )
for (key in keysToReplaceControlWithCommand) {
val originalKeybindings = this[key] ?: emptyList()
val newKeybindings = originalKeybindings.map {
it.copy(meta = it.control, control = false)
}
this[key] = newKeybindings
}
} }
return macBindings return macBindings
@ -186,3 +204,6 @@ fun KeyEvent.matchesBinding(keybindingOption: KeybindingOption): Boolean {
keybinding.key == this.key keybinding.key == this.key
} && this.type == KeyEventType.KeyDown } && this.type == KeyEventType.KeyDown
} }
val KeybindingOption.keyBinding
get() = keybindings[this]?.firstOrNull()

View File

@ -2,6 +2,7 @@
package com.jetpackduba.gitnuro.ui package com.jetpackduba.gitnuro.ui
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
@ -20,10 +21,12 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.boundsInRoot import androidx.compose.ui.layout.boundsInRoot
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.*
import androidx.compose.ui.window.Popup import androidx.compose.ui.window.Popup
@ -34,6 +37,11 @@ import com.jetpackduba.gitnuro.extensions.handMouseClickable
import com.jetpackduba.gitnuro.extensions.handOnHover import com.jetpackduba.gitnuro.extensions.handOnHover
import com.jetpackduba.gitnuro.extensions.ignoreKeyEvents import com.jetpackduba.gitnuro.extensions.ignoreKeyEvents
import com.jetpackduba.gitnuro.git.remote_operations.PullType import com.jetpackduba.gitnuro.git.remote_operations.PullType
import com.jetpackduba.gitnuro.keybindings.Keybinding
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
import com.jetpackduba.gitnuro.keybindings.keyBinding
import com.jetpackduba.gitnuro.theme.notoSansMonoFontFamily
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
import com.jetpackduba.gitnuro.ui.components.PrimaryButton import com.jetpackduba.gitnuro.ui.components.PrimaryButton
import com.jetpackduba.gitnuro.ui.components.tooltip.InstantTooltip import com.jetpackduba.gitnuro.ui.components.tooltip.InstantTooltip
import com.jetpackduba.gitnuro.ui.context_menu.* import com.jetpackduba.gitnuro.ui.context_menu.*
@ -62,19 +70,17 @@ fun Menu(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
InstantTooltip( MenuButton(
text = "Open a different repository", modifier = Modifier
enabled = !showOpenPopup, .padding(start = 16.dp)
) { .onGloballyPositioned { setPosition(it) },
MenuButton( title = "Open",
modifier = Modifier icon = painterResource(AppIcons.OPEN),
.padding(start = 16.dp) keybinding = KeybindingOption.OPEN_REPOSITORY.keyBinding,
.onGloballyPositioned { setPosition(it) }, tooltip = "Open a different repository",
title = "Open", tooltipEnabled = !showOpenPopup,
icon = painterResource(AppIcons.OPEN), onClick = { onShowOpenPopupChange(true) },
onClick = { onShowOpenPopupChange(true) }, )
)
}
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
@ -126,16 +132,15 @@ fun Menu(
Spacer(modifier = Modifier.width(32.dp)) Spacer(modifier = Modifier.width(32.dp))
InstantTooltip( MenuButton(
text = "Create a new branch", title = "Branch",
) { icon = painterResource(AppIcons.BRANCH),
MenuButton( onClick = {
title = "Branch",
icon = painterResource(AppIcons.BRANCH),
) {
onCreateBranch() onCreateBranch()
} },
} tooltip = "Create a new branch",
keybinding = KeybindingOption.BRANCH_CREATE.keyBinding,
)
Spacer(modifier = Modifier.width(32.dp)) Spacer(modifier = Modifier.width(32.dp))
@ -151,43 +156,42 @@ fun Menu(
) )
) )
InstantTooltip( MenuButton(
text = "Pop the last stash" title = "Pop",
) { icon = painterResource(AppIcons.APPLY_STASH),
MenuButton( keybinding = KeybindingOption.STASH_POP.keyBinding,
title = "Pop", tooltip = "Pop the last stash",
icon = painterResource(AppIcons.APPLY_STASH), ) { menuViewModel.popStash() }
) { menuViewModel.popStash() }
}
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
InstantTooltip( MenuButton(
text = "Open a terminal in the repository's path" modifier = Modifier.padding(end = 4.dp),
) { title = "Terminal",
MenuButton( icon = painterResource(AppIcons.TERMINAL),
modifier = Modifier.padding(end = 4.dp), onClick = { menuViewModel.openTerminal() },
title = "Terminal", tooltip = "Open a terminal in the repository's path",
icon = painterResource(AppIcons.TERMINAL), keybinding = null,
onClick = { menuViewModel.openTerminal() }, )
)
}
MenuButton( MenuButton(
modifier = Modifier.padding(end = 4.dp), modifier = Modifier.padding(end = 4.dp),
title = "Actions", title = "Actions",
icon = painterResource(AppIcons.BOLT), icon = painterResource(AppIcons.BOLT),
onClick = onQuickActions, onClick = onQuickActions,
tooltip = "Additional actions",
keybinding = KeybindingOption.STASH_POP.keyBinding,
) )
InstantTooltip( Box(
text = "Gitnuro's settings",
modifier = Modifier.padding(end = 16.dp) modifier = Modifier.padding(end = 16.dp)
) { ) {
MenuButton( MenuButton(
title = "Settings", title = "Settings",
icon = painterResource(AppIcons.SETTINGS), icon = painterResource(AppIcons.SETTINGS),
onClick = onShowSettingsDialog, onClick = onShowSettingsDialog,
tooltip = "Gitnuro's settings",
keybinding = KeybindingOption.STASH_POP.keyBinding,
) )
} }
} }
@ -257,35 +261,137 @@ fun MenuButton(
enabled: Boolean = true, enabled: Boolean = true,
title: String, title: String,
icon: Painter, icon: Painter,
onClick: () -> Unit keybinding: Keybinding?,
tooltip: String,
tooltipEnabled: Boolean = true,
onClick: () -> Unit,
) { ) {
Column( InstantTooltip(
modifier = modifier text = tooltip,
.ignoreKeyEvents() enabled = tooltipEnabled,
.clip(RoundedCornerShape(4.dp)) trailingContent = if (keybinding != null) {
.background(MaterialTheme.colors.surface) { KeybindingHint(keybinding) }
.handMouseClickable { if (enabled) onClick() } } else {
.size(56.dp), null
horizontalAlignment = Alignment.CenterHorizontally, }
verticalArrangement = Arrangement.Center,
) { ) {
Icon( Column(
painter = icon, modifier = modifier
contentDescription = title, .ignoreKeyEvents()
modifier = Modifier .clip(RoundedCornerShape(4.dp))
.size(24.dp), .background(MaterialTheme.colors.surface)
tint = MaterialTheme.colors.onBackground, .handMouseClickable { if (enabled) onClick() }
) .size(56.dp),
Text( horizontalAlignment = Alignment.CenterHorizontally,
text = title, verticalArrangement = Arrangement.Center,
style = MaterialTheme.typography.caption, ) {
maxLines = 1, Icon(
textAlign = TextAlign.Center, painter = icon,
color = MaterialTheme.colors.onBackground, contentDescription = title,
) modifier = Modifier
.size(24.dp),
tint = MaterialTheme.colors.onBackground,
)
Text(
text = title,
style = MaterialTheme.typography.caption,
maxLines = 1,
textAlign = TextAlign.Center,
color = MaterialTheme.colors.onBackground,
)
}
} }
} }
@Composable
fun KeybindingHint(keybinding: Keybinding) {
val parts = remember(keybinding) { getParts(keybinding) }.joinToString("+")
Text(
parts,
fontFamily = notoSansMonoFontFamily,
fontSize = MaterialTheme.typography.caption.fontSize,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colors.onBackgroundSecondary,
)
}
@Preview
@Composable
fun KeybindingHintPartPreview() {
KeybindingHintPart("CTRL")
}
@Composable
fun KeybindingHintPart(part: String) {
Text(
text = part,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colors.primary,
modifier = Modifier
.clip(RoundedCornerShape(4.dp))
.border(2.dp, MaterialTheme.colors.primary, RoundedCornerShape(4.dp))
.background(MaterialTheme.colors.primary.copy(alpha = 0.05f))
.padding(horizontal = 4.dp, vertical = 4.dp)
)
}
fun getParts(keybinding: Keybinding): List<String> {
val parts = mutableListOf<String>()
if (keybinding.control) {
parts.add("Ctrl")
}
if (keybinding.meta) {
parts.add("")
}
if (keybinding.alt) {
parts.add("Alt")
}
if (keybinding.shift) {
parts.add("Shift")
}
val key = when (keybinding.key) {
Key.A -> "A"
Key.B -> "B"
Key.C -> "C"
Key.D -> "D"
Key.E -> "E"
Key.F -> "F"
Key.G -> "G"
Key.H -> "H"
Key.I -> "I"
Key.J -> "J"
Key.K -> "K"
Key.L -> "L"
Key.M -> "M"
Key.N -> "N"
Key.O -> "O"
Key.P -> "P"
Key.Q -> "Q"
Key.R -> "R"
Key.S -> "S"
Key.T -> "T"
Key.U -> "U"
Key.V -> "V"
Key.W -> "W"
Key.X -> "X"
Key.Y -> "Y"
Key.Z -> "Z"
Key.Tab -> "Tab"
else -> throw NotImplementedError("Key not implemented")
}
parts.add(key)
return parts
}
@Composable @Composable
fun ExtendedMenuButton( fun ExtendedMenuButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,

View File

@ -28,6 +28,7 @@ import com.jetpackduba.gitnuro.theme.isDark
@Composable @Composable
fun InstantTooltip( fun InstantTooltip(
text: String?, text: String?,
trailingContent: (@Composable () -> Unit)? = null,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
position: InstantTooltipPosition = InstantTooltipPosition.BOTTOM, position: InstantTooltipPosition = InstantTooltipPosition.BOTTOM,
enabled: Boolean = true, enabled: Boolean = true,
@ -71,14 +72,14 @@ fun InstantTooltip(
onDismissRequest = {} onDismissRequest = {}
) { ) {
val padding = when(position) { val padding = when (position) {
InstantTooltipPosition.TOP -> PaddingValues(bottom = 4.dp) InstantTooltipPosition.TOP -> PaddingValues(bottom = 4.dp)
InstantTooltipPosition.BOTTOM -> PaddingValues(top = 4.dp) InstantTooltipPosition.BOTTOM -> PaddingValues(top = 4.dp)
InstantTooltipPosition.LEFT -> PaddingValues(end = 4.dp) InstantTooltipPosition.LEFT -> PaddingValues(end = 4.dp)
InstantTooltipPosition.RIGHT -> PaddingValues(start = 4.dp) InstantTooltipPosition.RIGHT -> PaddingValues(start = 4.dp)
} }
Box( Row(
modifier = Modifier modifier = Modifier
.padding(padding) .padding(padding)
.shadow(8.dp) .shadow(8.dp)
@ -94,15 +95,21 @@ fun InstantTooltip(
) )
} else } else
this this
}, }
.padding(8.dp),
) { ) {
Text( Text(
text = text, text = text,
fontSize = 12.sp, fontSize = 12.sp,
maxLines = 1, maxLines = 1,
color = MaterialTheme.colors.onBackground, color = MaterialTheme.colors.onBackground
modifier = Modifier.padding(8.dp)
) )
if (trailingContent != null) {
Spacer(Modifier.width(8.dp))
trailingContent()
}
} }
} }
} }