Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #494: Add flag to control gesture continuity #599

Merged
merged 5 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import com.bumble.appyx.interactions.core.ui.state.MatchedTargetUiState
import com.bumble.appyx.transitionmodel.BaseMotionController

class Puzzle15MotionController(
private val uiContext: UiContext,
uiContext: UiContext,
defaultAnimationSpec: SpringSpec<Float> = DefaultAnimationSpec
) : BaseMotionController<Tile, Puzzle15Model.State, MutableUiState, TargetUiState>(
uiContext = uiContext,
Expand Down Expand Up @@ -66,22 +66,26 @@ class Puzzle15MotionController(
return when (dragDirection4(delta)) {
Drag.Direction4.UP -> Gesture(
operation = Swap(Swap.Direction.DOWN),
completeAt = Offset(0f, -cellSize)
completeAt = Offset(0f, -cellSize),
isContinuous = false
)

Drag.Direction4.LEFT -> Gesture(
operation = Swap(Swap.Direction.RIGHT),
completeAt = Offset(-cellSize, 0f)
completeAt = Offset(-cellSize, 0f),
isContinuous = false
)

Drag.Direction4.RIGHT -> Gesture(
operation = Swap(Swap.Direction.LEFT),
completeAt = Offset(cellSize, 0f)
completeAt = Offset(cellSize, 0f),
isContinuous = false
)

Drag.Direction4.DOWN -> Gesture(
operation = Swap(Swap.Direction.UP),
completeAt = Offset(0f, cellSize)
completeAt = Offset(0f, cellSize),
isContinuous = false
)

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class BackStackParallax<InteractionTarget : Any>(
Gesture(
operation = Pop(),
completeAt = Offset(x = transitionBounds.widthPx.toFloat(), y = 0f),
isContinuous = false
)
} else {
Gesture.Noop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ class BackStack3D<InteractionTarget : Any>(
return if (dragVerticalDirection(delta) == Drag.VerticalDirection.DOWN) {
Gesture(
operation = Pop(),
completeAt = Offset(x = 0f, y = heightInPx)
completeAt = Offset(x = 0f, y = heightInPx),
isContinuous = false
)
} else {
Gesture.Noop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,29 +97,44 @@ internal class DragProgressController<InteractionTarget : Any, State>(
// Case: standard forward progress
if (totalTarget < startProgress + 1) {
model.setProgress(totalTarget)
val currentProgress = if (currentState is Keyframes<*>) currentState.progress else 0f
AppyxLogger.d(
TAG,
"delta applied forward, new progress: $currentProgress"
)
val currentProgress =
if (currentState is Keyframes<*>) currentState.progress else 0f
AppyxLogger.d(TAG, "delta applied forward, new progress: $currentProgress")

// Case: target is beyond the current segment, we'll need a new operation
} else {
// TODO without recursion
val remainder =
consumePartial(COMPLETE, dragAmount, totalTarget, deltaProgress, startProgress + 1)
if (remainder.getDistanceSquared() > 0) {
consumeDrag(remainder)
if (gesture!!.isContinuous) {
val remainder =
consumePartial(
direction = COMPLETE,
dragAmount = dragAmount,
totalTarget = totalTarget,
deltaProgress = deltaProgress,
boundary = startProgress + 1
)
if (remainder.getDistanceSquared() > 0) {
consumeDrag(remainder)
}
}
}

// Case: we went back to or beyond the start,
// now we need to re-evaluate for a new operation
} else {
// TODO without recursion
val remainder = consumePartial(REVERT, dragAmount, totalTarget, deltaProgress, startProgress)
if (dragAmount != remainder) {
consumeDrag(remainder)
if (gesture!!.isContinuous) {
val remainder =
consumePartial(
direction = REVERT,
dragAmount = dragAmount,
totalTarget = totalTarget,
deltaProgress = deltaProgress,
boundary = startProgress
)
if (dragAmount != remainder) {
consumeDrag(remainder)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@ import com.bumble.appyx.interactions.core.ui.math.proportionOf

open class Gesture<InteractionTarget, ModelState> internal constructor(
val operation: Operation<ModelState>,
val isContinuous: Boolean,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think if we moved it to GestureFactory? That way it wouldn't need to be specified per every gesture. The cases we have so far are either all of them are continuous or all of them are not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the current option gives more control, however your suggestion is simpler to use, I would choose the existing one, but it's your call

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a combination:

  • GestureFactory provides the default
  • Gesture falls back to factory default but allows overriding if you want

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming based on the cases so far that it's either/or for the whole of it, so if it's only one choice I'd go with factory-level definition for its ease.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll update to only use on the factory

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zsoltk done!

val dragToProgress: (Offset) -> Float,
val partial: (Offset, Float) -> Offset
) {
var startProgress: Float? = null

/**
* isContinuous: Boolean - indicates that if during a drag gesture this operation completes
* but there's still offset to process a new gesture will be created that handles the remaining
* amount.
*/
constructor(
operation: Operation<ModelState>,
completeAt: Offset,
isContinuous: Boolean = true,
) : this(
operation = operation,
isContinuous = isContinuous,
dragToProgress = { offset -> proportionOf(offset, completeAt) },
partial = { offset, remainder ->
val totalProgress = proportionOf(offset, completeAt)
Expand All @@ -25,6 +33,7 @@ open class Gesture<InteractionTarget, ModelState> internal constructor(

class Noop<InteractionTarget, ModelState> : Gesture<InteractionTarget, ModelState>(
operation = Operation.Noop(),
isContinuous = false,
dragToProgress = { 0f },
partial = { _, _ -> Offset(0f, 0f) }
)
Expand Down