Replaced nested SplitPane with a custom TripleVerticalSplit

This commit is contained in:
Abdelilah El Aissaoui 2024-01-09 21:18:32 +01:00
parent de64d43c15
commit d06e746c6c
No known key found for this signature in database
GPG Key ID: 7587FC860F594869
2 changed files with 191 additions and 145 deletions

View File

@ -12,9 +12,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.AppConstants import com.jetpackduba.gitnuro.AppConstants
import com.jetpackduba.gitnuro.LocalTabScope import com.jetpackduba.gitnuro.LocalTabScope
@ -24,6 +22,7 @@ import com.jetpackduba.gitnuro.git.rebase.RebaseInteractiveState
import com.jetpackduba.gitnuro.keybindings.KeybindingOption import com.jetpackduba.gitnuro.keybindings.KeybindingOption
import com.jetpackduba.gitnuro.keybindings.matchesBinding import com.jetpackduba.gitnuro.keybindings.matchesBinding
import com.jetpackduba.gitnuro.ui.components.SecondaryButton import com.jetpackduba.gitnuro.ui.components.SecondaryButton
import com.jetpackduba.gitnuro.ui.components.TripleVerticalSplit
import com.jetpackduba.gitnuro.ui.components.gitnuroDynamicViewModel import com.jetpackduba.gitnuro.ui.components.gitnuroDynamicViewModel
import com.jetpackduba.gitnuro.ui.dialogs.* import com.jetpackduba.gitnuro.ui.dialogs.*
import com.jetpackduba.gitnuro.ui.diff.Diff import com.jetpackduba.gitnuro.ui.diff.Diff
@ -33,9 +32,6 @@ import com.jetpackduba.gitnuro.viewmodels.TabViewModel
import org.eclipse.jgit.lib.RepositoryState import org.eclipse.jgit.lib.RepositoryState
import org.eclipse.jgit.revwalk.RevCommit import org.eclipse.jgit.revwalk.RevCommit
import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi
import org.jetbrains.compose.splitpane.HorizontalSplitPane
import org.jetbrains.compose.splitpane.SplitterScope
import org.jetbrains.compose.splitpane.rememberSplitPaneState
@Composable @Composable
fun RepositoryOpenPage( fun RepositoryOpenPage(
@ -244,7 +240,6 @@ fun RepoContent(
} }
} }
@OptIn(ExperimentalSplitPaneApi::class)
@Composable @Composable
fun MainContentView( fun MainContentView(
tabViewModel: TabViewModel, tabViewModel: TabViewModel,
@ -255,158 +250,125 @@ fun MainContentView(
) { ) {
val rebaseInteractiveState by tabViewModel.rebaseInteractiveState.collectAsState() val rebaseInteractiveState by tabViewModel.rebaseInteractiveState.collectAsState()
HorizontalSplitPane( TripleVerticalSplit(
splitPaneState = rememberSplitPaneState(initialPositionPercentage = 0.20f) modifier = Modifier.fillMaxSize(),
) { initialFirstWidth = 220f,
val size = if (rebaseInteractiveState == RebaseInteractiveState.AwaitingInteraction) minFirstWidth = 150f,
1.dp initialThirdWidth = 360f,
else minThirdWidth = 180f,
180.dp first = {
first(minSize = size) {
SidePanel() SidePanel()
} },
second = {
splitter { Box(
this.repositorySplitter() modifier = Modifier
} .fillMaxSize()
second {
HorizontalSplitPane(
splitPaneState = rememberSplitPaneState(0.9f)
) { ) {
first { if (rebaseInteractiveState == RebaseInteractiveState.AwaitingInteraction && diffSelected == null) {
Box( RebaseInteractive()
modifier = Modifier } else if (blameState is BlameState.Loaded && !blameState.isMinimized) {
.fillMaxSize() Blame(
) { filePath = blameState.filePath,
if (rebaseInteractiveState == RebaseInteractiveState.AwaitingInteraction && diffSelected == null) { blameResult = blameState.blameResult,
RebaseInteractive() onClose = { tabViewModel.resetBlameState() },
} else if (blameState is BlameState.Loaded && !blameState.isMinimized) { onSelectCommit = { tabViewModel.selectCommit(it) }
Blame( )
filePath = blameState.filePath, } else {
blameResult = blameState.blameResult, Column {
onClose = { tabViewModel.resetBlameState() }, Box(modifier = Modifier.weight(1f, true)) {
onSelectCommit = { tabViewModel.selectCommit(it) } when (diffSelected) {
) null -> {
} else { Log(
Column { selectedItem = selectedItem,
Box(modifier = Modifier.weight(1f, true)) { repositoryState = repositoryState,
when (diffSelected) { )
null -> {
Log(
selectedItem = selectedItem,
repositoryState = repositoryState,
)
}
else -> {
val diffViewModel = tabViewModel.diffViewModel
if (diffViewModel != null) {
Diff(
diffViewModel = diffViewModel,
onCloseDiffView = {
tabViewModel.newDiffSelected = null
}
)
}
}
}
} }
if (blameState is BlameState.Loaded) { // BlameState.isMinimized is true here else -> {
MinimizedBlame( val diffViewModel = tabViewModel.diffViewModel
filePath = blameState.filePath,
onExpand = { tabViewModel.expandBlame() }, if (diffViewModel != null) {
onClose = { tabViewModel.resetBlameState() } Diff(
) diffViewModel = diffViewModel,
onCloseDiffView = {
tabViewModel.newDiffSelected = null
}
)
}
} }
} }
} }
}
}
splitter { if (blameState is BlameState.Loaded) { // BlameState.isMinimized is true here
this.repositorySplitter() MinimizedBlame(
} filePath = blameState.filePath,
onExpand = { tabViewModel.expandBlame() },
second(minSize = 250.dp) { onClose = { tabViewModel.resetBlameState() }
Box( )
modifier = Modifier
.fillMaxHeight()
) {
when (selectedItem) {
SelectedItem.UncommittedChanges -> {
UncommittedChanges(
selectedEntryType = diffSelected,
repositoryState = repositoryState,
onStagedDiffEntrySelected = { diffEntry ->
tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = if (diffEntry != null) {
if (repositoryState == RepositoryState.SAFE)
DiffEntryType.SafeStagedDiff(diffEntry)
else
DiffEntryType.UnsafeStagedDiff(diffEntry)
} else {
null
}
},
onUnstagedDiffEntrySelected = { diffEntry ->
tabViewModel.minimizeBlame()
if (repositoryState == RepositoryState.SAFE)
tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry)
else
tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
},
onBlameFile = { tabViewModel.blameFile(it) },
onHistoryFile = { tabViewModel.fileHistory(it) }
)
}
is SelectedItem.CommitBasedItem -> {
CommitChanges(
selectedItem = selectedItem,
diffSelected = diffSelected,
onDiffSelected = { diffEntry ->
tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry)
},
onBlame = { tabViewModel.blameFile(it) },
onHistory = { tabViewModel.fileHistory(it) },
)
}
SelectedItem.None -> {}
} }
} }
} }
} }
} },
} third = {
} Box(
modifier = Modifier
.fillMaxHeight()
) {
when (selectedItem) {
SelectedItem.UncommittedChanges -> {
UncommittedChanges(
selectedEntryType = diffSelected,
repositoryState = repositoryState,
onStagedDiffEntrySelected = { diffEntry ->
tabViewModel.minimizeBlame()
fun SplitterScope.repositorySplitter() { tabViewModel.newDiffSelected = if (diffEntry != null) {
visiblePart { if (repositoryState == RepositoryState.SAFE)
Box( DiffEntryType.SafeStagedDiff(diffEntry)
Modifier else
.width(8.dp) DiffEntryType.UnsafeStagedDiff(diffEntry)
.fillMaxHeight() } else {
.background(Color.Transparent) null
) }
} },
handle { onUnstagedDiffEntrySelected = { diffEntry ->
Box( tabViewModel.minimizeBlame()
Modifier
.markAsHandle() if (repositoryState == RepositoryState.SAFE)
.pointerHoverIcon(resizePointerIconEast) tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry)
.background(Color.Transparent) else
.width(8.dp) tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
.fillMaxHeight() },
) onBlameFile = { tabViewModel.blameFile(it) },
} onHistoryFile = { tabViewModel.fileHistory(it) }
)
}
is SelectedItem.CommitBasedItem -> {
CommitChanges(
selectedItem = selectedItem,
diffSelected = diffSelected,
onDiffSelected = { diffEntry ->
tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry)
},
onBlame = { tabViewModel.blameFile(it) },
onHistory = { tabViewModel.fileHistory(it) },
)
}
SelectedItem.None -> {}
}
}
},
onFirstSizeChanged = {
},
onThirdSizeChanged = {
},
)
} }
sealed interface SelectedItem { sealed interface SelectedItem {

View File

@ -0,0 +1,84 @@
package com.jetpackduba.gitnuro.ui.components
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.ui.resizePointerIconEast
@Composable
fun TripleVerticalSplit(
modifier: Modifier = Modifier,
first: @Composable () -> Unit,
second: @Composable () -> Unit,
third: @Composable () -> Unit,
initialFirstWidth: Float,
minFirstWidth: Float,
initialThirdWidth: Float,
minThirdWidth: Float,
onFirstSizeChanged: (Float) -> Unit,
onThirdSizeChanged: (Float) -> Unit,
) {
val density = LocalDensity.current.density
var firstWidth by remember { mutableStateOf(initialFirstWidth) }
var thirdWidth by remember { mutableStateOf(initialThirdWidth) }
Row(
modifier = modifier
) {
Box(modifier = Modifier.width((firstWidth).dp)) {
first()
}
Box(
modifier = Modifier
.fillMaxHeight()
.width(8.dp)
.draggable(
state = rememberDraggableState {
val newWidth = firstWidth + it / density
if (newWidth > minFirstWidth) {
firstWidth = newWidth
onFirstSizeChanged(firstWidth)
}
},
orientation = Orientation.Horizontal
)
.pointerHoverIcon(resizePointerIconEast)
)
Box(Modifier.weight(1f, true)) {
second()
}
Box(
modifier = Modifier
.fillMaxHeight()
.width(8.dp)
.draggable(
rememberDraggableState {
val newWidth = thirdWidth - it / density
if(newWidth > minThirdWidth) {
thirdWidth = newWidth
onThirdSizeChanged(thirdWidth)
}
}, Orientation.Horizontal
)
.pointerHoverIcon(resizePointerIconEast)
)
Box(modifier = Modifier.width(thirdWidth.dp)) {
third()
}
}
}