mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
fix: resolve gesture conflicts by unifying drag handlers
Replaced competing pointerInput modifiers with a single unified gesture handler that determines drag direction early. This eliminates conflicts between horizontal seeking and vertical brightness/volume gestures, making swipe interactions more reliable and predictable.
This commit is contained in:
@@ -5,10 +5,10 @@ import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
|
||||
internal object HorizontalSeekGestureHelper {
|
||||
val START_THRESHOLD = 24.dp
|
||||
private const val COEFFICIENT = 1.3f
|
||||
const val EXPONENT = 1.8f
|
||||
private const val MAX_DELTA_MS = 300_000L
|
||||
val START_THRESHOLD = 12.dp
|
||||
private const val COEFFICIENT = 3.1f
|
||||
const val EXPONENT = 1.7f
|
||||
private const val MAX_DELTA_MS = 12_000_000L
|
||||
|
||||
fun deltaMs(rawDelta: Float): Long {
|
||||
val magnitude = abs(rawDelta)
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
package hu.bbara.purefin.player.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.gestures.detectDragGestures
|
||||
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
|
||||
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.gestures.drag
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.input.pointer.PointerInputChange
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.input.pointer.positionChange
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import hu.bbara.purefin.player.helper.HorizontalSeekGestureHelper
|
||||
import kotlin.math.abs
|
||||
|
||||
@Composable
|
||||
fun PlayerGesturesLayer(
|
||||
@@ -31,85 +32,96 @@ fun PlayerGesturesLayer(
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val horizontalThresholdPx = with(density) { HorizontalSeekGestureHelper.START_THRESHOLD.toPx() }
|
||||
val directionThresholdPx = with(density) { 20.dp.toPx() } // Threshold to determine drag direction
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth(0.90f)
|
||||
.fillMaxHeight(0.70f)
|
||||
// .background(Color(2f, 2f, 2f, 0.3f))
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onTap = { onTap() },
|
||||
onDoubleTap = { offset ->
|
||||
// TODO extract it into an enum
|
||||
val screenWidth = size.width
|
||||
val oneThird = screenWidth / 3
|
||||
val secondThird = oneThird * 2
|
||||
if (offset.x < oneThird) {
|
||||
onDoubleTapLeft()
|
||||
} else if (offset.x >= oneThird && offset.x <= secondThird) {
|
||||
onDoubleTapCenter()
|
||||
} else {
|
||||
onDoubleTapRight()
|
||||
when {
|
||||
offset.x < oneThird -> onDoubleTapLeft()
|
||||
offset.x <= secondThird -> onDoubleTapCenter()
|
||||
else -> onDoubleTapRight()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
.pointerInput(Unit) {
|
||||
detectDragGestures { change, dragAmount ->
|
||||
val horizontalThreshold = size.width / 2
|
||||
if (change.position.x < horizontalThreshold) {
|
||||
onVerticalDragLeft(dragAmount.y)
|
||||
} else {
|
||||
onVerticalDragRight(dragAmount.y)
|
||||
awaitEachGesture {
|
||||
val down = awaitFirstDown(requireUnconsumed = false)
|
||||
val startX = down.position.x
|
||||
|
||||
var accumulatedDrag = Offset.Zero
|
||||
var dragDirection: DragDirection? = null
|
||||
var accumulatedHorizontalDrag = 0f
|
||||
var isHorizontalDragActive = false
|
||||
var lastPreviewDelta: Long? = null
|
||||
|
||||
val dragResult = drag(down.id) { change ->
|
||||
val delta = change.positionChange()
|
||||
accumulatedDrag += delta
|
||||
|
||||
// Determine direction if not yet determined
|
||||
if (dragDirection == null && (abs(accumulatedDrag.x) > directionThresholdPx || abs(accumulatedDrag.y) > directionThresholdPx)) {
|
||||
dragDirection = if (abs(accumulatedDrag.x) > abs(accumulatedDrag.y)) {
|
||||
DragDirection.HORIZONTAL
|
||||
} else {
|
||||
DragDirection.VERTICAL
|
||||
}
|
||||
}
|
||||
|
||||
// Handle based on determined direction
|
||||
when (dragDirection) {
|
||||
DragDirection.HORIZONTAL -> {
|
||||
accumulatedHorizontalDrag += delta.x
|
||||
if (!isHorizontalDragActive && abs(accumulatedHorizontalDrag) >= horizontalThresholdPx) {
|
||||
isHorizontalDragActive = true
|
||||
}
|
||||
if (isHorizontalDragActive) {
|
||||
change.consume()
|
||||
val deltaMs = HorizontalSeekGestureHelper.deltaMs(accumulatedHorizontalDrag)
|
||||
if (deltaMs != 0L && deltaMs != lastPreviewDelta) {
|
||||
lastPreviewDelta = deltaMs
|
||||
onHorizontalDragPreview(deltaMs)
|
||||
}
|
||||
}
|
||||
}
|
||||
DragDirection.VERTICAL -> {
|
||||
val isLeftSide = startX < size.width / 2
|
||||
if (isLeftSide) {
|
||||
onVerticalDragLeft(delta.y)
|
||||
} else {
|
||||
onVerticalDragRight(delta.y)
|
||||
}
|
||||
}
|
||||
null -> {
|
||||
// Direction not determined yet, keep accumulating
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle drag end
|
||||
if (dragDirection == DragDirection.HORIZONTAL && isHorizontalDragActive) {
|
||||
val deltaMs = HorizontalSeekGestureHelper.deltaMs(accumulatedHorizontalDrag)
|
||||
if (deltaMs != 0L) {
|
||||
onHorizontalDrag(deltaMs)
|
||||
onHorizontalDragPreview(deltaMs)
|
||||
}
|
||||
}
|
||||
onHorizontalDragPreview(null)
|
||||
}
|
||||
}
|
||||
.pointerInput(Unit) {
|
||||
var accumulatedHorizontalDrag = 0f
|
||||
var isHorizontalDragActive = false
|
||||
var lastPreviewDelta: Long? = null
|
||||
detectHorizontalDragGestures(
|
||||
onDragStart = {
|
||||
accumulatedHorizontalDrag = 0f
|
||||
isHorizontalDragActive = false
|
||||
lastPreviewDelta = null
|
||||
onHorizontalDragPreview(null)
|
||||
},
|
||||
onHorizontalDrag = { change, dragAmount ->
|
||||
accumulatedHorizontalDrag += dragAmount
|
||||
if (!isHorizontalDragActive && kotlin.math.abs(accumulatedHorizontalDrag) >= horizontalThresholdPx) {
|
||||
isHorizontalDragActive = true
|
||||
}
|
||||
if (isHorizontalDragActive) {
|
||||
change.consume()
|
||||
val deltaMs = HorizontalSeekGestureHelper.deltaMs(accumulatedHorizontalDrag)
|
||||
if (deltaMs != 0L && deltaMs != lastPreviewDelta) {
|
||||
lastPreviewDelta = deltaMs
|
||||
onHorizontalDragPreview(deltaMs)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDragEnd = {
|
||||
if (isHorizontalDragActive) {
|
||||
val deltaMs = HorizontalSeekGestureHelper.deltaMs(accumulatedHorizontalDrag)
|
||||
if (deltaMs != 0L) {
|
||||
onHorizontalDrag(deltaMs)
|
||||
onHorizontalDragPreview(deltaMs)
|
||||
}
|
||||
}
|
||||
accumulatedHorizontalDrag = 0f
|
||||
isHorizontalDragActive = false
|
||||
lastPreviewDelta = null
|
||||
onHorizontalDragPreview(null)
|
||||
},
|
||||
onDragCancel = {
|
||||
accumulatedHorizontalDrag = 0f
|
||||
isHorizontalDragActive = false
|
||||
lastPreviewDelta = null
|
||||
onHorizontalDragPreview(null)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private enum class DragDirection {
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user