Skip to content

Commit 9fc86f0

Browse files
committed
Added keybindings labels
1 parent 52875ec commit 9fc86f0

File tree

5 files changed

+212
-76
lines changed

5 files changed

+212
-76
lines changed

src/main/kotlin/com/jetpackduba/gitnuro/App.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ class App {
287287
modifier = Modifier
288288
.background(MaterialTheme.colors.background)
289289
.onPreviewKeyEvent {
290+
println(it.toString())
290291
when {
291292
it.matchesBinding(KeybindingOption.OPEN_NEW_TAB) -> {
292293
tabsManager.addNewEmptyTab()

src/main/kotlin/com/jetpackduba/gitnuro/git/log/GetLogUseCase.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class GetLogUseCase @Inject constructor() {
4242

4343
if (hasUncommittedChanges)
4444
commitList.addUncommittedChangesGraphCommit(logList.first())
45-
45+
// val count = walk.count()
46+
// println("Commits list count is $count")
4647
commitList.source(walk)
4748
}
4849
commitList.fillTo(commitsLimit)

src/main/kotlin/com/jetpackduba/gitnuro/keybindings/Keybinding.kt

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,11 @@ private fun baseKeybindings() = mapOf(
142142
),
143143
KeybindingOption.CHANGE_CURRENT_TAB_LEFT to listOf(
144144
Keybinding(key = Key.DirectionLeft, alt = true),
145+
Keybinding(key = Key.Tab, control = true, shift = true),
145146
),
146147
KeybindingOption.CHANGE_CURRENT_TAB_RIGHT to listOf(
147148
Keybinding(key = Key.DirectionRight, alt = true),
149+
Keybinding(key = Key.Tab, control = true),
148150
),
149151
)
150152

@@ -155,10 +157,26 @@ private fun macKeybindings(): Map<KeybindingOption, List<Keybinding>> {
155157
val macBindings = baseKeybindings().toMutableMap()
156158

157159
macBindings.apply {
158-
this[KeybindingOption.REFRESH] = listOf(
159-
Keybinding(key = Key.F5),
160-
Keybinding(meta = true, key = Key.R),
160+
val keysToReplaceControlWithCommand = listOf(
161+
KeybindingOption.REFRESH,
162+
KeybindingOption.PULL,
163+
KeybindingOption.PUSH,
164+
KeybindingOption.BRANCH_CREATE,
165+
KeybindingOption.STASH,
166+
KeybindingOption.STASH_POP,
167+
KeybindingOption.OPEN_REPOSITORY,
168+
KeybindingOption.OPEN_NEW_TAB,
169+
KeybindingOption.CLOSE_CURRENT_TAB,
161170
)
171+
172+
for (key in keysToReplaceControlWithCommand) {
173+
val originalKeybindings = this[key] ?: emptyList()
174+
val newKeybindings = originalKeybindings.map {
175+
it.copy(meta = it.control, control = false)
176+
}
177+
178+
this[key] = newKeybindings
179+
}
162180
}
163181

164182
return macBindings
@@ -185,4 +203,7 @@ fun KeyEvent.matchesBinding(keybindingOption: KeybindingOption): Boolean {
185203
keybinding.shift == this.isShiftPressed &&
186204
keybinding.key == this.key
187205
} && this.type == KeyEventType.KeyDown
188-
}
206+
}
207+
208+
val KeybindingOption.keyBinding
209+
get() = keybindings[this]?.firstOrNull()

src/main/kotlin/com/jetpackduba/gitnuro/ui/Menu.kt

Lines changed: 172 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
package com.jetpackduba.gitnuro.ui
44

5+
import androidx.compose.desktop.ui.tooling.preview.Preview
56
import androidx.compose.foundation.ExperimentalFoundationApi
67
import androidx.compose.foundation.Image
78
import androidx.compose.foundation.background
@@ -20,10 +21,12 @@ import androidx.compose.ui.draw.clip
2021
import androidx.compose.ui.focus.FocusRequester
2122
import androidx.compose.ui.graphics.ColorFilter
2223
import androidx.compose.ui.graphics.painter.Painter
24+
import androidx.compose.ui.input.key.Key
2325
import androidx.compose.ui.layout.LayoutCoordinates
2426
import androidx.compose.ui.layout.boundsInRoot
2527
import androidx.compose.ui.layout.onGloballyPositioned
2628
import androidx.compose.ui.res.painterResource
29+
import androidx.compose.ui.text.font.FontWeight
2730
import androidx.compose.ui.text.style.TextAlign
2831
import androidx.compose.ui.unit.*
2932
import androidx.compose.ui.window.Popup
@@ -34,6 +37,11 @@ import com.jetpackduba.gitnuro.extensions.handMouseClickable
3437
import com.jetpackduba.gitnuro.extensions.handOnHover
3538
import com.jetpackduba.gitnuro.extensions.ignoreKeyEvents
3639
import com.jetpackduba.gitnuro.git.remote_operations.PullType
40+
import com.jetpackduba.gitnuro.keybindings.Keybinding
41+
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
42+
import com.jetpackduba.gitnuro.keybindings.keyBinding
43+
import com.jetpackduba.gitnuro.theme.notoSansMonoFontFamily
44+
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
3745
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
3846
import com.jetpackduba.gitnuro.ui.components.tooltip.InstantTooltip
3947
import com.jetpackduba.gitnuro.ui.context_menu.*
@@ -62,19 +70,17 @@ fun Menu(
6270
horizontalArrangement = Arrangement.Center,
6371
verticalAlignment = Alignment.CenterVertically,
6472
) {
65-
InstantTooltip(
66-
text = "Open a different repository",
67-
enabled = !showOpenPopup,
68-
) {
69-
MenuButton(
70-
modifier = Modifier
71-
.padding(start = 16.dp)
72-
.onGloballyPositioned { setPosition(it) },
73-
title = "Open",
74-
icon = painterResource(AppIcons.OPEN),
75-
onClick = { onShowOpenPopupChange(true) },
76-
)
77-
}
73+
MenuButton(
74+
modifier = Modifier
75+
.padding(start = 16.dp)
76+
.onGloballyPositioned { setPosition(it) },
77+
title = "Open",
78+
icon = painterResource(AppIcons.OPEN),
79+
keybinding = KeybindingOption.OPEN_REPOSITORY.keyBinding,
80+
tooltip = "Open a different repository",
81+
tooltipEnabled = !showOpenPopup,
82+
onClick = { onShowOpenPopupChange(true) },
83+
)
7884

7985
Spacer(modifier = Modifier.weight(1f))
8086

@@ -126,16 +132,15 @@ fun Menu(
126132

127133
Spacer(modifier = Modifier.width(32.dp))
128134

129-
InstantTooltip(
130-
text = "Create a new branch",
131-
) {
132-
MenuButton(
133-
title = "Branch",
134-
icon = painterResource(AppIcons.BRANCH),
135-
) {
135+
MenuButton(
136+
title = "Branch",
137+
icon = painterResource(AppIcons.BRANCH),
138+
onClick = {
136139
onCreateBranch()
137-
}
138-
}
140+
},
141+
tooltip = "Create a new branch",
142+
keybinding = KeybindingOption.BRANCH_CREATE.keyBinding,
143+
)
139144

140145

141146
Spacer(modifier = Modifier.width(32.dp))
@@ -151,43 +156,42 @@ fun Menu(
151156
)
152157
)
153158

154-
InstantTooltip(
155-
text = "Pop the last stash"
156-
) {
157-
MenuButton(
158-
title = "Pop",
159-
icon = painterResource(AppIcons.APPLY_STASH),
160-
) { menuViewModel.popStash() }
161-
}
159+
MenuButton(
160+
title = "Pop",
161+
icon = painterResource(AppIcons.APPLY_STASH),
162+
keybinding = KeybindingOption.STASH_POP.keyBinding,
163+
tooltip = "Pop the last stash",
164+
) { menuViewModel.popStash() }
162165

163166
Spacer(modifier = Modifier.weight(1f))
164167

165-
InstantTooltip(
166-
text = "Open a terminal in the repository's path"
167-
) {
168-
MenuButton(
169-
modifier = Modifier.padding(end = 4.dp),
170-
title = "Terminal",
171-
icon = painterResource(AppIcons.TERMINAL),
172-
onClick = { menuViewModel.openTerminal() },
173-
)
174-
}
168+
MenuButton(
169+
modifier = Modifier.padding(end = 4.dp),
170+
title = "Terminal",
171+
icon = painterResource(AppIcons.TERMINAL),
172+
onClick = { menuViewModel.openTerminal() },
173+
tooltip = "Open a terminal in the repository's path",
174+
keybinding = null,
175+
)
175176

176177
MenuButton(
177178
modifier = Modifier.padding(end = 4.dp),
178179
title = "Actions",
179180
icon = painterResource(AppIcons.BOLT),
180181
onClick = onQuickActions,
182+
tooltip = "Additional actions",
183+
keybinding = null,
181184
)
182185

183-
InstantTooltip(
184-
text = "Gitnuro's settings",
186+
Box(
185187
modifier = Modifier.padding(end = 16.dp)
186188
) {
187189
MenuButton(
188190
title = "Settings",
189191
icon = painterResource(AppIcons.SETTINGS),
190192
onClick = onShowSettingsDialog,
193+
tooltip = "Gitnuro's settings",
194+
keybinding = KeybindingOption.STASH_POP.keyBinding,
191195
)
192196
}
193197
}
@@ -257,33 +261,135 @@ fun MenuButton(
257261
enabled: Boolean = true,
258262
title: String,
259263
icon: Painter,
260-
onClick: () -> Unit
264+
keybinding: Keybinding?,
265+
tooltip: String,
266+
tooltipEnabled: Boolean = true,
267+
onClick: () -> Unit,
261268
) {
262-
Column(
263-
modifier = modifier
264-
.ignoreKeyEvents()
265-
.clip(RoundedCornerShape(4.dp))
266-
.background(MaterialTheme.colors.surface)
267-
.handMouseClickable { if (enabled) onClick() }
268-
.size(56.dp),
269-
horizontalAlignment = Alignment.CenterHorizontally,
270-
verticalArrangement = Arrangement.Center,
269+
InstantTooltip(
270+
text = tooltip,
271+
enabled = tooltipEnabled,
272+
trailingContent = if (keybinding != null) {
273+
{ KeybindingHint(keybinding) }
274+
} else {
275+
null
276+
}
271277
) {
272-
Icon(
273-
painter = icon,
274-
contentDescription = title,
275-
modifier = Modifier
276-
.size(24.dp),
277-
tint = MaterialTheme.colors.onBackground,
278-
)
279-
Text(
280-
text = title,
281-
style = MaterialTheme.typography.caption,
282-
maxLines = 1,
283-
textAlign = TextAlign.Center,
284-
color = MaterialTheme.colors.onBackground,
285-
)
278+
Column(
279+
modifier = modifier
280+
.ignoreKeyEvents()
281+
.clip(RoundedCornerShape(4.dp))
282+
.background(MaterialTheme.colors.surface)
283+
.handMouseClickable { if (enabled) onClick() }
284+
.size(56.dp),
285+
horizontalAlignment = Alignment.CenterHorizontally,
286+
verticalArrangement = Arrangement.Center,
287+
) {
288+
Icon(
289+
painter = icon,
290+
contentDescription = title,
291+
modifier = Modifier
292+
.size(24.dp),
293+
tint = MaterialTheme.colors.onBackground,
294+
)
295+
Text(
296+
text = title,
297+
style = MaterialTheme.typography.caption,
298+
maxLines = 1,
299+
textAlign = TextAlign.Center,
300+
color = MaterialTheme.colors.onBackground,
301+
)
302+
}
303+
}
304+
}
305+
306+
@Composable
307+
fun KeybindingHint(keybinding: Keybinding) {
308+
val parts = remember(keybinding) { getParts(keybinding) }.joinToString("+")
309+
310+
Text(
311+
parts,
312+
fontFamily = notoSansMonoFontFamily,
313+
fontSize = MaterialTheme.typography.caption.fontSize,
314+
fontWeight = FontWeight.Medium,
315+
color = MaterialTheme.colors.onBackgroundSecondary,
316+
)
317+
}
318+
319+
@Preview
320+
@Composable
321+
fun KeybindingHintPartPreview() {
322+
KeybindingHintPart("CTRL")
323+
}
324+
325+
@Composable
326+
fun KeybindingHintPart(part: String) {
327+
Text(
328+
text = part,
329+
fontWeight = FontWeight.Medium,
330+
color = MaterialTheme.colors.primary,
331+
modifier = Modifier
332+
.clip(RoundedCornerShape(4.dp))
333+
.border(2.dp, MaterialTheme.colors.primary, RoundedCornerShape(4.dp))
334+
.background(MaterialTheme.colors.primary.copy(alpha = 0.05f))
335+
.padding(horizontal = 4.dp, vertical = 4.dp)
336+
337+
)
338+
}
339+
340+
fun getParts(keybinding: Keybinding): List<String> {
341+
val parts = mutableListOf<String>()
342+
343+
if (keybinding.control) {
344+
parts.add("Ctrl")
286345
}
346+
347+
if (keybinding.meta) {
348+
parts.add("")
349+
}
350+
351+
if (keybinding.alt) {
352+
parts.add("Alt")
353+
}
354+
355+
if (keybinding.shift) {
356+
parts.add("Shift")
357+
}
358+
359+
val key = when (keybinding.key) {
360+
Key.A -> "A"
361+
Key.B -> "B"
362+
Key.C -> "C"
363+
Key.D -> "D"
364+
Key.E -> "E"
365+
Key.F -> "F"
366+
Key.G -> "G"
367+
Key.H -> "H"
368+
Key.I -> "I"
369+
Key.J -> "J"
370+
Key.K -> "K"
371+
Key.L -> "L"
372+
Key.M -> "M"
373+
Key.N -> "N"
374+
Key.O -> "O"
375+
Key.P -> "P"
376+
Key.Q -> "Q"
377+
Key.R -> "R"
378+
Key.S -> "S"
379+
Key.T -> "T"
380+
Key.U -> "U"
381+
Key.V -> "V"
382+
Key.W -> "W"
383+
Key.X -> "X"
384+
Key.Y -> "Y"
385+
Key.Z -> "Z"
386+
Key.Tab -> "Tab"
387+
else -> throw NotImplementedError("Key not implemented")
388+
}
389+
390+
parts.add(key)
391+
392+
return parts
287393
}
288394

289395
@Composable

0 commit comments

Comments
 (0)