Skip to content

Commit

Permalink
Added keybindings to pull, push and create branch
Browse files Browse the repository at this point in the history
  • Loading branch information
JetpackDuba committed Aug 20, 2024
1 parent 0dad158 commit 761ea59
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 82 deletions.
24 changes: 24 additions & 0 deletions src/main/kotlin/com/jetpackduba/gitnuro/keybindings/Keybinding.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ enum class KeybindingOption {
* Used to go down in lists
*/
DOWN,

/**
* Used to pull in current repository
*/
PULL,

/**
* Used to push in current repository
*/
PUSH,

/**
* Used to show branch creation dialog
*/
BRANCH_CREATE,
}


Expand All @@ -66,6 +81,15 @@ private fun baseKeybindings() = mapOf(
KeybindingOption.DOWN to listOf(
Keybinding(key = Key.DirectionDown),
),
KeybindingOption.PULL to listOf(
Keybinding(key = Key.U, control = true),
),
KeybindingOption.PUSH to listOf(
Keybinding(key = Key.P, control = true),
),
KeybindingOption.BRANCH_CREATE to listOf(
Keybinding(key = Key.B, control = true),
),
)

private fun linuxKeybindings(): Map<KeybindingOption, List<Keybinding>> = baseKeybindings()
Expand Down
28 changes: 27 additions & 1 deletion src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.AppConstants
import com.jetpackduba.gitnuro.extensions.handMouseClickable
import com.jetpackduba.gitnuro.git.DiffType
import com.jetpackduba.gitnuro.git.rebase.RebaseInteractiveState
import com.jetpackduba.gitnuro.git.remote_operations.PullType
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
import com.jetpackduba.gitnuro.keybindings.matchesBinding
import com.jetpackduba.gitnuro.models.AuthorInfoSimple
Expand Down Expand Up @@ -106,7 +108,31 @@ fun RepositoryOpenPage(
LaunchedEffect(selectedItem) {
focusRequester.requestFocus()
}
Column {
Column (
modifier = Modifier.onPreviewKeyEvent {
println("Key event $it")
when {
it.matchesBinding(KeybindingOption.PULL) -> {
tabViewModel.pull(PullType.DEFAULT)
true
}
it.matchesBinding(KeybindingOption.PUSH) -> {
tabViewModel.push()
true
}
it.matchesBinding(KeybindingOption.BRANCH_CREATE) -> {
if (!showNewBranchDialog) {
showNewBranchDialog = true
true
} else {
false
}
}
else -> false
}

}
) {
Row(modifier = Modifier.weight(1f)) {
Column(
modifier = Modifier
Expand Down
11 changes: 7 additions & 4 deletions src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.AppConstants
import com.jetpackduba.gitnuro.AppIcons
import com.jetpackduba.gitnuro.extensions.*
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
import com.jetpackduba.gitnuro.keybindings.matchesBinding
import com.jetpackduba.gitnuro.theme.AppTheme
import com.jetpackduba.gitnuro.theme.backgroundSelected
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
Expand Down Expand Up @@ -343,24 +345,25 @@ fun RecentRepositoriesList(
if (it.type != KeyEventType.KeyDown) {
return@onPreviewKeyEvent false
}
when (it.key) {
Key.DirectionDown -> {

when {
it.matchesBinding(KeybindingOption.DOWN) -> {
if (focusedItemIndex < filteredRepositories.lastIndex) {
focusedItemIndex += 1
scope.launch { listState.animateScrollToItem(focusedItemIndex) }
}
true
}

Key.DirectionUp -> {
it.matchesBinding(KeybindingOption.UP) -> {
if (focusedItemIndex > 0) {
focusedItemIndex -= 1
scope.launch { listState.animateScrollToItem(focusedItemIndex) }
}
true
}

Key.Enter -> {
it.matchesBinding(KeybindingOption.SIMPLE_ACCEPT) -> {
val repo = filteredRepositories.getOrNull(focusedItemIndex)
if (repo != null && isSearchFocused) {
onOpenKnownRepository(repo)
Expand Down
4 changes: 0 additions & 4 deletions src/main/kotlin/com/jetpackduba/gitnuro/ui/diff/Diff.kt
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,6 @@ fun Diff(

ViewDiffResult.None -> throw NotImplementedError("None should be a possible state in the diff")
}

LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.jetpackduba.gitnuro.viewmodels

import com.jetpackduba.gitnuro.TaskType
import com.jetpackduba.gitnuro.git.RefreshType
import com.jetpackduba.gitnuro.git.TabState
import com.jetpackduba.gitnuro.git.remote_operations.FetchAllRemotesUseCase
import com.jetpackduba.gitnuro.git.remote_operations.PullBranchUseCase
import com.jetpackduba.gitnuro.git.remote_operations.PullType
import com.jetpackduba.gitnuro.git.remote_operations.PushBranchUseCase
import com.jetpackduba.gitnuro.git.stash.PopLastStashUseCase
import com.jetpackduba.gitnuro.git.stash.StashChangesUseCase
import com.jetpackduba.gitnuro.managers.AppStateManager
import com.jetpackduba.gitnuro.models.errorNotification
import com.jetpackduba.gitnuro.models.positiveNotification
import com.jetpackduba.gitnuro.repositories.AppSettingsRepository
import com.jetpackduba.gitnuro.terminal.OpenRepositoryInTerminalUseCase
import kotlinx.coroutines.Job
import javax.inject.Inject

interface IGlobalMenuActionsViewModel {
fun pull(pullType: PullType): Job
fun fetchAll(): Job
fun push(force: Boolean = false, pushTags: Boolean = false): Job
fun stash(): Job
fun popStash(): Job
fun openTerminal(): Job
}

class GlobalMenuActionsViewModel @Inject constructor(
private val tabState: TabState,
private val pullBranchUseCase: PullBranchUseCase,
private val pushBranchUseCase: PushBranchUseCase,
private val fetchAllRemotesUseCase: FetchAllRemotesUseCase,
private val popLastStashUseCase: PopLastStashUseCase,
private val stashChangesUseCase: StashChangesUseCase,
private val openRepositoryInTerminalUseCase: OpenRepositoryInTerminalUseCase,
settings: AppSettingsRepository,
appStateManager: AppStateManager,
) : IGlobalMenuActionsViewModel {
override fun pull(pullType: PullType) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA,
title = "Pulling",
subtitle = "Pulling changes from the remote branch to the current branch",
refreshEvenIfCrashes = true,
taskType = TaskType.PULL,
) { git ->
pullBranchUseCase(git, pullType)

positiveNotification("Pull completed")
}

override fun fetchAll() = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA,
title = "Fetching",
subtitle = "Updating references from the remote repositories...",
isCancellable = false,
refreshEvenIfCrashes = true,
taskType = TaskType.FETCH,
) { git ->
fetchAllRemotesUseCase(git)

positiveNotification("Fetch all completed")
}

override fun push(force: Boolean, pushTags: Boolean) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA,
title = "Push",
subtitle = "Pushing current branch to the remote repository",
isCancellable = false,
refreshEvenIfCrashes = true,
taskType = TaskType.PUSH,
) { git ->
pushBranchUseCase(git, force, pushTags)

positiveNotification("Push completed")
}

override fun stash() = tabState.safeProcessing(
refreshType = RefreshType.UNCOMMITTED_CHANGES_AND_LOG,
taskType = TaskType.STASH,
) { git ->
if (stashChangesUseCase(git, null)) {
positiveNotification("Changes stashed")
} else {
errorNotification("There are no changes to stash")
}
}

override fun popStash() = tabState.safeProcessing(
refreshType = RefreshType.UNCOMMITTED_CHANGES_AND_LOG,
refreshEvenIfCrashes = true,
taskType = TaskType.POP_STASH,
) { git ->
popLastStashUseCase(git)

positiveNotification("Stash popped")
}

override fun openTerminal() = tabState.runOperation(
refreshType = RefreshType.NONE
) { git ->
openRepositoryInTerminalUseCase(git.repository.workTree.absolutePath)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,80 +20,11 @@ import javax.inject.Inject

class MenuViewModel @Inject constructor(
private val tabState: TabState,
private val pullBranchUseCase: PullBranchUseCase,
private val pushBranchUseCase: PushBranchUseCase,
private val fetchAllRemotesUseCase: FetchAllRemotesUseCase,
private val popLastStashUseCase: PopLastStashUseCase,
private val stashChangesUseCase: StashChangesUseCase,
private val openRepositoryInTerminalUseCase: OpenRepositoryInTerminalUseCase,
private val globalMenuActionsViewModel: GlobalMenuActionsViewModel,
settings: AppSettingsRepository,
appStateManager: AppStateManager,
) {
): IGlobalMenuActionsViewModel by globalMenuActionsViewModel {
val isPullWithRebaseDefault = settings.pullRebaseFlow
val lastLoadedTabs = appStateManager.latestOpenedRepositoriesPaths

fun pull(pullType: PullType) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA,
title = "Pulling",
subtitle = "Pulling changes from the remote branch to the current branch",
refreshEvenIfCrashes = true,
taskType = TaskType.PULL,
) { git ->
pullBranchUseCase(git, pullType)

positiveNotification("Pull completed")
}

fun fetchAll() = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA,
title = "Fetching",
subtitle = "Updating references from the remote repositories...",
isCancellable = false,
refreshEvenIfCrashes = true,
taskType = TaskType.FETCH,
) { git ->
fetchAllRemotesUseCase(git)

positiveNotification("Fetch all completed")
}

fun push(force: Boolean = false, pushTags: Boolean = false) = tabState.safeProcessing(
refreshType = RefreshType.ALL_DATA,
title = "Push",
subtitle = "Pushing current branch to the remote repository",
isCancellable = false,
refreshEvenIfCrashes = true,
taskType = TaskType.PUSH,
) { git ->
pushBranchUseCase(git, force, pushTags)

positiveNotification("Push completed")
}

fun stash() = tabState.safeProcessing(
refreshType = RefreshType.UNCOMMITTED_CHANGES_AND_LOG,
taskType = TaskType.STASH,
) { git ->
if (stashChangesUseCase(git, null)) {
positiveNotification("Changes stashed")
} else {
errorNotification("There are no changes to stash")
}
}

fun popStash() = tabState.safeProcessing(
refreshType = RefreshType.UNCOMMITTED_CHANGES_AND_LOG,
refreshEvenIfCrashes = true,
taskType = TaskType.POP_STASH,
) { git ->
popLastStashUseCase(git)

positiveNotification("Stash popped")
}

fun openTerminal() = tabState.runOperation(
refreshType = RefreshType.NONE
) { git ->
openRepositoryInTerminalUseCase(git.repository.workTree.absolutePath)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import com.jetpackduba.gitnuro.managers.newErrorNow
import com.jetpackduba.gitnuro.models.AuthorInfoSimple
import com.jetpackduba.gitnuro.models.errorNotification
import com.jetpackduba.gitnuro.models.positiveNotification
import com.jetpackduba.gitnuro.models.warningNotification
import com.jetpackduba.gitnuro.system.OpenFilePickerUseCase
import com.jetpackduba.gitnuro.system.OpenUrlInBrowserUseCase
import com.jetpackduba.gitnuro.system.PickerType
Expand Down Expand Up @@ -77,7 +76,9 @@ class TabViewModel @Inject constructor(
private val tabScope: CoroutineScope,
private val verticalSplitPaneConfig: VerticalSplitPaneConfig,
val tabViewModelsProvider: TabViewModelsProvider,
) : IVerticalSplitPaneConfig by verticalSplitPaneConfig {
private val globalMenuActionsViewModel: GlobalMenuActionsViewModel,
) : IVerticalSplitPaneConfig by verticalSplitPaneConfig,
IGlobalMenuActionsViewModel by globalMenuActionsViewModel {
var initialPath: String? = null // Stores the path that should be opened when the tab is selected
val errorsManager: ErrorsManager = tabState.errorsManager
val selectedItem: StateFlow<SelectedItem> = tabState.selectedItem
Expand Down

0 comments on commit 761ea59

Please sign in to comment.