Add tap gestures support in lib, rework settings popup

This commit is contained in:
Oleksandr Balan
2022-07-24 16:50:44 +02:00
parent 840093c2e7
commit faa198f7b0
9 changed files with 280 additions and 126 deletions

View File

@@ -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)

View File

@@ -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),
)

View File

@@ -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)

View File

@@ -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
}
}
}
}

View File

@@ -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),
)