mirror of
https://github.com/fankes/pagecurl-multiplatform.git
synced 2025-09-06 02:35:25 +08:00
Add tap gestures support in lib, rework settings popup
This commit is contained in:
@@ -3,28 +3,17 @@ package eu.wewox.pagecurl.config
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.wewox.pagecurl.ExperimentalPageCurlApi
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
public data class PageCurlConfig(
|
||||
val curl: CurlConfig = CurlConfig(),
|
||||
val direction: PageCurlDirection = PageCurlDirection.StartToEnd,
|
||||
val interaction: InteractionConfig = InteractionConfig(forward = direction.forward()),
|
||||
)
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
public data class InteractionConfig(
|
||||
val forward: DragDirection,
|
||||
val backward: DragDirection = DragDirection(forward.end, forward.start),
|
||||
)
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
public data class DragDirection(
|
||||
val start: Rect,
|
||||
val end: Rect,
|
||||
val interaction: InteractionConfig = InteractionConfig(),
|
||||
)
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
@@ -48,18 +37,60 @@ public data class ShadowConfig(
|
||||
)
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
public enum class PageCurlDirection {
|
||||
StartToEnd,
|
||||
// TODO (Alex) Add support for reversed end-to-start direction
|
||||
// EndToStart,
|
||||
public data class InteractionConfig(
|
||||
val drag: Drag = Drag(),
|
||||
val tap: Tap = Tap(),
|
||||
) {
|
||||
@ExperimentalPageCurlApi
|
||||
public data class Drag(
|
||||
val forward: Interaction = Interaction(true, rightHalf(), leftHalf()),
|
||||
val backward: Interaction = Interaction(true, forward.end, forward.start),
|
||||
) {
|
||||
@ExperimentalPageCurlApi
|
||||
public data class Interaction(
|
||||
val enabled: Boolean,
|
||||
val start: Rect = Rect.Zero,
|
||||
val end: Rect = Rect.Zero,
|
||||
)
|
||||
}
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
public data class Tap(
|
||||
val forward: Interaction = Interaction(true, rightHalf()),
|
||||
val backward: Interaction = Interaction(true, leftHalf()),
|
||||
val custom: CustomInteraction = CustomInteraction(false)
|
||||
) {
|
||||
@ExperimentalPageCurlApi
|
||||
public data class Interaction(
|
||||
val enabled: Boolean,
|
||||
val target: Rect = Rect.Zero,
|
||||
)
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
public data class CustomInteraction(
|
||||
val enabled: Boolean,
|
||||
val onTap: Density.(IntSize, Offset) -> Boolean = { _, _ -> false },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun left(): Rect = Rect(Offset(0.0f, 0.0f), Offset(0.5f, 1.0f))
|
||||
|
||||
private fun right(): Rect = Rect(Offset(0.5f, 0.0f), Offset(1.0f, 1.0f))
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
private fun PageCurlDirection.forward(): DragDirection =
|
||||
when (this) {
|
||||
PageCurlDirection.StartToEnd -> DragDirection(right(), left())
|
||||
}
|
||||
public fun InteractionConfig.copy(
|
||||
dragForwardEnabled: Boolean = drag.forward.enabled,
|
||||
dragBackwardEnabled: Boolean = drag.backward.enabled,
|
||||
tapForwardEnabled: Boolean = tap.forward.enabled,
|
||||
tapBackwardEnabled: Boolean = tap.backward.enabled,
|
||||
): InteractionConfig = copy(
|
||||
drag = drag.copy(
|
||||
forward = drag.forward.copy(enabled = dragForwardEnabled),
|
||||
backward = drag.backward.copy(enabled = dragBackwardEnabled)
|
||||
),
|
||||
tap = tap.copy(
|
||||
forward = tap.forward.copy(enabled = tapForwardEnabled),
|
||||
backward = tap.backward.copy(enabled = tapBackwardEnabled)
|
||||
)
|
||||
)
|
||||
|
||||
private fun leftHalf(): Rect = Rect(0.0f, 0.0f, 0.5f, 1.0f)
|
||||
|
||||
private fun rightHalf(): Rect = Rect(0.5f, 0.0f, 1.0f, 1.0f)
|
||||
|
@@ -10,12 +10,11 @@ import androidx.compose.foundation.gestures.drag
|
||||
import androidx.compose.foundation.gestures.forEachGesture
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.input.pointer.util.VelocityTracker
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import eu.wewox.pagecurl.ExperimentalPageCurlApi
|
||||
import eu.wewox.pagecurl.config.DragDirection
|
||||
import eu.wewox.pagecurl.config.InteractionConfig
|
||||
import eu.wewox.pagecurl.utils.multiply
|
||||
import eu.wewox.pagecurl.utils.rotate
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -26,7 +25,7 @@ internal fun Modifier.curlGesture(
|
||||
state: PageCurlState.InternalState,
|
||||
enabled: Boolean,
|
||||
scope: CoroutineScope,
|
||||
direction: DragDirection,
|
||||
direction: InteractionConfig.Drag.Interaction,
|
||||
start: Edge,
|
||||
end: Edge,
|
||||
edge: Animatable<Edge, AnimationVector4D>,
|
||||
@@ -68,7 +67,7 @@ internal fun Modifier.curlGesture(
|
||||
internal fun Modifier.curlGesture(
|
||||
key: Any?,
|
||||
enabled: Boolean,
|
||||
direction: DragDirection,
|
||||
direction: InteractionConfig.Drag.Interaction,
|
||||
onStart: () -> Unit,
|
||||
onCurl: (Offset, Offset) -> Unit,
|
||||
onEnd: () -> Unit,
|
||||
@@ -127,9 +126,3 @@ internal fun Modifier.curlGesture(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Rect.multiply(size: IntSize): Rect =
|
||||
Rect(
|
||||
topLeft = Offset(size.width * left, size.height * top),
|
||||
bottomRight = Offset(size.width * right, size.height * bottom),
|
||||
)
|
||||
|
@@ -30,9 +30,9 @@ public fun PageCurl(
|
||||
Modifier
|
||||
.curlGesture(
|
||||
state = internalState,
|
||||
enabled = updatedCurrent < state.max - 1,
|
||||
enabled = config.interaction.drag.forward.enabled && updatedCurrent < state.max - 1,
|
||||
scope = scope,
|
||||
direction = config.interaction.forward,
|
||||
direction = config.interaction.drag.forward,
|
||||
start = internalState.rightEdge,
|
||||
end = internalState.leftEdge,
|
||||
edge = internalState.forward,
|
||||
@@ -40,14 +40,21 @@ public fun PageCurl(
|
||||
)
|
||||
.curlGesture(
|
||||
state = internalState,
|
||||
enabled = updatedCurrent > 0,
|
||||
enabled = config.interaction.drag.backward.enabled && updatedCurrent > 0,
|
||||
scope = scope,
|
||||
direction = config.interaction.backward,
|
||||
direction = config.interaction.drag.backward,
|
||||
start = internalState.leftEdge,
|
||||
end = internalState.rightEdge,
|
||||
edge = internalState.backward,
|
||||
onChange = { state.current = updatedCurrent - 1 }
|
||||
)
|
||||
.tapGesture(
|
||||
state = internalState,
|
||||
scope = scope,
|
||||
interaction = config.interaction.tap,
|
||||
onTapForward = state::next,
|
||||
onTapBackward = state::prev,
|
||||
)
|
||||
) {
|
||||
if (updatedCurrent + 1 < state.max) {
|
||||
content(updatedCurrent + 1)
|
||||
|
@@ -0,0 +1,50 @@
|
||||
package eu.wewox.pagecurl.page
|
||||
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.forEachGesture
|
||||
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import eu.wewox.pagecurl.ExperimentalPageCurlApi
|
||||
import eu.wewox.pagecurl.config.InteractionConfig
|
||||
import eu.wewox.pagecurl.utils.multiply
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@ExperimentalPageCurlApi
|
||||
internal fun Modifier.tapGesture(
|
||||
state: PageCurlState.InternalState,
|
||||
scope: CoroutineScope,
|
||||
interaction: InteractionConfig.Tap,
|
||||
onTapForward: suspend () -> Unit,
|
||||
onTapBackward: suspend () -> Unit,
|
||||
): Modifier = pointerInput(interaction, state) {
|
||||
forEachGesture {
|
||||
awaitPointerEventScope {
|
||||
val down = awaitFirstDown().also { it.consume() }
|
||||
val up = waitForUpOrCancellation() ?: return@awaitPointerEventScope
|
||||
|
||||
if ((down.position - up.position).getDistance() > viewConfiguration.touchSlop) {
|
||||
return@awaitPointerEventScope
|
||||
}
|
||||
|
||||
if (interaction.custom.enabled && interaction.custom.onTap(this, size, up.position)) {
|
||||
return@awaitPointerEventScope
|
||||
}
|
||||
|
||||
if (interaction.forward.enabled && interaction.forward.target.multiply(size).contains(up.position)) {
|
||||
scope.launch {
|
||||
onTapForward()
|
||||
}
|
||||
return@awaitPointerEventScope
|
||||
}
|
||||
|
||||
if (interaction.backward.enabled && interaction.backward.target.multiply(size).contains(up.position)) {
|
||||
scope.launch {
|
||||
onTapBackward()
|
||||
}
|
||||
return@awaitPointerEventScope
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package eu.wewox.pagecurl.utils
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
|
||||
internal fun Rect.multiply(size: IntSize): Rect =
|
||||
Rect(
|
||||
topLeft = Offset(size.width * left, size.height * top),
|
||||
bottomRight = Offset(size.width * right, size.height * bottom),
|
||||
)
|
Reference in New Issue
Block a user