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

Position alignment #539

Merged
merged 11 commits into from
Jul 24, 2023
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

## Pending changes

- [#530](https://github.com/bumble-tech/appyx/issues/530) – **Fixed**: Backstack Parallax motion controller bug
### Added

- [#539](https://github.com/bumble-tech/appyx/pull/539) – Position alignment

### Fixed

- [#530](https://github.com/bumble-tech/appyx/issues/530) – Backstack Parallax motion controller bug

---

## 2.0.0-alpha01

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Puzzle15MotionController(
element = tileElements,
targetUiState = TargetUiState(
position = Position.Target(
value = DpOffset(
offset = DpOffset(
x = (index % 4 * width).dp,
y = (index / 4 * width).dp
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fun ComposeContentTestRule.createTestDrive(
},
progressAnimationSpec = animationSpec ?: spring(),
gestureFactory = {
TestDriveSimpleMotionController.Gestures()
TestDriveSimpleMotionController.Gestures(it)
},
).also { setupTestDrive(it, model) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fun <InteractionTarget : Any> TestDriveExperiment(
),
)
},
gestureFactory = { TestDriveSimpleMotionController.Gestures() }
gestureFactory = { TestDriveSimpleMotionController.Gestures(it) }
)
}

Expand Down Expand Up @@ -161,7 +161,8 @@ fun <InteractionTarget : Any> TestDriveUi(
Box(
modifier = Modifier
.size(60.dp)
.offset(targetUiState.position.value.x, targetUiState.position.value.y)
.align(targetUiState.position.value.alignment)
.offset(targetUiState.position.value.offset.x, targetUiState.position.value.offset.y)
.border(2.dp, targetUiState.backgroundColor.value)
.semantics {
contentDescription = TEST_DRIVE_EXPERIMENT_TEST_HELPER
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.bumble.appyx.components.internal.testdrive.ui.rotation

import androidx.compose.animation.core.SpringSpec
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.Alignment
import com.bumble.appyx.components.internal.testdrive.TestDriveModel
import com.bumble.appyx.components.internal.testdrive.TestDriveModel.State.ElementState.A
import com.bumble.appyx.components.internal.testdrive.TestDriveModel.State.ElementState.B
Expand Down Expand Up @@ -36,40 +35,36 @@ class TestDriveRotationMotionController<InteractionTarget : Any>(
)

companion object {
val offsetA = DpOffset(0.dp, 0.dp)
val offsetB = DpOffset(200.dp, 0.dp)
val offsetC = DpOffset(200.dp, 300.dp)
val offsetD = DpOffset(0.dp, 300.dp)

fun TestDriveModel.State.ElementState.toTargetUiState(): TargetUiState =
when (this) {
A -> a
B -> b
C -> c
D -> d
A -> topLeftCorner
B -> topRightCorner
C -> bottomRightCorner
D -> bottomLeftCorner
}

private val a = TargetUiState(
position = Position.Target(offsetA),
private val topLeftCorner = TargetUiState(
position = Position.Target(Alignment.TopStart),
rotationZ = RotationZ.Target(0f),
backgroundColor = BackgroundColor.Target(md_red_500)
)

private val b = TargetUiState(
position = Position.Target(offsetB),
rotationZ = RotationZ.Target(90f),
private val topRightCorner = TargetUiState(
position = Position.Target(Alignment.TopEnd),
rotationZ = RotationZ.Target(180f),
backgroundColor = BackgroundColor.Target(md_light_green_500)
)

private val c = TargetUiState(
position = Position.Target(offsetC),
rotationZ = RotationZ.Target(180f),
private val bottomRightCorner = TargetUiState(
position = Position.Target(Alignment.CenterEnd),
rotationZ = RotationZ.Target(270f),
backgroundColor = BackgroundColor.Target(md_yellow_500)
)

private val d = TargetUiState(
position = Position.Target(offsetD),
rotationZ = RotationZ.Target(270f),
private val bottomLeftCorner = TargetUiState(
position = Position.Target(Alignment.CenterStart),
rotationZ = RotationZ.Target(540f),
backgroundColor = BackgroundColor.Target(md_light_blue_500)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.bumble.appyx.components.internal.testdrive.ui.simple

import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor
import com.bumble.appyx.interactions.core.ui.property.impl.Position
import com.bumble.appyx.interactions.core.ui.property.impl.RotationZ
import com.bumble.appyx.interactions.core.ui.state.MutableUiStateSpecs

@Suppress("unused")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.bumble.appyx.components.internal.testdrive.ui.simple

import androidx.compose.animation.core.SpringSpec
import androidx.compose.ui.Alignment
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.bumble.appyx.components.internal.testdrive.TestDriveModel
import com.bumble.appyx.components.internal.testdrive.TestDriveModel.State.ElementState.A
import com.bumble.appyx.components.internal.testdrive.TestDriveModel.State.ElementState.B
Expand All @@ -16,6 +15,7 @@ import com.bumble.appyx.components.internal.testdrive.ui.md_light_green_500
import com.bumble.appyx.components.internal.testdrive.ui.md_red_500
import com.bumble.appyx.components.internal.testdrive.ui.md_yellow_500
import com.bumble.appyx.interactions.AppyxLogger
import com.bumble.appyx.interactions.core.ui.context.TransitionBounds
import com.bumble.appyx.interactions.core.ui.context.UiContext
import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.DOWN
import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.DOWNLEFT
Expand Down Expand Up @@ -49,86 +49,78 @@ class TestDriveSimpleMotionController<InteractionTarget : Any>(
)

companion object {
val offsetA = DpOffset(0.dp, 0.dp)
val offsetB = DpOffset(200.dp, 0.dp)
val offsetC = DpOffset(200.dp, 300.dp)
val offsetD = DpOffset(0.dp, 300.dp)

fun TestDriveModel.State.ElementState.toTargetUiState(): TargetUiState =
when (this) {
A -> uiStateA
B -> uiStateB
C -> uiStateC
D -> uiStateD
A -> topLeftCorner
B -> topRightCorner
C -> bottomRightCorner
D -> bottomLeftCorner
}

// Top-left corner, red
private val uiStateA = TargetUiState(
position = Position.Target(offsetA),
private val topLeftCorner = TargetUiState(
position = Position.Target(Alignment.TopStart),
backgroundColor = BackgroundColor.Target(md_red_500)
)

// Top-right corner, green
private val uiStateB = TargetUiState(
position = Position.Target(offsetB),
private val topRightCorner = TargetUiState(
position = Position.Target(Alignment.TopEnd),
backgroundColor = BackgroundColor.Target(md_light_green_500)
)

// Bottom-right corner, yellow
private val uiStateC = TargetUiState(
position = Position.Target(offsetC),
private val bottomRightCorner = TargetUiState(
position = Position.Target(Alignment.CenterEnd),
backgroundColor = BackgroundColor.Target(md_yellow_500)
)

// Bottom-left corner, blue
private val uiStateD = TargetUiState(
position = Position.Target(offsetD),
private val bottomLeftCorner = TargetUiState(
position = Position.Target(Alignment.CenterStart),
backgroundColor = BackgroundColor.Target(md_light_blue_500)
)
}

override fun mutableUiStateFor(uiContext: UiContext, targetUiState: TargetUiState): MutableUiState =
targetUiState.toMutableState(uiContext)

class Gestures<InteractionTarget> : GestureFactory<InteractionTarget, TestDriveModel.State<InteractionTarget>> {
private val widthDp = offsetB.x - offsetA.x
private val heightDp = offsetD.y - offsetA.y
class Gestures<InteractionTarget>(
private val transitionBounds: TransitionBounds
) : GestureFactory<InteractionTarget, TestDriveModel.State<InteractionTarget>> {

override fun createGesture(
state: TestDriveModel.State<InteractionTarget>,
delta: Offset,
density: Density
): Gesture<InteractionTarget, TestDriveModel.State<InteractionTarget>> {
val width = with(density) { widthDp.toPx() }
val height = with(density) { heightDp.toPx() }
val maxX = transitionBounds.widthPx.toFloat()
val maxY = transitionBounds.heightPx.toFloat() / 2 // Alignment at CenterStart/End

val direction = dragDirection8(delta)
return when (state.elementState) {
A -> when (direction) {
RIGHT -> Gesture(MoveTo(B), Offset(width, 0f))
DOWNRIGHT -> Gesture(MoveTo(C), Offset(width, height))
DOWN -> Gesture(MoveTo(D), Offset(0f, height))
RIGHT -> Gesture(MoveTo(B), Offset(maxX, 0f))
DOWNRIGHT -> Gesture(MoveTo(C), Offset(maxX, maxY))
DOWN -> Gesture(MoveTo(D), Offset(0f, maxY))
else -> Gesture.Noop()
}

B -> when (direction) {
DOWN -> Gesture(MoveTo(C), Offset(0f, height))
DOWNLEFT -> Gesture(MoveTo(D), Offset(-width, height))
LEFT -> Gesture(MoveTo(A), Offset(-width, 0f))
DOWN -> Gesture(MoveTo(C), Offset(0f, maxY))
DOWNLEFT -> Gesture(MoveTo(D), Offset(-maxX, maxY))
LEFT -> Gesture(MoveTo(A), Offset(-maxX, 0f))
else -> Gesture.Noop()
}

C -> when (direction) {
LEFT -> Gesture(MoveTo(D), Offset(-width, 0f))
UPLEFT -> Gesture(MoveTo(A), Offset(-width, -height))
UP -> Gesture(MoveTo(B), Offset(0f, -height))
LEFT -> Gesture(MoveTo(D), Offset(-maxX, 0f))
UPLEFT -> Gesture(MoveTo(A), Offset(-maxX, -maxY))
UP -> Gesture(MoveTo(B), Offset(0f, -maxY))
else -> Gesture.Noop()
}

D -> when (direction) {
UP -> Gesture(MoveTo(A), Offset(0f, -height))
UPRIGHT -> Gesture(MoveTo(B), Offset(width, -height))
RIGHT -> Gesture(MoveTo(C), Offset(width, 0f))
UP -> Gesture(MoveTo(A), Offset(0f, -maxY))
UPRIGHT -> Gesture(MoveTo(B), Offset(maxX, -maxY))
RIGHT -> Gesture(MoveTo(C), Offset(maxX, 0f))
else -> Gesture.Noop()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class TargetUiState(
) : this(
positionInList = positionInList,
position = Position.Target(
base.position.value.copy(
base.position.value.offset.copy(
x = (positionInList * elementWidth.value).dp
)
),
Expand All @@ -49,9 +49,10 @@ class TargetUiState(
MutableUiState(
uiContext = uiContext,
position = Position(
uiContext, position,
scrollX.mapState(uiContext.coroutineScope) {
DpOffset((it * elementWidth.value).dp, 0.dp)
uiContext = uiContext,
target = position,
displacement = scrollX.mapState(uiContext.coroutineScope) {
Position.Value(offset = DpOffset((it * elementWidth.value).dp, 0.dp))
},
),
scale = Scale(uiContext, scale),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class TargetUiState(
) : this(
positionInList = positionInList,
position = Position.Target(
base.position.value.copy(
base.position.value.offset.copy(
x = (positionInList * elementWidth.value).dp
)
),
Expand All @@ -55,9 +55,10 @@ class TargetUiState(
return MutableUiState(
uiContext = uiContext,
position = Position(
uiContext, position,
scrollX.mapState(uiContext.coroutineScope) {
DpOffset((it * elementWidth.value).dp, 0.dp)
uiContext = uiContext,
target = position,
displacement = scrollX.mapState(uiContext.coroutineScope) {
Position.Value(offset = DpOffset((it * elementWidth.value).dp, 0.dp))
},
),
scale = Scale(uiContext, scale,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class TargetUiState(
) : this(
positionInList = positionInList,
position = Position.Target(
base.position.value.copy(
base.position.value.offset.copy(
x = (positionInList * elementWidth.value).dp
)
),
Expand All @@ -47,9 +47,10 @@ class TargetUiState(
return MutableUiState(
uiContext = uiContext,
position = Position(
uiContext, position,
scrollX.mapState(uiContext.coroutineScope) {
DpOffset((it * elementWidth.value).dp, 0.dp)
uiContext = uiContext,
target = position,
displacement = scrollX.mapState(uiContext.coroutineScope) {
Position.Value(offset = DpOffset((it * elementWidth.value).dp, 0.dp))
},
),
scale = Scale(uiContext, scale,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.bumble.appyx.components.spotlight.ui.stack3d

import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
Expand All @@ -9,7 +8,6 @@ import com.bumble.appyx.interactions.core.ui.math.clamp
import com.bumble.appyx.interactions.core.ui.math.smoothstep
import com.bumble.appyx.interactions.core.ui.property.impl.Alpha
import com.bumble.appyx.interactions.core.ui.property.impl.Position
import com.bumble.appyx.interactions.core.ui.property.impl.RotationX
import com.bumble.appyx.interactions.core.ui.property.impl.Scale
import com.bumble.appyx.interactions.core.ui.property.impl.ZIndex
import com.bumble.appyx.interactions.core.ui.state.MutableUiStateSpecs
Expand Down Expand Up @@ -48,9 +46,11 @@ class TargetUiState(
target = position,
displacement = scrollX.mapState(uiContext.coroutineScope) {
val factor = 0.075f + smoothstep(0f, 1f, it)
DpOffset(
x = 0.dp,
y = (-factor * it * itemHeight.value / (1f - 0.1f * it)).dp,
Position.Value(
offset = DpOffset(
x = 0.dp,
y = (-factor * it * itemHeight.value / (1f - 0.1f * it)).dp,
)
)
}
),
Expand Down
Loading
Loading