Fixed text selection when using split diff

This commit is contained in:
Abdelilah El Aissaoui 2022-08-24 04:43:05 +02:00
parent 81261e42c7
commit cbcb13d730
3 changed files with 90 additions and 14 deletions

View File

@ -34,6 +34,8 @@ import app.theme.secondaryTextColor
import app.ui.components.AvatarImage import app.ui.components.AvatarImage
import app.ui.components.ScrollableLazyColumn import app.ui.components.ScrollableLazyColumn
import app.ui.components.TooltipText import app.ui.components.TooltipText
import app.ui.diff.HunkSplitTextDiff
import app.ui.diff.HunkUnifiedTextDiff
import app.viewmodels.HistoryState import app.viewmodels.HistoryState
import app.viewmodels.HistoryViewModel import app.viewmodels.HistoryViewModel
import app.viewmodels.ViewDiffResult import app.viewmodels.ViewDiffResult

View File

@ -9,7 +9,6 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
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
@ -26,6 +25,7 @@ import app.ui.components.ScrollableColumn
import app.ui.dialogs.AuthorDialog import app.ui.dialogs.AuthorDialog
import app.ui.dialogs.NewBranchDialog import app.ui.dialogs.NewBranchDialog
import app.ui.dialogs.StashWithMessageDialog import app.ui.dialogs.StashWithMessageDialog
import app.ui.diff.Diff
import app.ui.log.Log import app.ui.log.Log
import app.viewmodels.BlameState import app.viewmodels.BlameState
import app.viewmodels.TabViewModel import app.viewmodels.TabViewModel

View File

@ -1,6 +1,6 @@
@file:OptIn(ExperimentalComposeUiApi::class) @file:OptIn(ExperimentalComposeUiApi::class)
package app.ui package app.ui.diff
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
@ -20,7 +20,9 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.PointerIconDefaults import androidx.compose.ui.input.pointer.PointerIconDefaults
import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.res.loadImageBitmap import androidx.compose.ui.res.loadImageBitmap
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -306,6 +308,7 @@ fun HunkSplitTextDiff(
onResetHunk: (DiffEntry, Hunk) -> Unit, onResetHunk: (DiffEntry, Hunk) -> Unit,
) { ) {
val hunks = diffResult.hunks val hunks = diffResult.hunks
var selectableSide by remember { mutableStateOf(SelectableSide.BOTH) }
SelectionContainer { SelectionContainer {
ScrollableLazyColumn( ScrollableLazyColumn(
@ -332,28 +335,55 @@ fun HunkSplitTextDiff(
val highestLineNumberLength = highestLineNumber.toString().count() val highestLineNumberLength = highestLineNumber.toString().count()
items(splitHunk.lines) { linesPair -> items(splitHunk.lines) { linesPair ->
SplitDiffLine(highestLineNumberLength, linesPair.first, linesPair.second) SplitDiffLine(
highestLineNumberLength = highestLineNumberLength,
oldLine = linesPair.first,
newLine = linesPair.second,
selectableSide = selectableSide,
onChangeSelectableSide = { newSelectableSide ->
if (newSelectableSide != selectableSide) {
println("newSelectableSide $newSelectableSide")
selectableSide = newSelectableSide
}
}
)
} }
} }
} }
} }
} }
@Composable @Composable
fun SplitDiffLine(highestLineNumberLength: Int, first: Line?, second: Line?) { fun DynamicSelectionDisable(isDisabled: Boolean, content: @Composable () -> Unit) {
if (isDisabled) {
DisableSelection(content)
} else
content()
}
@Composable
fun SplitDiffLine(
highestLineNumberLength: Int,
oldLine: Line?,
newLine: Line?,
selectableSide: SelectableSide,
onChangeSelectableSide: (SelectableSide) -> Unit,
) {
Row( Row(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colors.secondarySurface) .background(MaterialTheme.colors.secondarySurface)
.height(IntrinsicSize.Min) .height(IntrinsicSize.Min)
) { ) {
Box( SplitDiffLineSide(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f),
) { highestLineNumberLength = highestLineNumberLength,
if (first != null) line = oldLine,
SplitDiffLine(highestLineNumberLength, first, first.oldLineNumber + 1) displayLineNumber = oldLine?.displayOldLineNumber ?: 0,
} currentSelectableSide = selectableSide,
lineSelectableSide = SelectableSide.OLD,
onChangeSelectableSide = onChangeSelectableSide,
)
Box( Box(
modifier = Modifier modifier = Modifier
@ -362,13 +392,57 @@ fun SplitDiffLine(highestLineNumberLength: Int, first: Line?, second: Line?) {
.background(MaterialTheme.colors.secondarySurface) .background(MaterialTheme.colors.secondarySurface)
) )
Box(modifier = Modifier.weight(1f)) { SplitDiffLineSide(
if (second != null) modifier = Modifier
SplitDiffLine(highestLineNumberLength, second, second.newLineNumber + 1) .weight(1f),
highestLineNumberLength = highestLineNumberLength,
line = newLine,
displayLineNumber = newLine?.displayNewLineNumber ?: 0,
currentSelectableSide = selectableSide,
lineSelectableSide = SelectableSide.NEW,
onChangeSelectableSide = onChangeSelectableSide,
)
}
}
@Composable
fun SplitDiffLineSide(
modifier: Modifier,
highestLineNumberLength: Int,
line: Line?,
displayLineNumber: Int,
currentSelectableSide: SelectableSide,
lineSelectableSide: SelectableSide,
onChangeSelectableSide: (SelectableSide) -> Unit,
) {
Box(
modifier = modifier
.onPointerEvent(PointerEventType.Press) {
onChangeSelectableSide(lineSelectableSide)
}
.onPointerEvent(PointerEventType.Release) {
onChangeSelectableSide(SelectableSide.BOTH)
}
) {
if (line != null) {
// To avoid both sides being selected, disable one side when the use is interacting with the other
DynamicSelectionDisable(
currentSelectableSide != lineSelectableSide &&
currentSelectableSide != SelectableSide.BOTH
) {
SplitDiffLine(highestLineNumberLength, line, displayLineNumber)
}
} }
} }
} }
enum class SelectableSide {
BOTH,
OLD,
NEW;
}
@Composable @Composable
fun HunkHeader( fun HunkHeader(
header: String, header: String,