Added persistance of commit message
Merge message is also recovered when having conflicts
This commit is contained in:
parent
7335499f97
commit
67aff36bc4
@ -404,7 +404,7 @@ fun DiffLine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = line.text.replace("\t", " "), // this replace is a workaround until this issue gets fixed https://github.com/JetBrains/compose-jb/issues/615
|
text = line.text.replace("\t", " "), // TODO this replace is a workaround until this issue gets fixed https://github.com/JetBrains/compose-jb/issues/615
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 8.dp)
|
.padding(start = 8.dp)
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
|
@ -40,6 +40,7 @@ import app.ui.components.SecondaryButton
|
|||||||
import app.ui.context_menu.*
|
import app.ui.context_menu.*
|
||||||
import app.viewmodels.StageStatus
|
import app.viewmodels.StageStatus
|
||||||
import app.viewmodels.StatusViewModel
|
import app.viewmodels.StatusViewModel
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
import org.eclipse.jgit.lib.RepositoryState
|
import org.eclipse.jgit.lib.RepositoryState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -53,7 +54,7 @@ fun UncommitedChanges(
|
|||||||
onHistoryFile: (String) -> Unit,
|
onHistoryFile: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val stageStatusState = statusViewModel.stageStatus.collectAsState()
|
val stageStatusState = statusViewModel.stageStatus.collectAsState()
|
||||||
var commitMessage by remember { mutableStateOf(statusViewModel.savedCommitMessage) }
|
var commitMessage by remember { mutableStateOf(statusViewModel.savedCommitMessage.message) }
|
||||||
|
|
||||||
val stageStatus = stageStatusState.value
|
val stageStatus = stageStatusState.value
|
||||||
val staged: List<StatusEntry>
|
val staged: List<StatusEntry>
|
||||||
@ -70,13 +71,18 @@ fun UncommitedChanges(
|
|||||||
val doCommit = { amend: Boolean ->
|
val doCommit = { amend: Boolean ->
|
||||||
statusViewModel.commit(commitMessage, amend)
|
statusViewModel.commit(commitMessage, amend)
|
||||||
onStagedDiffEntrySelected(null)
|
onStagedDiffEntrySelected(null)
|
||||||
statusViewModel.savedCommitMessage = ""
|
|
||||||
commitMessage = ""
|
commitMessage = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
val canCommit = commitMessage.isNotEmpty() && staged.isNotEmpty()
|
val canCommit = commitMessage.isNotEmpty() && staged.isNotEmpty()
|
||||||
val canAmend = (commitMessage.isNotEmpty() || staged.isNotEmpty()) && statusViewModel.hasPreviousCommits
|
val canAmend = (commitMessage.isNotEmpty() || staged.isNotEmpty()) && statusViewModel.hasPreviousCommits
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
statusViewModel.commitMessageChangesFlow.collect { newCommitMessage ->
|
||||||
|
commitMessage = newCommitMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = stageStatus is StageStatus.Loading,
|
visible = stageStatus is StageStatus.Loading,
|
||||||
@ -175,7 +181,8 @@ fun UncommitedChanges(
|
|||||||
value = commitMessage,
|
value = commitMessage,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
commitMessage = it
|
commitMessage = it
|
||||||
statusViewModel.savedCommitMessage = it
|
|
||||||
|
statusViewModel.updateCommitMessage(it)
|
||||||
},
|
},
|
||||||
label = { Text("Write your commit message here", fontSize = 14.sp) },
|
label = { Text("Write your commit message here", fontSize = 14.sp) },
|
||||||
colors = textFieldColors(),
|
colors = textFieldColors(),
|
||||||
@ -185,13 +192,19 @@ fun UncommitedChanges(
|
|||||||
when {
|
when {
|
||||||
repositoryState.isMerging -> MergeButtons(
|
repositoryState.isMerging -> MergeButtons(
|
||||||
haveConflictsBeenSolved = unstaged.isEmpty(),
|
haveConflictsBeenSolved = unstaged.isEmpty(),
|
||||||
onAbort = { statusViewModel.abortMerge() },
|
onAbort = {
|
||||||
|
statusViewModel.abortMerge()
|
||||||
|
statusViewModel.updateCommitMessage("")
|
||||||
|
},
|
||||||
onMerge = { doCommit(false) }
|
onMerge = { doCommit(false) }
|
||||||
)
|
)
|
||||||
repositoryState.isRebasing -> RebasingButtons(
|
repositoryState.isRebasing -> RebasingButtons(
|
||||||
canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(),
|
canContinue = staged.isNotEmpty() || unstaged.isNotEmpty(),
|
||||||
haveConflictsBeenSolved = unstaged.isEmpty(),
|
haveConflictsBeenSolved = unstaged.isEmpty(),
|
||||||
onAbort = { statusViewModel.abortRebase() },
|
onAbort = {
|
||||||
|
statusViewModel.abortRebase()
|
||||||
|
statusViewModel.updateCommitMessage("")
|
||||||
|
},
|
||||||
onContinue = { statusViewModel.continueRebase() },
|
onContinue = { statusViewModel.continueRebase() },
|
||||||
onSkip = { statusViewModel.skipRebase() },
|
onSkip = { statusViewModel.skipRebase() },
|
||||||
)
|
)
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
package app.viewmodels
|
package app.viewmodels
|
||||||
|
|
||||||
|
import app.extensions.isMerging
|
||||||
import app.git.*
|
import app.git.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.lib.RepositoryState
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class StatusViewModel @Inject constructor(
|
class StatusViewModel @Inject constructor(
|
||||||
private val tabState: TabState,
|
private val tabState: TabState,
|
||||||
private val statusManager: StatusManager,
|
private val statusManager: StatusManager,
|
||||||
private val branchesManager: BranchesManager,
|
|
||||||
private val repositoryManager: RepositoryManager,
|
|
||||||
private val rebaseManager: RebaseManager,
|
private val rebaseManager: RebaseManager,
|
||||||
private val mergeManager: MergeManager,
|
private val mergeManager: MergeManager,
|
||||||
private val logManager: LogManager,
|
private val logManager: LogManager,
|
||||||
@ -21,11 +23,32 @@ class StatusViewModel @Inject constructor(
|
|||||||
private val _stageStatus = MutableStateFlow<StageStatus>(StageStatus.Loaded(listOf(), listOf()))
|
private val _stageStatus = MutableStateFlow<StageStatus>(StageStatus.Loaded(listOf(), listOf()))
|
||||||
val stageStatus: StateFlow<StageStatus> = _stageStatus
|
val stageStatus: StateFlow<StageStatus> = _stageStatus
|
||||||
|
|
||||||
var savedCommitMessage: String = ""
|
var savedCommitMessage = CommitMessage("", MessageType.NORMAL)
|
||||||
|
|
||||||
var hasPreviousCommits = true // When false, disable "amend previous commit"
|
var hasPreviousCommits = true // When false, disable "amend previous commit"
|
||||||
|
|
||||||
private var lastUncommitedChangesState = false
|
private var lastUncommitedChangesState = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the UI that the commit message has been changed by the view model
|
||||||
|
*/
|
||||||
|
private val _commitMessageChangesFlow = MutableSharedFlow<String>()
|
||||||
|
val commitMessageChangesFlow: SharedFlow<String> = _commitMessageChangesFlow
|
||||||
|
|
||||||
|
private fun persistMessage() = tabState.runOperation(
|
||||||
|
refreshType = RefreshType.NONE,
|
||||||
|
) { git ->
|
||||||
|
val messageToPersist = savedCommitMessage.message.ifBlank { null }
|
||||||
|
|
||||||
|
println("Persisting message: $messageToPersist")
|
||||||
|
|
||||||
|
if (git.repository.repositoryState.isMerging) {
|
||||||
|
git.repository.writeMergeCommitMsg(messageToPersist)
|
||||||
|
} else if (git.repository.repositoryState == RepositoryState.SAFE) {
|
||||||
|
git.repository.writeCommitEditMsg(messageToPersist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun stage(statusEntry: StatusEntry) = tabState.runOperation(
|
fun stage(statusEntry: StatusEntry) = tabState.runOperation(
|
||||||
refreshType = RefreshType.UNCOMMITED_CHANGES,
|
refreshType = RefreshType.UNCOMMITED_CHANGES,
|
||||||
) { git ->
|
) { git ->
|
||||||
@ -66,6 +89,21 @@ class StatusViewModel @Inject constructor(
|
|||||||
private suspend fun loadStatus(git: Git) {
|
private suspend fun loadStatus(git: Git) {
|
||||||
val previousStatus = _stageStatus.value
|
val previousStatus = _stageStatus.value
|
||||||
|
|
||||||
|
val requiredMessageType = if (git.repository.repositoryState == RepositoryState.MERGING) {
|
||||||
|
MessageType.MERGE
|
||||||
|
} else {
|
||||||
|
MessageType.NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requiredMessageType != savedCommitMessage.messageType) {
|
||||||
|
savedCommitMessage = CommitMessage(messageByRepoState(git), requiredMessageType)
|
||||||
|
_commitMessageChangesFlow.emit(savedCommitMessage.message)
|
||||||
|
|
||||||
|
} else if (savedCommitMessage.message.isEmpty()) {
|
||||||
|
savedCommitMessage = savedCommitMessage.copy(message = messageByRepoState(git))
|
||||||
|
_commitMessageChangesFlow.emit(savedCommitMessage.message)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_stageStatus.value = StageStatus.Loading
|
_stageStatus.value = StageStatus.Loading
|
||||||
val status = statusManager.getStatus(git)
|
val status = statusManager.getStatus(git)
|
||||||
@ -79,6 +117,17 @@ class StatusViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun messageByRepoState(git: Git): String {
|
||||||
|
val message: String? = if (git.repository.repositoryState == RepositoryState.MERGING) {
|
||||||
|
git.repository.readMergeCommitMsg()
|
||||||
|
} else {
|
||||||
|
git.repository.readCommitEditMsg()
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO this replace is a workaround until this issue gets fixed https://github.com/JetBrains/compose-jb/issues/615
|
||||||
|
return message.orEmpty().replace("\t", " ")
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun loadHasUncommitedChanges(git: Git) = withContext(Dispatchers.IO) {
|
private suspend fun loadHasUncommitedChanges(git: Git) = withContext(Dispatchers.IO) {
|
||||||
lastUncommitedChangesState = statusManager.hasUncommitedChanges(git)
|
lastUncommitedChangesState = statusManager.hasUncommitedChanges(git)
|
||||||
}
|
}
|
||||||
@ -92,6 +141,7 @@ class StatusViewModel @Inject constructor(
|
|||||||
message
|
message
|
||||||
|
|
||||||
statusManager.commit(git, commitMessage, amend)
|
statusManager.commit(git, commitMessage, amend)
|
||||||
|
updateCommitMessage("")
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun refresh(git: Git) = withContext(Dispatchers.IO) {
|
suspend fun refresh(git: Git) = withContext(Dispatchers.IO) {
|
||||||
@ -148,6 +198,11 @@ class StatusViewModel @Inject constructor(
|
|||||||
|
|
||||||
fileToDelete.delete()
|
fileToDelete.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateCommitMessage(message: String) {
|
||||||
|
savedCommitMessage = savedCommitMessage.copy(message = message)
|
||||||
|
persistMessage()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class StageStatus {
|
sealed class StageStatus {
|
||||||
@ -155,3 +210,9 @@ sealed class StageStatus {
|
|||||||
data class Loaded(val staged: List<StatusEntry>, val unstaged: List<StatusEntry>) : StageStatus()
|
data class Loaded(val staged: List<StatusEntry>, val unstaged: List<StatusEntry>) : StageStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class CommitMessage(val message: String, val messageType: MessageType)
|
||||||
|
|
||||||
|
enum class MessageType {
|
||||||
|
NORMAL,
|
||||||
|
MERGE;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user