diff --git a/src/main/kotlin/app/ui/Blame.kt b/src/main/kotlin/app/ui/Blame.kt index 3ae4fe7..f8f4e47 100644 --- a/src/main/kotlin/app/ui/Blame.kt +++ b/src/main/kotlin/app/ui/Blame.kt @@ -1,10 +1,10 @@ -@file:Suppress("UNUSED_PARAMETER") - package app.ui import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* +import androidx.compose.material.Button import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -18,13 +18,16 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import app.extensions.lineAt import app.theme.primaryTextColor +import app.ui.components.PrimaryButton import app.ui.components.ScrollableLazyColumn import org.eclipse.jgit.blame.BlameResult +import org.eclipse.jgit.revwalk.RevCommit @Composable fun Blame( filePath: String, blameResult: BlameResult, + onSelectCommit: (RevCommit) -> Unit, onClose: () -> Unit, ) { Column { @@ -45,7 +48,11 @@ fun Blame( verticalAlignment = Alignment.CenterVertically, ) { Column( - modifier = Modifier.width(200.dp).fillMaxHeight().background(MaterialTheme.colors.surface), + modifier = Modifier + .width(200.dp) + .fillMaxHeight() + .background(MaterialTheme.colors.surface) + .clickable { onSelectCommit(commit) }, verticalArrangement = Arrangement.Center, ) { Text( @@ -77,13 +84,68 @@ fun Blame( } } +@Composable +fun MinimizedBlame( + filePath: String, + onExpand: () -> Unit, + onClose: () -> Unit, +) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(50.dp) + .background(MaterialTheme.colors.surface), + verticalAlignment = Alignment.CenterVertically, + ) { + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + ) { + Text( + text = "Minimized file blame", + color = MaterialTheme.colors.primaryTextColor, + maxLines = 1, + fontSize = 10.sp, + ) + Text( + text = filePath, + color = MaterialTheme.colors.primaryTextColor, + maxLines = 1, + fontSize = 12.sp, + ) + } + + Spacer(modifier = Modifier.weight(1f)) + + PrimaryButton( + onClick = onExpand, + text = "Show", + ) + + IconButton( + onClick = onClose, + modifier = Modifier.padding(horizontal = 16.dp) + ) { + Image( + painter = painterResource("close.svg"), + contentDescription = "Close blame", + colorFilter = ColorFilter.tint(MaterialTheme.colors.primaryTextColor), + ) + } + } +} + @Composable private fun Header( filePath: String, onClose: () -> Unit, ) { Row( - modifier = Modifier.fillMaxWidth().background(MaterialTheme.colors.surface), + modifier = Modifier + .fillMaxWidth() + .height(50.dp) + .padding(start = 8.dp, end = 8.dp, top = 8.dp) + .background(MaterialTheme.colors.surface), verticalAlignment = Alignment.CenterVertically, ) { Text( @@ -94,12 +156,13 @@ private fun Header( ) Spacer(modifier = Modifier.weight(1f)) + IconButton( onClick = onClose ) { Image( painter = painterResource("close.svg"), - contentDescription = "Close diff", + contentDescription = "Close blame", colorFilter = ColorFilter.tint(MaterialTheme.colors.primaryTextColor), ) } diff --git a/src/main/kotlin/app/ui/Diff.kt b/src/main/kotlin/app/ui/Diff.kt index 3139e6d..5397bef 100644 --- a/src/main/kotlin/app/ui/Diff.kt +++ b/src/main/kotlin/app/ui/Diff.kt @@ -54,7 +54,6 @@ fun Diff( Column( modifier = Modifier - .padding(8.dp) .background(MaterialTheme.colors.background) .fillMaxSize() ) { @@ -228,7 +227,7 @@ fun HunkHeader( Row( modifier = Modifier .background(MaterialTheme.colors.surface) - .padding(vertical = 4.dp) + .padding(horizontal = 8.dp, vertical = 4.dp) .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { @@ -282,6 +281,8 @@ fun DiffHeader( Row( modifier = Modifier .fillMaxWidth() + .height(50.dp) + .padding(start = 8.dp, end = 8.dp, top = 8.dp) .background(MaterialTheme.colors.surface), verticalAlignment = Alignment.CenterVertically, ) { @@ -351,6 +352,7 @@ fun DiffLine(highestLineNumberLength: Int, line: Line) { } Row( modifier = Modifier + .padding(horizontal = 8.dp) .background(backgroundColor) .height(IntrinsicSize.Min) ) { diff --git a/src/main/kotlin/app/ui/RepositoryOpen.kt b/src/main/kotlin/app/ui/RepositoryOpen.kt index 14e6bbc..8d348c0 100644 --- a/src/main/kotlin/app/ui/RepositoryOpen.kt +++ b/src/main/kotlin/app/ui/RepositoryOpen.kt @@ -118,25 +118,38 @@ fun RepoContent( shape = RoundedCornerShape(4.dp) ) ) { - if (blameState is BlameState.Loaded) { + if (blameState is BlameState.Loaded && !blameState.isMinimized) { Blame( filePath = blameState.filePath, blameResult = blameState.blameResult, - onClose = { tabViewModel.resetBlameState() } + onClose = { tabViewModel.resetBlameState() }, + onSelectCommit = { tabViewModel.selectCommit(it) } ) } else { - when (diffSelected) { - null -> { - Log( - logViewModel = tabViewModel.logViewModel, - selectedItem = selectedItem, - repositoryState = repositoryState, - ) + Column { + Box(modifier = Modifier.weight(1f, true)) { + when (diffSelected) { + null -> { + Log( + logViewModel = tabViewModel.logViewModel, + selectedItem = selectedItem, + repositoryState = repositoryState, + ) + } + else -> { + Diff( + diffViewModel = tabViewModel.diffViewModel, + onCloseDiffView = { tabViewModel.newDiffSelected = null }) + } + } } - else -> { - Diff( - diffViewModel = tabViewModel.diffViewModel, - onCloseDiffView = { tabViewModel.newDiffSelected = null }) + + if (blameState is BlameState.Loaded) { // BlameState.isMinimized is true here + MinimizedBlame( + filePath = blameState.filePath, + onExpand = { tabViewModel.expandBlame() }, + onClose = { tabViewModel.resetBlameState() } + ) } } } @@ -155,10 +168,7 @@ fun RepoContent( selectedEntryType = diffSelected, repositoryState = repositoryState, onStagedDiffEntrySelected = { diffEntry -> - // TODO: Instead of resetting the state, create a new one where the blame - // is "on hold". In this state we can show a bar at the bottom so the user - // can click on it and return to the blame - tabViewModel.resetBlameState() + tabViewModel.minimizeBlame() tabViewModel.newDiffSelected = if (diffEntry != null) { if (repositoryState == RepositoryState.SAFE) @@ -170,7 +180,7 @@ fun RepoContent( } }, onUnstagedDiffEntrySelected = { diffEntry -> - tabViewModel.resetBlameState() + tabViewModel.minimizeBlame() if (repositoryState == RepositoryState.SAFE) tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry) @@ -185,7 +195,7 @@ fun RepoContent( selectedItem = safeSelectedItem, diffSelected = diffSelected, onDiffSelected = { diffEntry -> - tabViewModel.resetBlameState() + tabViewModel.minimizeBlame() tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry) }, onBlame = { tabViewModel.blameFile(it) } diff --git a/src/main/kotlin/app/viewmodels/TabViewModel.kt b/src/main/kotlin/app/viewmodels/TabViewModel.kt index 784903a..9f7ab2c 100644 --- a/src/main/kotlin/app/viewmodels/TabViewModel.kt +++ b/src/main/kotlin/app/viewmodels/TabViewModel.kt @@ -17,6 +17,7 @@ import org.eclipse.jgit.api.Git import org.eclipse.jgit.blame.BlameResult import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.lib.RepositoryState +import org.eclipse.jgit.revwalk.RevCommit import java.io.File import javax.inject.Inject import javax.inject.Provider @@ -340,6 +341,26 @@ class TabViewModel @Inject constructor( fun resetBlameState() { _blameState.value = BlameState.None } + + fun expandBlame() { + val blameState = _blameState.value + + if(blameState is BlameState.Loaded && blameState.isMinimized) { + _blameState.value = blameState.copy(isMinimized = false) + } + } + + fun minimizeBlame() { + val blameState = _blameState.value + + if(blameState is BlameState.Loaded && !blameState.isMinimized) { + _blameState.value = blameState.copy(isMinimized = true) + } + } + + fun selectCommit(commit: RevCommit) { + tabState.newSelectedItem(SelectedItem.Commit(commit)) + } } @@ -352,6 +373,8 @@ sealed class RepositorySelectionStatus { sealed interface BlameState { data class Loading(val filePath: String) : BlameState - data class Loaded(val filePath: String, val blameResult: BlameResult) : BlameState + + data class Loaded(val filePath: String, val blameResult: BlameResult, val isMinimized: Boolean = false) : BlameState + object None : BlameState } \ No newline at end of file