Add squash feature
This commit is contained in:
parent
0a7741423d
commit
0685986a13
@ -5,5 +5,6 @@ import org.eclipse.jgit.revwalk.RevCommit
|
|||||||
|
|
||||||
sealed interface TaskEvent {
|
sealed interface TaskEvent {
|
||||||
data class RebaseInteractive(val revCommit: RevCommit) : TaskEvent
|
data class RebaseInteractive(val revCommit: RevCommit) : TaskEvent
|
||||||
|
data class SquashCommits(val commits: List<RevCommit>, val upstreamCommit: RevCommit) : TaskEvent
|
||||||
data class ScrollToGraphItem(val selectedItem: SelectedItem) : TaskEvent
|
data class ScrollToGraphItem(val selectedItem: SelectedItem) : TaskEvent
|
||||||
}
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.jetpackduba.gitnuro.git.branches
|
||||||
|
|
||||||
|
import com.jetpackduba.gitnuro.extensions.isBranch
|
||||||
|
import com.jetpackduba.gitnuro.extensions.isHead
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.api.ListBranchCommand
|
||||||
|
import org.eclipse.jgit.lib.ObjectId
|
||||||
|
import org.eclipse.jgit.lib.Ref
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GetBranchByCommitUseCase @Inject constructor() {
|
||||||
|
|
||||||
|
suspend operator fun invoke(git: Git, commit: RevCommit): Ref = withContext(Dispatchers.IO) {
|
||||||
|
git
|
||||||
|
.branchList()
|
||||||
|
.setContains(commit.id.name)
|
||||||
|
.setListMode(ListBranchCommand.ListMode.ALL)
|
||||||
|
.call()
|
||||||
|
.first { it.isBranch }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -127,9 +127,12 @@ fun RepositoryOpenPage(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel
|
val rebaseInteractiveViewModel = tabViewModel.rebaseInteractiveViewModel
|
||||||
|
val squashCommitsViewModel = tabViewModel.squashCommitsViewModel
|
||||||
|
|
||||||
if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
|
if (repositoryState == RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
|
||||||
RebaseInteractive(rebaseInteractiveViewModel)
|
RebaseInteractive(rebaseInteractiveViewModel)
|
||||||
|
} else if (repositoryState == RepositoryState.REBASING_INTERACTIVE && squashCommitsViewModel != null) {
|
||||||
|
SquashCommits(squashCommitsViewModel)
|
||||||
} else if (repositoryState == RepositoryState.REBASING_INTERACTIVE) {
|
} else if (repositoryState == RepositoryState.REBASING_INTERACTIVE) {
|
||||||
RebaseInteractiveStartedExternally(
|
RebaseInteractiveStartedExternally(
|
||||||
onCancelRebaseInteractive = { tabViewModel.cancelRebaseInteractive() }
|
onCancelRebaseInteractive = { tabViewModel.cancelRebaseInteractive() }
|
||||||
|
101
src/main/kotlin/com/jetpackduba/gitnuro/ui/SquashCommits.kt
Normal file
101
src/main/kotlin/com/jetpackduba/gitnuro/ui/SquashCommits.kt
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package com.jetpackduba.gitnuro.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.CircularProgressIndicator
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||||
|
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||||
|
import com.jetpackduba.gitnuro.viewmodels.SquashCommitsState
|
||||||
|
import com.jetpackduba.gitnuro.viewmodels.SquashCommitsViewModel
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SquashCommits(
|
||||||
|
squashCommitsViewModel: SquashCommitsViewModel
|
||||||
|
) {
|
||||||
|
val state = squashCommitsViewModel.squashState.collectAsState()
|
||||||
|
val stateValue = state.value
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colors.surface)
|
||||||
|
.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
when (stateValue) {
|
||||||
|
is SquashCommitsState.Failed -> {}
|
||||||
|
is SquashCommitsState.Loaded -> {
|
||||||
|
SquashCommitsLoaded(
|
||||||
|
squashCommitsViewModel,
|
||||||
|
stateValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SquashCommitsState.Loading -> {
|
||||||
|
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SquashCommitsLoaded(
|
||||||
|
viewModel: SquashCommitsViewModel,
|
||||||
|
stateValue: SquashCommitsState.Loaded,
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = "Edit message for squashed commits",
|
||||||
|
color = MaterialTheme.colors.onBackground,
|
||||||
|
modifier = Modifier.padding(start = 16.dp, top = 16.dp),
|
||||||
|
fontSize = 20.sp,
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
AdjustableOutlinedTextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.heightIn(min = 40.dp),
|
||||||
|
value = stateValue.message,
|
||||||
|
onValueChange = {
|
||||||
|
viewModel.editMessage(it)
|
||||||
|
},
|
||||||
|
textStyle = MaterialTheme.typography.body2,
|
||||||
|
backgroundColor = MaterialTheme.colors.background
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(bottom = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
PrimaryButton(
|
||||||
|
text = "Cancel",
|
||||||
|
modifier = Modifier.padding(end = 8.dp),
|
||||||
|
onClick = {
|
||||||
|
viewModel.cancel()
|
||||||
|
},
|
||||||
|
backgroundColor = Color.Transparent,
|
||||||
|
textColor = MaterialTheme.colors.onBackground,
|
||||||
|
)
|
||||||
|
PrimaryButton(
|
||||||
|
modifier = Modifier.padding(end = 16.dp),
|
||||||
|
onClick = {
|
||||||
|
viewModel.continueSquash()
|
||||||
|
},
|
||||||
|
text = "OK"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -140,7 +140,11 @@ fun showPopup(x: Int, y: Int, contextMenuElements: List<ContextMenuElement>, onD
|
|||||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||||
for (item in contextMenuElements) {
|
for (item in contextMenuElements) {
|
||||||
when (item) {
|
when (item) {
|
||||||
is ContextMenuElement.ContextTextEntry -> TextEntry(item, onDismissRequest = onDismissRequest)
|
is ContextMenuElement.ContextTextEntry -> {
|
||||||
|
if (item.isVisible) {
|
||||||
|
TextEntry(item, onDismissRequest = onDismissRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
ContextMenuElement.ContextSeparator -> Separator()
|
ContextMenuElement.ContextSeparator -> Separator()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +207,8 @@ sealed interface ContextMenuElement {
|
|||||||
data class ContextTextEntry(
|
data class ContextTextEntry(
|
||||||
val label: String,
|
val label: String,
|
||||||
val icon: @Composable (() -> Painter)? = null,
|
val icon: @Composable (() -> Painter)? = null,
|
||||||
val onClick: () -> Unit = {}
|
val onClick: () -> Unit = {},
|
||||||
|
val isVisible: Boolean = true,
|
||||||
) : ContextMenuElement
|
) : ContextMenuElement
|
||||||
|
|
||||||
object ContextSeparator : ContextMenuElement
|
object ContextSeparator : ContextMenuElement
|
||||||
|
@ -10,12 +10,20 @@ fun logContextMenu(
|
|||||||
onCherryPickCommit: () -> Unit,
|
onCherryPickCommit: () -> Unit,
|
||||||
onResetBranch: () -> Unit,
|
onResetBranch: () -> Unit,
|
||||||
onRebaseInteractive: () -> Unit,
|
onRebaseInteractive: () -> Unit,
|
||||||
|
showSquashCommits: Boolean,
|
||||||
|
onSquashCommits: () -> Unit,
|
||||||
) = listOf(
|
) = listOf(
|
||||||
ContextMenuElement.ContextTextEntry(
|
ContextMenuElement.ContextTextEntry(
|
||||||
label = "Checkout commit",
|
label = "Checkout commit",
|
||||||
icon = { painterResource("start.svg") },
|
icon = { painterResource("start.svg") },
|
||||||
onClick = onCheckoutCommit
|
onClick = onCheckoutCommit
|
||||||
),
|
),
|
||||||
|
ContextMenuElement.ContextTextEntry(
|
||||||
|
label = "Squash commits",
|
||||||
|
icon = { painterResource("branch.svg") },
|
||||||
|
isVisible = showSquashCommits,
|
||||||
|
onClick = onSquashCommits
|
||||||
|
),
|
||||||
ContextMenuElement.ContextTextEntry(
|
ContextMenuElement.ContextTextEntry(
|
||||||
label = "Create branch",
|
label = "Create branch",
|
||||||
icon = { painterResource("branch.svg") },
|
icon = { painterResource("branch.svg") },
|
||||||
|
@ -429,6 +429,8 @@ fun MessagesList(
|
|||||||
onRevCommitSelected = {
|
onRevCommitSelected = {
|
||||||
logViewModel.selectLogLine(graphNode, keyScope.isCtrlPressed, keyScope.isShiftPressed)
|
logViewModel.selectLogLine(graphNode, keyScope.isCtrlPressed, keyScope.isShiftPressed)
|
||||||
},
|
},
|
||||||
|
onSquashCommits = { logViewModel.squashCommits() },
|
||||||
|
showSquashCommits = selectedItem is SelectedItem.MultiCommitBasedItem && selectedItem.itemList.size > 1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -764,6 +766,8 @@ fun CommitLine(
|
|||||||
onRebaseBranch: (Ref) -> Unit,
|
onRebaseBranch: (Ref) -> Unit,
|
||||||
onRevCommitSelected: () -> Unit,
|
onRevCommitSelected: () -> Unit,
|
||||||
onRebaseInteractive: () -> Unit,
|
onRebaseInteractive: () -> Unit,
|
||||||
|
onSquashCommits: () -> Unit,
|
||||||
|
showSquashCommits: Boolean,
|
||||||
) {
|
) {
|
||||||
ContextMenu(
|
ContextMenu(
|
||||||
items = {
|
items = {
|
||||||
@ -775,6 +779,8 @@ fun CommitLine(
|
|||||||
onCherryPickCommit = { logViewModel.cherrypickCommit(graphNode) },
|
onCherryPickCommit = { logViewModel.cherrypickCommit(graphNode) },
|
||||||
onRebaseInteractive = onRebaseInteractive,
|
onRebaseInteractive = onRebaseInteractive,
|
||||||
onResetBranch = { resetBranch() },
|
onResetBranch = { resetBranch() },
|
||||||
|
onSquashCommits = { onSquashCommits() },
|
||||||
|
showSquashCommits = showSquashCommits,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -10,6 +10,7 @@ import com.jetpackduba.gitnuro.git.branches.*
|
|||||||
import com.jetpackduba.gitnuro.git.graph.GraphCommitList
|
import com.jetpackduba.gitnuro.git.graph.GraphCommitList
|
||||||
import com.jetpackduba.gitnuro.git.graph.GraphNode
|
import com.jetpackduba.gitnuro.git.graph.GraphNode
|
||||||
import com.jetpackduba.gitnuro.git.log.*
|
import com.jetpackduba.gitnuro.git.log.*
|
||||||
|
import com.jetpackduba.gitnuro.git.rebase.GetRebaseLinesFullMessageUseCase
|
||||||
import com.jetpackduba.gitnuro.git.rebase.RebaseBranchUseCase
|
import com.jetpackduba.gitnuro.git.rebase.RebaseBranchUseCase
|
||||||
import com.jetpackduba.gitnuro.git.remote_operations.DeleteRemoteBranchUseCase
|
import com.jetpackduba.gitnuro.git.remote_operations.DeleteRemoteBranchUseCase
|
||||||
import com.jetpackduba.gitnuro.git.remote_operations.PullFromSpecificBranchUseCase
|
import com.jetpackduba.gitnuro.git.remote_operations.PullFromSpecificBranchUseCase
|
||||||
@ -25,8 +26,11 @@ import com.jetpackduba.gitnuro.ui.log.LogDialog
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler
|
||||||
import org.eclipse.jgit.api.errors.CheckoutConflictException
|
import org.eclipse.jgit.api.errors.CheckoutConflictException
|
||||||
|
import org.eclipse.jgit.lib.RebaseTodoLine
|
||||||
import org.eclipse.jgit.lib.Ref
|
import org.eclipse.jgit.lib.Ref
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -63,6 +67,7 @@ class LogViewModel @Inject constructor(
|
|||||||
private val createTagOnCommitUseCase: CreateTagOnCommitUseCase,
|
private val createTagOnCommitUseCase: CreateTagOnCommitUseCase,
|
||||||
private val deleteTagUseCase: DeleteTagUseCase,
|
private val deleteTagUseCase: DeleteTagUseCase,
|
||||||
private val rebaseBranchUseCase: RebaseBranchUseCase,
|
private val rebaseBranchUseCase: RebaseBranchUseCase,
|
||||||
|
private val getRebaseLinesFullMessageUseCase: GetRebaseLinesFullMessageUseCase,
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val appSettings: AppSettings,
|
private val appSettings: AppSettings,
|
||||||
private val tabScope: CoroutineScope,
|
private val tabScope: CoroutineScope,
|
||||||
@ -305,6 +310,29 @@ class LogViewModel @Inject constructor(
|
|||||||
NONE_MATCHING_INDEX
|
NONE_MATCHING_INDEX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun squashCommits() = tabState.runOperation(
|
||||||
|
refreshType = RefreshType.NONE,
|
||||||
|
) {
|
||||||
|
val selectedItem = tabState.selectedItem.value
|
||||||
|
val log = logStatus.value
|
||||||
|
|
||||||
|
if (selectedItem is SelectedItem.MultiCommitBasedItem && log is LogStatus.Loaded) {
|
||||||
|
val firstCommit = selectedItem.itemList
|
||||||
|
.sortedBy { it.commitTime }
|
||||||
|
.minBy { it.commitTime }
|
||||||
|
|
||||||
|
val firstCommitIndex = log.plotCommitList.indexOf(firstCommit)
|
||||||
|
val upstreamCommit = log.plotCommitList[firstCommitIndex + 1]
|
||||||
|
|
||||||
|
tabState.emitNewTaskEvent(
|
||||||
|
TaskEvent.SquashCommits(
|
||||||
|
commits = selectedItem.itemList,
|
||||||
|
upstreamCommit = upstreamCommit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun selectLogLine(
|
fun selectLogLine(
|
||||||
commit: GraphNode,
|
commit: GraphNode,
|
||||||
multiSelect: Boolean,
|
multiSelect: Boolean,
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.jetpackduba.gitnuro.viewmodels
|
||||||
|
|
||||||
|
import com.jetpackduba.gitnuro.git.RefreshType
|
||||||
|
import com.jetpackduba.gitnuro.git.TabState
|
||||||
|
import com.jetpackduba.gitnuro.git.branches.GetBranchByCommitUseCase
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import org.eclipse.jgit.lib.RebaseTodoLine
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SquashCommitsViewModel @Inject constructor(
|
||||||
|
private val tabState: TabState,
|
||||||
|
private val rebaseInteractiveViewModel: RebaseInteractiveViewModel,
|
||||||
|
private val getBranchByCommitUseCase: GetBranchByCommitUseCase,
|
||||||
|
) {
|
||||||
|
private val _squashState = MutableStateFlow<SquashCommitsState>(SquashCommitsState.Loading)
|
||||||
|
val squashState: StateFlow<SquashCommitsState> = _squashState
|
||||||
|
|
||||||
|
private var commits: List<RevCommit> = emptyList()
|
||||||
|
private var squashMessage: String? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
tabState.runOperation(
|
||||||
|
refreshType = RefreshType.NONE
|
||||||
|
) {
|
||||||
|
rebaseInteractiveViewModel.rebaseState.collect { state ->
|
||||||
|
_squashState.value = when (state) {
|
||||||
|
is RebaseInteractiveState.Failed -> SquashCommitsState.Failed(state.error)
|
||||||
|
is RebaseInteractiveState.Loading -> SquashCommitsState.Loading
|
||||||
|
is RebaseInteractiveState.Loaded -> {
|
||||||
|
SquashCommitsState.Loaded(
|
||||||
|
message = getDefaultSquashMessageFromCommits(
|
||||||
|
messages = commits.mapNotNull { state.messages[it.abbreviate(7).name()] }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun startSquash(commits: List<RevCommit>, upstreamCommit: RevCommit) = tabState.runOperation(
|
||||||
|
refreshType = RefreshType.ALL_DATA,
|
||||||
|
showError = true,
|
||||||
|
) { git ->
|
||||||
|
commits
|
||||||
|
.groupBy { getBranchByCommitUseCase(git, it) }
|
||||||
|
.let {
|
||||||
|
if (it.size > 1) throw Exception("Squash is impossible")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.commits = commits
|
||||||
|
|
||||||
|
rebaseInteractiveViewModel.startRebaseInteractive(upstreamCommit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancel() {
|
||||||
|
rebaseInteractiveViewModel.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun editMessage(message: String) {
|
||||||
|
val state = _squashState.value
|
||||||
|
if (state !is SquashCommitsState.Loaded) return
|
||||||
|
_squashState.value = state.copy(message = message)
|
||||||
|
squashMessage = message
|
||||||
|
}
|
||||||
|
|
||||||
|
fun continueSquash() {
|
||||||
|
commits.forEachIndexed { index, commit ->
|
||||||
|
val abbreviate = commit.abbreviate(7)
|
||||||
|
val action = if (index == commits.size - 1) RebaseTodoLine.Action.PICK else RebaseTodoLine.Action.SQUASH
|
||||||
|
rebaseInteractiveViewModel.onCommitActionChanged(abbreviate, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
rebaseInteractiveViewModel.continueRebaseInteractive()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDefaultSquashMessageFromCommits(messages: List<String>): String = buildString {
|
||||||
|
messages.forEachIndexed { index, value ->
|
||||||
|
append(value)
|
||||||
|
if (messages.size != index + 1) {
|
||||||
|
append("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed interface SquashCommitsState {
|
||||||
|
object Loading : SquashCommitsState
|
||||||
|
data class Loaded(val message: String) : SquashCommitsState
|
||||||
|
data class Failed(val error: String) : SquashCommitsState
|
||||||
|
}
|
@ -47,6 +47,7 @@ class TabViewModel @Inject constructor(
|
|||||||
private val openRepositoryUseCase: OpenRepositoryUseCase,
|
private val openRepositoryUseCase: OpenRepositoryUseCase,
|
||||||
private val diffViewModelProvider: Provider<DiffViewModel>,
|
private val diffViewModelProvider: Provider<DiffViewModel>,
|
||||||
private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>,
|
private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>,
|
||||||
|
private val squashCommitsViewModelProvider: Provider<SquashCommitsViewModel>,
|
||||||
private val historyViewModelProvider: Provider<HistoryViewModel>,
|
private val historyViewModelProvider: Provider<HistoryViewModel>,
|
||||||
private val authorViewModelProvider: Provider<AuthorViewModel>,
|
private val authorViewModelProvider: Provider<AuthorViewModel>,
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
@ -67,6 +68,9 @@ class TabViewModel @Inject constructor(
|
|||||||
var rebaseInteractiveViewModel: RebaseInteractiveViewModel? = null
|
var rebaseInteractiveViewModel: RebaseInteractiveViewModel? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var squashCommitsViewModel: SquashCommitsViewModel? = null
|
||||||
|
private set
|
||||||
|
|
||||||
private val _repositorySelectionStatus = MutableStateFlow<RepositorySelectionStatus>(RepositorySelectionStatus.None)
|
private val _repositorySelectionStatus = MutableStateFlow<RepositorySelectionStatus>(RepositorySelectionStatus.None)
|
||||||
val repositorySelectionStatus: StateFlow<RepositorySelectionStatus>
|
val repositorySelectionStatus: StateFlow<RepositorySelectionStatus>
|
||||||
get() = _repositorySelectionStatus
|
get() = _repositorySelectionStatus
|
||||||
@ -115,7 +119,7 @@ class TabViewModel @Inject constructor(
|
|||||||
when (refreshType) {
|
when (refreshType) {
|
||||||
RefreshType.NONE -> printLog(TAG, "Not refreshing...")
|
RefreshType.NONE -> printLog(TAG, "Not refreshing...")
|
||||||
RefreshType.REPO_STATE -> refreshRepositoryState()
|
RefreshType.REPO_STATE -> refreshRepositoryState()
|
||||||
else -> {}
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,8 +127,8 @@ class TabViewModel @Inject constructor(
|
|||||||
tabState.taskEvent.collect { taskEvent ->
|
tabState.taskEvent.collect { taskEvent ->
|
||||||
when (taskEvent) {
|
when (taskEvent) {
|
||||||
is TaskEvent.RebaseInteractive -> onRebaseInteractive(taskEvent)
|
is TaskEvent.RebaseInteractive -> onRebaseInteractive(taskEvent)
|
||||||
else -> { /*Nothing to do here*/
|
is TaskEvent.SquashCommits -> onSquashCommits(taskEvent)
|
||||||
}
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,6 +153,11 @@ class TabViewModel @Inject constructor(
|
|||||||
rebaseInteractiveViewModel?.startRebaseInteractive(taskEvent.revCommit)
|
rebaseInteractiveViewModel?.startRebaseInteractive(taskEvent.revCommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun onSquashCommits(taskEvent: TaskEvent.SquashCommits) {
|
||||||
|
squashCommitsViewModel = squashCommitsViewModelProvider.get()
|
||||||
|
squashCommitsViewModel?.startSquash(taskEvent.commits, taskEvent.upstreamCommit)
|
||||||
|
}
|
||||||
|
|
||||||
fun openRepository(directory: String) {
|
fun openRepository(directory: String) {
|
||||||
openRepository(File(directory))
|
openRepository(File(directory))
|
||||||
}
|
}
|
||||||
@ -211,10 +220,17 @@ class TabViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onRepositoryStateChanged(newRepoState: RepositoryState) {
|
private fun onRepositoryStateChanged(newRepoState: RepositoryState) {
|
||||||
if (newRepoState != RepositoryState.REBASING_INTERACTIVE && rebaseInteractiveViewModel != null) {
|
if (newRepoState != RepositoryState.REBASING_INTERACTIVE) {
|
||||||
|
if (rebaseInteractiveViewModel != null) {
|
||||||
rebaseInteractiveViewModel?.cancel()
|
rebaseInteractiveViewModel?.cancel()
|
||||||
rebaseInteractiveViewModel = null
|
rebaseInteractiveViewModel = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newRepoState != RepositoryState.SAFE && squashCommitsViewModel != null) {
|
||||||
|
squashCommitsViewModel?.cancel()
|
||||||
|
squashCommitsViewModel = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun watchRepositoryChanges(git: Git) = tabScope.launch(Dispatchers.IO) {
|
private suspend fun watchRepositoryChanges(git: Git) = tabScope.launch(Dispatchers.IO) {
|
||||||
@ -439,7 +455,10 @@ class TabViewModel @Inject constructor(
|
|||||||
refreshType = RefreshType.ALL_DATA,
|
refreshType = RefreshType.ALL_DATA,
|
||||||
) { git ->
|
) { git ->
|
||||||
abortRebaseUseCase(git)
|
abortRebaseUseCase(git)
|
||||||
rebaseInteractiveViewModel = null // shouldn't be necessary but just to make sure
|
|
||||||
|
// shouldn't be necessary but just to make sure
|
||||||
|
rebaseInteractiveViewModel = null
|
||||||
|
squashCommitsViewModel = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ class TabViewModelsHolder @Inject constructor(
|
|||||||
// Dynamic VM
|
// Dynamic VM
|
||||||
private val diffViewModelProvider: Provider<DiffViewModel>,
|
private val diffViewModelProvider: Provider<DiffViewModel>,
|
||||||
private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>,
|
private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>,
|
||||||
|
private val squashCommitsViewModel: Provider<SquashCommitsViewModel>,
|
||||||
private val historyViewModelProvider: Provider<HistoryViewModel>,
|
private val historyViewModelProvider: Provider<HistoryViewModel>,
|
||||||
private val authorViewModelProvider: Provider<AuthorViewModel>,
|
private val authorViewModelProvider: Provider<AuthorViewModel>,
|
||||||
) {
|
) {
|
||||||
|
Loading…
Reference in New Issue
Block a user