Log full cleanup

- Refactored log function into multiple sub functions
- Removed use of DialogManager from Log
- Merge branch now shows current branch instead of hardcoded "HEAD"
This commit is contained in:
Abdelilah El Aissaoui 2021-12-04 07:02:40 +01:00
parent f9a2917bbd
commit 6c1dc32928
8 changed files with 374 additions and 316 deletions

View File

@ -20,6 +20,15 @@ class BranchesManager @Inject constructor() {
val currentBranch: StateFlow<String> val currentBranch: StateFlow<String>
get() = _currentBranch get() = _currentBranch
suspend fun currentBranchRef(git: Git): Ref? {
val branchList = getBranches(git)
val branchName = git
.repository
.fullBranch
return branchList.firstOrNull { it.name == branchName }
}
suspend fun loadBranches(git: Git) = withContext(Dispatchers.IO) { suspend fun loadBranches(git: Git) = withContext(Dispatchers.IO) {
val branchList = getBranches(git) val branchList = getBranches(git)
@ -58,7 +67,7 @@ class BranchesManager @Inject constructor() {
} }
suspend fun mergeBranch(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) { suspend fun mergeBranch(git: Git, branch: Ref, fastForward: Boolean) = withContext(Dispatchers.IO) {
val fastForwardMode = if(fastForward) val fastForwardMode = if (fastForward)
MergeCommand.FastForwardMode.FF MergeCommand.FastForwardMode.FF
else else
MergeCommand.FastForwardMode.NO_FF MergeCommand.FastForwardMode.NO_FF

View File

@ -21,6 +21,7 @@ import javax.inject.Inject
class LogManager @Inject constructor( class LogManager @Inject constructor(
private val statusManager: StatusManager, private val statusManager: StatusManager,
private val branchesManager: BranchesManager,
) { ) {
private val _logStatus = MutableStateFlow<LogStatus>(LogStatus.Loading) private val _logStatus = MutableStateFlow<LogStatus>(LogStatus.Loading)
@ -49,7 +50,7 @@ class LogManager @Inject constructor(
ensureActive() ensureActive()
val loadedStatus = LogStatus.Loaded(commitList) val loadedStatus = LogStatus.Loaded(commitList, branchesManager.currentBranchRef(git))
_logStatus.value = loadedStatus _logStatus.value = loadedStatus
} }
@ -102,5 +103,5 @@ enum class ResetType {
sealed class LogStatus { sealed class LogStatus {
object Loading : LogStatus() object Loading : LogStatus()
class Loaded(val plotCommitList: GraphCommitList) : LogStatus() class Loaded(val plotCommitList: GraphCommitList, val currentBranch: Ref?) : LogStatus()
} }

View File

@ -4,22 +4,18 @@ import androidx.compose.animation.Crossfade
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.input.pointer.PointerIcon import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.PointerIconDefaults
import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import app.DialogManager import app.DialogManager
import app.credentials.CredentialsState
import app.git.DiffEntryType import app.git.DiffEntryType
import app.git.GitManager import app.git.GitManager
import app.ui.dialogs.NewBranchDialog import app.ui.dialogs.NewBranchDialog
import app.ui.dialogs.PasswordDialog import app.ui.log.Log
import app.ui.dialogs.UserPasswordDialog
import openRepositoryDialog import openRepositoryDialog
import org.eclipse.jgit.revwalk.RevCommit import org.eclipse.jgit.revwalk.RevCommit
import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi

View File

@ -27,6 +27,7 @@ fun MergeDialog(
) { ) {
var fastForwardCheck by remember { mutableStateOf(fastForward) } var fastForwardCheck by remember { mutableStateOf(fastForward) }
MaterialDialog {
Column( Column(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colors.background), .background(MaterialTheme.colors.background),
@ -59,7 +60,7 @@ fun MergeDialog(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.mouseClickable { .mouseClickable {
if(this.buttons.isPrimaryPressed) { if (this.buttons.isPrimaryPressed) {
fastForwardCheck = !fastForwardCheck fastForwardCheck = !fastForwardCheck
} }
} }
@ -100,4 +101,5 @@ fun MergeDialog(
} }
} }
} }
}
} }

View File

@ -26,6 +26,7 @@ fun NewTagDialog(
val tagFieldFocusRequester = remember { FocusRequester() } val tagFieldFocusRequester = remember { FocusRequester() }
val buttonFieldFocusRequester = remember { FocusRequester() } val buttonFieldFocusRequester = remember { FocusRequester() }
MaterialDialog {
Column( Column(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colors.background), .background(MaterialTheme.colors.background),
@ -39,7 +40,7 @@ fun NewTagDialog(
} }
.width(300.dp) .width(300.dp)
.onPreviewKeyEvent { .onPreviewKeyEvent {
if(it.key == Key.Enter) { if (it.key == Key.Enter) {
onAccept(tagField) onAccept(tagField)
true true
} else { } else {
@ -85,4 +86,5 @@ fun NewTagDialog(
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
tagFieldFocusRequester.requestFocus() tagFieldFocusRequester.requestFocus()
} }
}
} }

View File

@ -24,6 +24,7 @@ fun ResetBranchDialog(
) { ) {
var resetType by remember { mutableStateOf(ResetType.MIXED) } var resetType by remember { mutableStateOf(ResetType.MIXED) }
MaterialDialog {
Column( Column(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colors.background), .background(MaterialTheme.colors.background),
@ -72,6 +73,7 @@ fun ResetBranchDialog(
} }
} }
} }
}
} }
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)

View File

@ -2,7 +2,7 @@
@file:Suppress("UNUSED_PARAMETER") @file:Suppress("UNUSED_PARAMETER")
package app.ui package app.ui.log
import androidx.compose.foundation.* import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.Orientation
@ -32,7 +32,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import app.DialogManager
import app.extensions.* import app.extensions.*
import app.git.GitManager import app.git.GitManager
import app.git.LogStatus import app.git.LogStatus
@ -46,6 +45,7 @@ import app.ui.dialogs.MergeDialog
import app.ui.dialogs.NewBranchDialog import app.ui.dialogs.NewBranchDialog
import app.ui.dialogs.NewTagDialog import app.ui.dialogs.NewTagDialog
import app.ui.dialogs.ResetBranchDialog import app.ui.dialogs.ResetBranchDialog
import app.ui.rememberNetworkImage
import org.eclipse.jgit.lib.Ref import org.eclipse.jgit.lib.Ref
import org.eclipse.jgit.revwalk.RevCommit import org.eclipse.jgit.revwalk.RevCommit
@ -69,7 +69,6 @@ private const val CANVAS_MIN_WIDTH = 100
@Composable @Composable
fun Log( fun Log(
gitManager: GitManager, gitManager: GitManager,
dialogManager: DialogManager,
onRevCommitSelected: (RevCommit) -> Unit, onRevCommitSelected: (RevCommit) -> Unit,
onUncommitedChangesSelected: () -> Unit, onUncommitedChangesSelected: () -> Unit,
selectedIndex: MutableState<Int> = remember { mutableStateOf(-1) } selectedIndex: MutableState<Int> = remember { mutableStateOf(-1) }
@ -78,11 +77,20 @@ fun Log(
val logStatus = logStatusState.value val logStatus = logStatusState.value
val selectedUncommited = remember { mutableStateOf(false) } val selectedUncommited = remember { mutableStateOf(false) }
val showLogDialog = remember { mutableStateOf<LogDialog>(LogDialog.None) }
if (logStatus is LogStatus.Loaded) { if (logStatus is LogStatus.Loaded) {
val commitList = logStatus.plotCommitList val commitList = logStatus.plotCommitList
Box( LogDialogs(
gitManager,
currentBranch = logStatus.currentBranch,
onResetShowLogDialog = { showLogDialog.value = LogDialog.None },
showLogDialog = showLogDialog.value,
)
Column(
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(8.dp)
.background(MaterialTheme.colors.background) .background(MaterialTheme.colors.background)
@ -95,13 +103,108 @@ fun Log(
if (graphWidth.value < CANVAS_MIN_WIDTH) if (graphWidth.value < CANVAS_MIN_WIDTH)
graphWidth = CANVAS_MIN_WIDTH.dp graphWidth = CANVAS_MIN_WIDTH.dp
GraphHeader(
graphWidth = graphWidth,
weightMod = weightMod,
)
ScrollableLazyColumn( ScrollableLazyColumn(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colors.background) .background(MaterialTheme.colors.background)
.fillMaxSize(), .fillMaxSize(),
) { ) {
if (hasUncommitedChanges)
item {
UncommitedChangesLine(
selected = selectedUncommited.value,
hasPreviousCommits = commitList.count() > 0,
graphWidth = graphWidth,
weightMod = weightMod,
onUncommitedChangesSelected = {
selectedIndex.value = -1
selectedUncommited.value = true
onUncommitedChangesSelected()
}
)
}
stickyHeader { itemsIndexed(items = commitList) { index, graphNode ->
CommitLine(
gitManager = gitManager,
graphNode = graphNode,
selected = selectedIndex.value == index,
weightMod = weightMod,
graphWidth = graphWidth,
showCreateNewBranch = { showLogDialog.value = LogDialog.NewBranch(graphNode) },
showCreateNewTag = { showLogDialog.value = LogDialog.NewTag(graphNode) },
resetBranch = { showLogDialog.value = LogDialog.ResetBranch(graphNode) },
onMergeBranch = { ref -> showLogDialog.value = LogDialog.MergeBranch(ref) },
onRevCommitSelected = {
selectedIndex.value = index
selectedUncommited.value = false
onRevCommitSelected(it)
}
)
}
}
}
}
}
@Composable
fun LogDialogs(
gitManager: GitManager,
onResetShowLogDialog: () -> Unit,
showLogDialog: LogDialog,
currentBranch: Ref?,
) {
when(showLogDialog) {
is LogDialog.NewBranch -> {
NewBranchDialog(
onReject = onResetShowLogDialog,
onAccept = { branchName ->
gitManager.createBranchOnCommit(branchName, showLogDialog.graphNode)
onResetShowLogDialog()
}
)
}
is LogDialog.NewTag -> {
NewTagDialog(
onReject = onResetShowLogDialog,
onAccept = { tagName ->
gitManager.createTagOnCommit(tagName, showLogDialog.graphNode)
onResetShowLogDialog()
}
)
}
is LogDialog.MergeBranch -> {
if(currentBranch != null)
MergeDialog(
currentBranchName = currentBranch.simpleName,
mergeBranchName = showLogDialog.ref.simpleName,
onReject = onResetShowLogDialog,
onAccept = { ff ->
gitManager.mergeBranch(showLogDialog.ref, ff)
onResetShowLogDialog()
}
)
}
is LogDialog.ResetBranch -> ResetBranchDialog(
onReject = onResetShowLogDialog,
onAccept = { resetType ->
gitManager.resetToCommit(showLogDialog.graphNode, resetType)
onResetShowLogDialog()
}
)
LogDialog.None -> {}
}
}
@Composable
fun GraphHeader(
graphWidth: Dp,
weightMod: MutableState<Float>,
) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -137,11 +240,17 @@ fun Log(
maxLines = 1, maxLines = 1,
) )
} }
} }
if (hasUncommitedChanges) @Composable
item { fun UncommitedChangesLine(
val textColor = if (selectedUncommited.value) { selected: Boolean,
hasPreviousCommits: Boolean,
graphWidth: Dp,
weightMod: MutableState<Float>,
onUncommitedChangesSelected: () -> Unit
) {
val textColor = if (selected) {
MaterialTheme.colors.primary MaterialTheme.colors.primary
} else } else
MaterialTheme.colors.primaryTextColor MaterialTheme.colors.primaryTextColor
@ -151,13 +260,9 @@ fun Log(
.height(40.dp) .height(40.dp)
.fillMaxWidth() .fillMaxWidth()
.clickable { .clickable {
selectedIndex.value = -1
selectedUncommited.value = true
onUncommitedChangesSelected() onUncommitedChangesSelected()
}, },
) { ) {
val hasPreviousCommits = commitList.count() > 0
UncommitedChangesGraphLine( UncommitedChangesGraphLine(
modifier = Modifier modifier = Modifier
.width(graphWidth), .width(graphWidth),
@ -191,51 +296,22 @@ fun Log(
Spacer(modifier = Modifier.weight(2f)) Spacer(modifier = Modifier.weight(2f))
} }
} }
}
itemsIndexed(items = commitList) { index, graphNode ->
CommitLine(
gitManager = gitManager,
dialogManager = dialogManager,
graphNode = graphNode,
selected = selectedIndex.value == index,
weightMod = weightMod,
graphWidth = graphWidth,
onRevCommitSelected = {
selectedIndex.value = index
selectedUncommited.value = false
onRevCommitSelected(it)
}
)
}
}
}
}
} }
@Composable @Composable
fun CommitLine( fun CommitLine(
gitManager: GitManager, gitManager: GitManager,
dialogManager: DialogManager,
graphNode: GraphNode, graphNode: GraphNode,
selected: Boolean, selected: Boolean,
weightMod: MutableState<Float>, weightMod: MutableState<Float>,
graphWidth: Dp, graphWidth: Dp,
showCreateNewBranch: () -> Unit,
showCreateNewTag: () -> Unit,
resetBranch: (GraphNode) -> Unit,
onMergeBranch: (Ref) -> Unit,
onRevCommitSelected: (GraphNode) -> Unit, onRevCommitSelected: (GraphNode) -> Unit,
) { ) {
val commitRefs = graphNode.refs val commitRefs = graphNode.refs
var showCreateBranchDialog by remember(graphNode.id.name) { mutableStateOf(false) }
if(showCreateBranchDialog)
NewBranchDialog(
onReject = {
showCreateBranchDialog = false
},
onAccept = { branchName ->
gitManager.createBranchOnCommit(branchName, graphNode)
showCreateBranchDialog = false
}
)
Box(modifier = Modifier Box(modifier = Modifier
.clickable { .clickable {
@ -252,48 +328,20 @@ fun CommitLine(
}), }),
ContextMenuItem( ContextMenuItem(
label = "Create branch", label = "Create branch",
onClick = { onClick = showCreateNewBranch
showCreateBranchDialog = true
}
), ),
ContextMenuItem( ContextMenuItem(
label = "Create tag", label = "Create tag",
onClick = { onClick = showCreateNewTag
dialogManager.show {
NewTagDialog(
onReject = {
dialogManager.dismiss()
},
onAccept = { tagName ->
gitManager.createTagOnCommit(tagName, graphNode)
dialogManager.dismiss()
}
)
}
}
), ),
ContextMenuItem( ContextMenuItem(
label = "Revert commit", label = "Revert commit",
onClick = { onClick = { gitManager.revertCommit(graphNode) }
gitManager.revertCommit(graphNode)
}
), ),
ContextMenuItem( ContextMenuItem(
label = "Reset current branch to this commit", label = "Reset current branch to this commit",
onClick = { onClick = { resetBranch(graphNode) }
dialogManager.show {
ResetBranchDialog(
onReject = {
dialogManager.dismiss()
},
onAccept = { resetType ->
dialogManager.dismiss()
gitManager.resetToCommit(graphNode, resetType)
}
)
}
}
) )
) )
}, },
@ -326,21 +374,7 @@ fun CommitLine(
selected = selected, selected = selected,
refs = commitRefs, refs = commitRefs,
onCheckoutRef = { ref -> gitManager.checkoutRef(ref) }, onCheckoutRef = { ref -> gitManager.checkoutRef(ref) },
onMergeBranch = { ref -> onMergeBranch = { ref -> onMergeBranch(ref) },
dialogManager.show {
MergeDialog(
currentBranchName = "HEAD",
mergeBranchName = ref.simpleName,
onReject = {
dialogManager.dismiss()
},
onAccept = { fastForward ->
dialogManager.dismiss()
gitManager.mergeBranch(ref, fastForward)
}
)
}
},
onDeleteBranch = { ref -> gitManager.deleteBranch(ref) } onDeleteBranch = { ref -> gitManager.deleteBranch(ref) }
) )
} }

View File

@ -0,0 +1,12 @@
package app.ui.log
import app.git.graph.GraphNode
import org.eclipse.jgit.lib.Ref
sealed class LogDialog {
object None: LogDialog()
data class NewBranch(val graphNode: GraphNode): LogDialog()
data class NewTag(val graphNode: GraphNode): LogDialog()
data class ResetBranch(val graphNode: GraphNode): LogDialog()
data class MergeBranch(val ref: Ref): LogDialog()
}