diff --git a/src/main/kotlin/app/git/BranchesManager.kt b/src/main/kotlin/app/git/BranchesManager.kt index 8af5ea4..4435f6d 100644 --- a/src/main/kotlin/app/git/BranchesManager.kt +++ b/src/main/kotlin/app/git/BranchesManager.kt @@ -3,13 +3,8 @@ package app.git import app.extensions.isBranch import app.extensions.simpleName import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.withContext -import org.eclipse.jgit.api.CreateBranchCommand -import org.eclipse.jgit.api.Git -import org.eclipse.jgit.api.ListBranchCommand -import org.eclipse.jgit.api.MergeCommand +import org.eclipse.jgit.api.* import org.eclipse.jgit.lib.Ref import org.eclipse.jgit.revwalk.RevCommit import javax.inject.Inject @@ -50,19 +45,6 @@ class BranchesManager @Inject constructor() { .call() } - suspend fun mergeBranch(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) { - val fastForwardMode = if (fastForward) - MergeCommand.FastForwardMode.FF - else - MergeCommand.FastForwardMode.NO_FF - - git - .merge() - .include(branch) - .setFastForward(fastForwardMode) - .call() - } - suspend fun deleteBranch(git: Git, branch: Ref) = withContext(Dispatchers.IO) { git .branchDelete() diff --git a/src/main/kotlin/app/git/LogManager.kt b/src/main/kotlin/app/git/LogManager.kt index 9b0aecb..26aa6c1 100644 --- a/src/main/kotlin/app/git/LogManager.kt +++ b/src/main/kotlin/app/git/LogManager.kt @@ -25,7 +25,7 @@ class LogManager @Inject constructor( suspend fun loadLog(git: Git, currentBranch: Ref?) = withContext(Dispatchers.IO) { val commitList = GraphCommitList() val repositoryState = git.repository.repositoryState - + println("Repository state ${repositoryState.description}") if(currentBranch != null || repositoryState.isRebasing) { // Current branch is null when there is no log (new repo) or rebasing val logList = git.log().setMaxCount(2).call().toList() diff --git a/src/main/kotlin/app/git/MergeManager.kt b/src/main/kotlin/app/git/MergeManager.kt new file mode 100644 index 0000000..7c3fefa --- /dev/null +++ b/src/main/kotlin/app/git/MergeManager.kt @@ -0,0 +1,31 @@ +package app.git + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.api.MergeCommand +import org.eclipse.jgit.api.ResetCommand +import org.eclipse.jgit.lib.Ref +import javax.inject.Inject + +class MergeManager @Inject constructor() { + suspend fun mergeBranch(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) { + val fastForwardMode = if (fastForward) + MergeCommand.FastForwardMode.FF + else + MergeCommand.FastForwardMode.NO_FF + + git + .merge() + .include(branch) + .setFastForward(fastForwardMode) + .call() + } + + suspend fun abortBranch(git: Git) = withContext(Dispatchers.IO) { + git.repository.writeMergeCommitMsg(null); + git.repository.writeMergeHeads(null); + + git.reset().setMode(ResetCommand.ResetType.HARD).call(); + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/git/RebaseManager.kt b/src/main/kotlin/app/git/RebaseManager.kt new file mode 100644 index 0000000..f46b918 --- /dev/null +++ b/src/main/kotlin/app/git/RebaseManager.kt @@ -0,0 +1,36 @@ +package app.git + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.api.RebaseCommand +import org.eclipse.jgit.lib.Ref +import javax.inject.Inject + +class RebaseManager @Inject constructor() { + + suspend fun rebaseBranch(git: Git, ref: Ref) = withContext(Dispatchers.IO) { + git.rebase() + .setOperation(RebaseCommand.Operation.BEGIN) + .setUpstream(ref.objectId) + .call() + } + + suspend fun continueRebase(git: Git) = withContext(Dispatchers.IO) { + git.rebase() + .setOperation(RebaseCommand.Operation.CONTINUE) + .call() + } + + suspend fun abortRebase(git: Git) = withContext(Dispatchers.IO) { + git.rebase() + .setOperation(RebaseCommand.Operation.ABORT) + .call() + } + + suspend fun skipRebase(git: Git) = withContext(Dispatchers.IO) { + git.rebase() + .setOperation(RebaseCommand.Operation.SKIP) + .call() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/ui/Branches.kt b/src/main/kotlin/app/ui/Branches.kt index 1962da0..d48ef20 100644 --- a/src/main/kotlin/app/ui/Branches.kt +++ b/src/main/kotlin/app/ui/Branches.kt @@ -19,6 +19,7 @@ import app.ui.components.SideMenuSubentry import app.ui.components.entryHeight import app.ui.context_menu.branchContextMenuItems import app.ui.dialogs.MergeDialog +import app.ui.dialogs.RebaseDialog import app.viewmodels.BranchesViewModel import org.eclipse.jgit.lib.Ref @@ -30,6 +31,7 @@ fun Branches( val branches by branchesViewModel.branches.collectAsState() val currentBranch by branchesViewModel.currentBranch.collectAsState() val (mergeBranch, setMergeBranch) = remember { mutableStateOf(null) } + val (rebaseBranch, setRebaseBranch) = remember { mutableStateOf(null) } Column { SideMenuEntry("Local branches") @@ -43,13 +45,14 @@ fun Branches( Box(modifier = Modifier.heightIn(max = maxHeight.dp)) { ScrollableLazyColumn(modifier = Modifier.fillMaxWidth()) { itemsIndexed(branches) { _, branch -> - BranchRow( + BranchLineEntry( branch = branch, isCurrentBranch = currentBranch == branch.name, onBranchClicked = { onBranchClicked(branch) }, onCheckoutBranch = { branchesViewModel.checkoutRef(branch) }, onMergeBranch = { setMergeBranch(branch) }, - onDeleteBranch = { branchesViewModel.deleteBranch(branch) }, + onRebaseBranch = { branchesViewModel.deleteBranch(branch) }, + onDeleteBranch = { setRebaseBranch(branch) }, ) } } @@ -64,16 +67,26 @@ fun Branches( onAccept = { ff -> branchesViewModel.mergeBranch(mergeBranch, ff) } ) } + + if (rebaseBranch != null) { + RebaseDialog( + currentBranch, + rebaseBranchName = rebaseBranch.name, + onReject = { setRebaseBranch(null) }, + onAccept = { branchesViewModel.rebaseBranch(rebaseBranch) } + ) + } } @OptIn(ExperimentalFoundationApi::class) @Composable -private fun BranchRow( +private fun BranchLineEntry( branch: Ref, isCurrentBranch: Boolean, onBranchClicked: () -> Unit, onCheckoutBranch: () -> Unit, onMergeBranch: () -> Unit, + onRebaseBranch: () -> Unit, onDeleteBranch: () -> Unit, ) { ContextMenuArea( @@ -84,6 +97,7 @@ private fun BranchRow( onCheckoutBranch = onCheckoutBranch, onMergeBranch = onMergeBranch, onDeleteBranch = onDeleteBranch, + onRebaseBranch = onRebaseBranch, ) } ) { diff --git a/src/main/kotlin/app/ui/UncommitedChanges.kt b/src/main/kotlin/app/ui/UncommitedChanges.kt index 18e9b96..9ea323b 100644 --- a/src/main/kotlin/app/ui/UncommitedChanges.kt +++ b/src/main/kotlin/app/ui/UncommitedChanges.kt @@ -22,7 +22,6 @@ import androidx.compose.ui.input.pointer.pointerMoveFilter import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import app.extensions.filePath @@ -58,7 +57,7 @@ fun UncommitedChanges( staged = stageStatus.staged unstaged = stageStatus.unstaged LaunchedEffect(staged) { - if(selectedEntryType != null) { + if (selectedEntryType != null) { checkIfSelectedEntryShouldBeUpdated( selectedEntryType = selectedEntryType, staged = staged, @@ -69,8 +68,8 @@ fun UncommitedChanges( } } } else { - staged = listOf() - unstaged = listOf() // return empty lists if still loading + staged = listOf() + unstaged = listOf() // return empty lists if still loading } val doCommit = { @@ -134,16 +133,20 @@ fun UncommitedChanges( allActionTitle = "Stage all" ) - Card( + Column( modifier = Modifier .padding(8.dp) - .height(192.dp) + .run { + // When rebasing, we don't need a fixed size as we don't show the message TextField + if(!repositoryState.isRebasing) { + height(192.dp) + } else + this + } .fillMaxWidth() ) { - Column( - modifier = Modifier - .fillMaxSize() - ) { + // Don't show the message TextField when rebasing as it can't be edited + if (!repositoryState.isRebasing) TextField( modifier = Modifier .fillMaxWidth() @@ -159,32 +162,131 @@ fun UncommitedChanges( onValueChange = { statusViewModel.newCommitMessage = it }, label = { Text("Write your commit message here", fontSize = 14.sp) }, colors = TextFieldDefaults.textFieldColors(backgroundColor = MaterialTheme.colors.background), - textStyle = TextStyle.Default.copy(fontSize = 14.sp), + textStyle = TextStyle.Default.copy(fontSize = 14.sp, color = MaterialTheme.colors.primaryTextColor), ) - Button( - modifier = Modifier - .fillMaxWidth(), - onClick = { - doCommit() - }, - enabled = canCommit, - shape = RectangleShape, - ) { - val buttonText = if(repositoryState.isMerging) - "Merge" - else if (repositoryState.isRebasing) - "Continue rebasing" - else - "Commit" - Text( - text = buttonText, - fontSize = 14.sp, - ) + when { + repositoryState.isMerging -> MergeButtons( + haveConflictsBeenSolved = unstaged.isEmpty(), + onAbort = { statusViewModel.abortMerge() }, + onMerge = { doCommit() } + ) + repositoryState.isRebasing -> RebasingButtons( + canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(), + haveConflictsBeenSolved = unstaged.isEmpty(), + onAbort = { statusViewModel.abortRebase() }, + onContinue = { statusViewModel.continueRebase() }, + onSkip = { statusViewModel.skipRebase() }, + ) + else -> { + Button( + modifier = Modifier + .fillMaxWidth(), + onClick = doCommit, + enabled = canCommit, + shape = RectangleShape, + ) { + + Text( + text = "Commit", + fontSize = 14.sp, + ) + } } } } } + +} + +@Composable +fun MergeButtons( + haveConflictsBeenSolved: Boolean, + onAbort: () -> Unit, + onMerge: () -> Unit, +) { + Row( + modifier = Modifier.fillMaxWidth() + ) { + Button( + onClick = onAbort, + modifier = Modifier + .weight(1f) + .padding(start = 8.dp, end = 4.dp), + ) { + Text( + text = "Abort", + fontSize = 14.sp, + ) + } + + Button( + onClick = onMerge, + enabled = haveConflictsBeenSolved, + modifier = Modifier + .weight(1f) + .padding(start = 8.dp, end = 4.dp), + ) { + Text( + text = "Merge", + fontSize = 14.sp, + ) + } + + } +} + +@Composable +fun RebasingButtons( + canContinue: Boolean, + haveConflictsBeenSolved: Boolean, + onAbort: () -> Unit, + onContinue: () -> Unit, + onSkip: () -> Unit, +) { + Row( + modifier = Modifier.fillMaxWidth() + ) { + Button( + onClick = onAbort, + modifier = Modifier + .weight(1f) + .padding(start = 8.dp, end = 4.dp), + ) { + Text( + text = "Abort", + fontSize = 14.sp, + ) + } + + if (canContinue) { + Button( + onClick = onContinue, + enabled = haveConflictsBeenSolved, + modifier = Modifier + .weight(1f) + .padding(start = 8.dp, end = 4.dp), + ) { + Text( + text = "Continue", + fontSize = 14.sp, + ) + } + } else { + Button( + onClick = onSkip, + modifier = Modifier + .weight(1f) + .padding(start = 8.dp, end = 4.dp), + ) { + Text( + text = "Skip", + fontSize = 14.sp, + ) + } + } + + } } // TODO: This logic should be part of the diffViewModel where it gets the latest version of the diffEntry @@ -199,9 +301,10 @@ fun checkIfSelectedEntryShouldBeUpdated( val selectedEntryTypeNewId = selectedDiffEntry.newId.name() if (selectedEntryType is DiffEntryType.StagedDiff) { - val entryType = staged.firstOrNull { stagedEntry -> stagedEntry.diffEntry.newPath == selectedDiffEntry.newPath }?.diffEntry + val entryType = + staged.firstOrNull { stagedEntry -> stagedEntry.diffEntry.newPath == selectedDiffEntry.newPath }?.diffEntry - if( + if ( entryType != null && selectedEntryTypeNewId != entryType.newId.name() ) { @@ -210,15 +313,15 @@ fun checkIfSelectedEntryShouldBeUpdated( } else if (entryType == null) { onStagedDiffEntrySelected(null) } - } else if(selectedEntryType is DiffEntryType.UnstagedDiff) { + } else if (selectedEntryType is DiffEntryType.UnstagedDiff) { val entryType = unstaged.firstOrNull { unstagedEntry -> - if(selectedDiffEntry.changeType == DiffEntry.ChangeType.DELETE) + if (selectedDiffEntry.changeType == DiffEntry.ChangeType.DELETE) unstagedEntry.diffEntry.oldPath == selectedDiffEntry.oldPath else unstagedEntry.diffEntry.newPath == selectedDiffEntry.newPath } - if(entryType != null) { + if (entryType != null) { onUnstagedDiffEntrySelected(entryType.diffEntry) } else onStagedDiffEntrySelected(null) diff --git a/src/main/kotlin/app/ui/context_menu/BranchContextMenu.kt b/src/main/kotlin/app/ui/context_menu/BranchContextMenu.kt index e770fa6..293d27e 100644 --- a/src/main/kotlin/app/ui/context_menu/BranchContextMenu.kt +++ b/src/main/kotlin/app/ui/context_menu/BranchContextMenu.kt @@ -9,22 +9,29 @@ fun branchContextMenuItems( isLocal: Boolean, onCheckoutBranch: () -> Unit, onMergeBranch: () -> Unit, + onRebaseBranch: () -> Unit, onDeleteBranch: () -> Unit, ): List { - return mutableListOf( - ContextMenuItem( - label = "Checkout branch", - onClick = onCheckoutBranch - ), - - ).apply { + return mutableListOf().apply { if (!isCurrentBranch) { + add( + ContextMenuItem( + label = "Checkout branch", + onClick = onCheckoutBranch + ) + ) add( ContextMenuItem( label = "Merge branch", onClick = onMergeBranch ) ) + add( + ContextMenuItem( + label = "Rebase branch", + onClick = onRebaseBranch + ) + ) } if (isLocal && !isCurrentBranch) { add( diff --git a/src/main/kotlin/app/ui/dialogs/RebaseDialog.kt b/src/main/kotlin/app/ui/dialogs/RebaseDialog.kt new file mode 100644 index 0000000..b0b985c --- /dev/null +++ b/src/main/kotlin/app/ui/dialogs/RebaseDialog.kt @@ -0,0 +1,83 @@ +package app.ui.dialogs + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import app.theme.primaryTextColor + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun RebaseDialog( + currentBranchName: String, + rebaseBranchName: String, + onReject: () -> Unit, + onAccept: () -> Unit +) { + MaterialDialog { + Column( + modifier = Modifier + .background(MaterialTheme.colors.background), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = currentBranchName, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colors.primaryTextColor, + ) + + + Text( + text = "will rebase ", + modifier = Modifier.padding(horizontal = 8.dp), + color = MaterialTheme.colors.primaryTextColor, + ) + + Text( + text = rebaseBranchName, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colors.primaryTextColor, + ) + } + + Text( + text = "After completing the operation, $currentBranchName will contain $rebaseBranchName changes", + color = MaterialTheme.colors.primaryTextColor, + ) + + Row( + modifier = Modifier + .padding(top = 16.dp) + .align(Alignment.End) + ) { + TextButton( + modifier = Modifier.padding(end = 8.dp), + onClick = { + onReject() + } + ) { + Text("Cancel") + } + Button( + onClick = { + onAccept() + } + ) { + Text("Rebase") + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/ui/log/Log.kt b/src/main/kotlin/app/ui/log/Log.kt index 9d436d1..34dd9ca 100644 --- a/src/main/kotlin/app/ui/log/Log.kt +++ b/src/main/kotlin/app/ui/log/Log.kt @@ -39,10 +39,7 @@ import app.ui.components.AvatarImage import app.ui.components.ScrollableLazyColumn import app.ui.context_menu.branchContextMenuItems import app.ui.context_menu.tagContextMenuItems -import app.ui.dialogs.MergeDialog -import app.ui.dialogs.NewBranchDialog -import app.ui.dialogs.NewTagDialog -import app.ui.dialogs.ResetBranchDialog +import app.ui.dialogs.* import app.viewmodels.LogStatus import app.viewmodels.LogViewModel import org.eclipse.jgit.lib.Ref @@ -156,6 +153,7 @@ fun Log( showCreateNewTag = { showLogDialog.value = LogDialog.NewTag(graphNode) }, resetBranch = { showLogDialog.value = LogDialog.ResetBranch(graphNode) }, onMergeBranch = { ref -> showLogDialog.value = LogDialog.MergeBranch(ref) }, + onRebaseBranch = { ref -> showLogDialog.value = LogDialog.RebaseBranch(ref) }, onRevCommitSelected = { onItemSelected(SelectedItem.Commit(graphNode)) } @@ -212,6 +210,19 @@ fun LogDialogs( onResetShowLogDialog() } ) + is LogDialog.RebaseBranch -> { + if(currentBranch != null) { + RebaseDialog( + currentBranchName = currentBranch.simpleName, + rebaseBranchName = showLogDialog.ref.simpleName, + onReject = onResetShowLogDialog, + onAccept = { + logViewModel.rebaseBranch(showLogDialog.ref) + onResetShowLogDialog() + } + ) + } + } LogDialog.None -> { } } @@ -334,6 +345,7 @@ fun CommitLine( showCreateNewTag: () -> Unit, resetBranch: (GraphNode) -> Unit, onMergeBranch: (Ref) -> Unit, + onRebaseBranch: (Ref) -> Unit, onRevCommitSelected: (GraphNode) -> Unit, ) { val commitRefs = graphNode.refs @@ -405,6 +417,7 @@ fun CommitLine( onMergeBranch = { ref -> onMergeBranch(ref) }, onDeleteBranch = { ref -> logViewModel.deleteBranch(ref) }, onDeleteTag = { ref -> logViewModel.deleteTag(ref) }, + onRebaseBranch = { ref -> onRebaseBranch(ref) }, ) } } @@ -422,6 +435,7 @@ fun CommitMessage( onCheckoutRef: (ref: Ref) -> Unit, onMergeBranch: (ref: Ref) -> Unit, onDeleteBranch: (ref: Ref) -> Unit, + onRebaseBranch: (ref: Ref) -> Unit, onDeleteTag: (ref: Ref) -> Unit, ) { val textColor = if (selected) { @@ -467,6 +481,7 @@ fun CommitMessage( onCheckoutBranch = { onCheckoutRef(ref) }, onMergeBranch = { onMergeBranch(ref) }, onDeleteBranch = { onDeleteBranch(ref) }, + onRebaseBranch = { onRebaseBranch(ref) }, ) } } @@ -644,6 +659,7 @@ fun BranchChip( onCheckoutBranch: () -> Unit, onMergeBranch: () -> Unit, onDeleteBranch: () -> Unit, + onRebaseBranch: () -> Unit, color: Color, ) { val contextMenuItemsList = { @@ -653,6 +669,7 @@ fun BranchChip( onCheckoutBranch = onCheckoutBranch, onMergeBranch = onMergeBranch, onDeleteBranch = onDeleteBranch, + onRebaseBranch = onRebaseBranch, ) } diff --git a/src/main/kotlin/app/ui/log/LogDialog.kt b/src/main/kotlin/app/ui/log/LogDialog.kt index a5a482b..1ca5799 100644 --- a/src/main/kotlin/app/ui/log/LogDialog.kt +++ b/src/main/kotlin/app/ui/log/LogDialog.kt @@ -9,4 +9,5 @@ sealed class LogDialog { data class NewTag(val graphNode: GraphNode) : LogDialog() data class ResetBranch(val graphNode: GraphNode) : LogDialog() data class MergeBranch(val ref: Ref) : LogDialog() + data class RebaseBranch(val ref: Ref) : LogDialog() } \ No newline at end of file diff --git a/src/main/kotlin/app/viewmodels/BranchesViewModel.kt b/src/main/kotlin/app/viewmodels/BranchesViewModel.kt index 6ab8b6d..c968377 100644 --- a/src/main/kotlin/app/viewmodels/BranchesViewModel.kt +++ b/src/main/kotlin/app/viewmodels/BranchesViewModel.kt @@ -1,8 +1,6 @@ package app.viewmodels -import app.git.BranchesManager -import app.git.RefreshType -import app.git.TabState +import app.git.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.eclipse.jgit.api.Git @@ -12,6 +10,8 @@ import javax.inject.Inject class BranchesViewModel @Inject constructor( private val branchesManager: BranchesManager, + private val rebaseManager: RebaseManager, + private val mergeManager: MergeManager, private val tabState: TabState, ) { private val _branches = MutableStateFlow>(listOf()) @@ -37,7 +37,7 @@ class BranchesViewModel @Inject constructor( } fun mergeBranch(ref: Ref, fastForward: Boolean) = tabState.safeProcessing { git -> - branchesManager.mergeBranch(git, ref, fastForward) + mergeManager.mergeBranch(git, ref, fastForward) return@safeProcessing RefreshType.ALL_DATA } @@ -57,4 +57,10 @@ class BranchesViewModel @Inject constructor( suspend fun refresh(git: Git) { loadBranches(git) } + + fun rebaseBranch(ref: Ref) = tabState.safeProcessing { git -> + rebaseManager.rebaseBranch(git, ref) + + return@safeProcessing RefreshType.ALL_DATA + } } \ No newline at end of file diff --git a/src/main/kotlin/app/viewmodels/LogViewModel.kt b/src/main/kotlin/app/viewmodels/LogViewModel.kt index 24c26f1..6a2d41f 100644 --- a/src/main/kotlin/app/viewmodels/LogViewModel.kt +++ b/src/main/kotlin/app/viewmodels/LogViewModel.kt @@ -4,7 +4,6 @@ import app.git.* import app.git.graph.GraphCommitList import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch import org.eclipse.jgit.api.Git import org.eclipse.jgit.lib.Ref import org.eclipse.jgit.revwalk.RevCommit @@ -14,7 +13,9 @@ class LogViewModel @Inject constructor( private val logManager: LogManager, private val statusManager: StatusManager, private val branchesManager: BranchesManager, + private val rebaseManager: RebaseManager, private val tagsManager: TagsManager, + private val mergeManager: MergeManager, private val tabState: TabState, ) { private val _logStatus = MutableStateFlow(LogStatus.Loading) @@ -69,7 +70,7 @@ class LogViewModel @Inject constructor( } fun mergeBranch(ref: Ref, fastForward: Boolean) = tabState.safeProcessing { git -> - branchesManager.mergeBranch(git, ref, fastForward) + mergeManager.mergeBranch(git, ref, fastForward) return@safeProcessing RefreshType.ALL_DATA } @@ -89,6 +90,12 @@ class LogViewModel @Inject constructor( suspend fun refresh(git: Git) { loadLog(git) } + + fun rebaseBranch(ref: Ref) = tabState.safeProcessing { git -> + rebaseManager.rebaseBranch(git, ref) + + return@safeProcessing RefreshType.ALL_DATA + } } sealed class LogStatus { diff --git a/src/main/kotlin/app/viewmodels/StatusViewModel.kt b/src/main/kotlin/app/viewmodels/StatusViewModel.kt index 41828a1..1879ec9 100644 --- a/src/main/kotlin/app/viewmodels/StatusViewModel.kt +++ b/src/main/kotlin/app/viewmodels/StatusViewModel.kt @@ -14,6 +14,8 @@ class StatusViewModel @Inject constructor( private val statusManager: StatusManager, private val branchesManager: BranchesManager, private val repositoryManager: RepositoryManager, + private val rebaseManager: RebaseManager, + private val mergeManager: MergeManager, ) { private val _stageStatus = MutableStateFlow(StageStatus.Loaded(listOf(), listOf())) val stageStatus: StateFlow = _stageStatus @@ -112,6 +114,30 @@ class StatusViewModel @Inject constructor( // Return true to update the log only if the uncommitedChanges status has changed return (hasNowUncommitedChanges != hadUncommitedChanges) } + + fun continueRebase() = tabState.safeProcessing { git -> + rebaseManager.continueRebase(git) + + return@safeProcessing RefreshType.ALL_DATA + } + + fun abortRebase() = tabState.safeProcessing { git -> + rebaseManager.abortRebase(git) + + return@safeProcessing RefreshType.ALL_DATA + } + + fun skipRebase() = tabState.safeProcessing { git -> + rebaseManager.skipRebase(git) + + return@safeProcessing RefreshType.ALL_DATA + } + + fun abortMerge() = tabState.safeProcessing { git -> + mergeManager.abortBranch(git) + + return@safeProcessing RefreshType.ALL_DATA + } } sealed class StageStatus {