Gitnuro/src/main/kotlin/com/jetpackduba/gitnuro/ui/components/TripleVerticalSplitPanel.kt
2024-07-30 22:26:38 +02:00

122 lines
4.0 KiB
Kotlin

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.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.jetpackduba.gitnuro.ui.resizePointerIconEast
const val MAX_SIDE_PANE_PROPORTION = 0.4f
@Composable
fun TripleVerticalSplitPanel(
modifier: Modifier = Modifier,
first: @Composable () -> Unit,
second: @Composable () -> Unit,
third: @Composable () -> Unit,
firstWidth: Float,
thirdWidth: Float,
onFirstSizeDragStarted: (Float) -> Unit,
onFirstSizeChange: (Float) -> Unit,
onFirstSizeDragStopped: () -> Unit,
onThirdSizeDragStarted: (Float) -> Unit,
onThirdSizeChange: (Float) -> Unit,
onThirdSizeDragStopped: () -> Unit,
) {
val density = LocalDensity.current.density
// The panes width used to be calculated in the remember lambda, but as it required the view to compose once to get
// the composable width, it was flickering, so we only update them when size of the parent component changes
var firstWidthLimited by remember(firstWidth) { mutableStateOf(firstWidth)}
var thirdWidthLimited by remember(thirdWidth) { mutableStateOf(thirdWidth) }
fun updateMaxPaneWidthToComponentWidth(screenWidth: Int) {
val screenWidthInDp = screenWidth /density
firstWidthLimited = calcLimitedWidth(screenWidthInDp, firstWidth)
thirdWidthLimited = calcLimitedWidth(screenWidthInDp, thirdWidth)
}
Row(
modifier = modifier
.onSizeChanged {
updateMaxPaneWidthToComponentWidth(it.width)
}
) {
if (firstWidth > 0) {
Box(
modifier = Modifier
.width(firstWidth.dp)
) {
first()
}
Box(
modifier = Modifier
.fillMaxHeight()
.width(8.dp)
.draggable(
state = rememberDraggableState {
onFirstSizeChange(it)
},
orientation = Orientation.Horizontal,
onDragStarted = {
onFirstSizeDragStarted(firstWidthLimited)
},
onDragStopped = {
onFirstSizeDragStopped()
},
)
.pointerHoverIcon(resizePointerIconEast)
)
}
Box(
Modifier
.weight(1f, true)
) {
second()
}
Box(
modifier = Modifier
.fillMaxHeight()
.width(8.dp)
.draggable(
state = rememberDraggableState {
onThirdSizeChange(it)
},
orientation = Orientation.Horizontal,
onDragStarted = {
onThirdSizeDragStarted(thirdWidthLimited)
},
onDragStopped = {
onThirdSizeDragStopped()
},
)
.pointerHoverIcon(resizePointerIconEast)
)
Box(
modifier = Modifier
.width(thirdWidth.dp)
) {
third()
}
}
}
private fun calcLimitedWidth(maxSize: Float, currentSize: Float): Float {
return if (currentSize > maxSize * MAX_SIDE_PANE_PROPORTION) {
maxSize * MAX_SIDE_PANE_PROPORTION
} else {
currentSize
}
}