diff --git a/CHANGELOG.md b/CHANGELOG.md index c56d537db..44be48b33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Please refer to [2.0.0-alpha10 – Migration guide](2.0.0-alpha10.md) - [#652](https://github.com/bumble-tech/appyx/pull/652) - KSP processor renamed from `mutable-ui-processor` to `appyx-processor` - [#654](https://github.com/bumble-tech/appyx/pull/654) - Renamings - [#657](https://github.com/bumble-tech/appyx/pull/657) - Rename ParentNode & Node to Node and LeafNode +- [#644](https://github.com/bumble-tech/appyx/pull/644) – Refactor AppyxComponent and application of draggable modifier ### Fixed diff --git a/appyx-components/experimental/cards/android/src/main/kotlin/com/bumble/appyx/components/experimental/cards/android/DatingCards.kt b/appyx-components/experimental/cards/android/src/main/kotlin/com/bumble/appyx/components/experimental/cards/android/DatingCards.kt index 73353b4fa..711400b9f 100644 --- a/appyx-components/experimental/cards/android/src/main/kotlin/com/bumble/appyx/components/experimental/cards/android/DatingCards.kt +++ b/appyx-components/experimental/cards/android/src/main/kotlin/com/bumble/appyx/components/experimental/cards/android/DatingCards.kt @@ -47,10 +47,11 @@ fun DatingCards(modifier: Modifier = Modifier) { screenHeightPx = (LocalConfiguration.current.screenHeightDp * LocalDensity.current.density).roundToInt(), appyxComponent = cards, gestureValidator = permissiveValidator, - ) { elementUiModel -> + ) { element -> ProfileCard( - profile = elementUiModel.element.interactionTarget.profile, - modifier = Modifier.fillMaxSize().then(elementUiModel.modifier) + profile = element.interactionTarget.profile, + modifier = Modifier + .fillMaxSize() ) } } diff --git a/appyx-components/experimental/cards/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/cards/ui/CardsVisualisation.kt b/appyx-components/experimental/cards/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/cards/ui/CardsVisualisation.kt index 5ef4f4ee9..8933757d4 100644 --- a/appyx-components/experimental/cards/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/cards/ui/CardsVisualisation.kt +++ b/appyx-components/experimental/cards/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/cards/ui/CardsVisualisation.kt @@ -13,7 +13,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragHorizontalDirection -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.RotationZ import com.bumble.appyx.interactions.core.ui.property.impl.Scale import com.bumble.appyx.interactions.core.ui.property.impl.ZIndex diff --git a/appyx-components/experimental/promoter/android/src/main/kotlin/com/bumble/appyx/components/experimental/promoter/android/PromoterExperiment.kt b/appyx-components/experimental/promoter/android/src/main/kotlin/com/bumble/appyx/components/experimental/promoter/android/PromoterExperiment.kt index afdd022ce..75279d2af 100644 --- a/appyx-components/experimental/promoter/android/src/main/kotlin/com/bumble/appyx/components/experimental/promoter/android/PromoterExperiment.kt +++ b/appyx-components/experimental/promoter/android/src/main/kotlin/com/bumble/appyx/components/experimental/promoter/android/PromoterExperiment.kt @@ -82,9 +82,9 @@ fun PromoterExperiment(modifier: Modifier = Modifier) { horizontal = 64.dp, vertical = 12.dp ), - element = { + elementUi = { Element( - elementUiModel = it, + element = it, modifier = Modifier.size(100.dp) ) }, diff --git a/appyx-components/experimental/promoter/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/promoter/ui/PromoterVisualisation.kt b/appyx-components/experimental/promoter/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/promoter/ui/PromoterVisualisation.kt index 73569f73d..2b1f14d4b 100644 --- a/appyx-components/experimental/promoter/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/promoter/ui/PromoterVisualisation.kt +++ b/appyx-components/experimental/promoter/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/promoter/ui/PromoterVisualisation.kt @@ -9,7 +9,7 @@ import com.bumble.appyx.components.experimental.promoter.PromoterModel import com.bumble.appyx.components.experimental.promoter.PromoterModel.State.ElementState 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.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.AngularPosition import com.bumble.appyx.interactions.core.ui.property.impl.RotationY import com.bumble.appyx.interactions.core.ui.property.impl.RotationZ diff --git a/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Ui.kt b/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Ui.kt index 0d9cb7958..1c36ad14e 100644 --- a/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Ui.kt +++ b/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Ui.kt @@ -2,7 +2,6 @@ package com.bumble.appyx.components.experimental.puzzle15.ui import androidx.compose.foundation.background import androidx.compose.foundation.border -import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -28,7 +27,6 @@ import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.input.key.type -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.bumble.appyx.components.experimental.puzzle15.Puzzle15 @@ -39,8 +37,9 @@ import com.bumble.appyx.components.experimental.puzzle15.operation.Swap.Directio import com.bumble.appyx.components.experimental.puzzle15.operation.Swap.Direction.LEFT import com.bumble.appyx.components.experimental.puzzle15.operation.Swap.Direction.RIGHT import com.bumble.appyx.components.experimental.puzzle15.operation.Swap.Direction.UP +import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.gesture.GestureValidator import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup -import com.bumble.appyx.interactions.sample.Children @Suppress("MagicNumber", "LongMethod") @Composable @@ -83,74 +82,31 @@ fun Puzzle15Ui( .size(240.dp) .border(4.dp, accentColor) ) { - Children( + AppyxInteractionsContainer( + gestureValidator = GestureValidator.permissiveValidator, screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, appyxComponent = puzzle15, - ) { elementUiModel -> - if (elementUiModel.element.interactionTarget == Puzzle15Model.Tile.EmptyTile) { + ) { element -> + if (element.interactionTarget == Puzzle15Model.Tile.EmptyTile) { Box( - modifier = Modifier.size(60.dp) - .then( - elementUiModel.modifier - .background(color = Color.Transparent) - ) + modifier = Modifier + .size(60.dp) + .background(color = Color.Transparent) + ) } else { - val state = model.output.value - val element = - state.currentTargetState.items.find { it.id == elementUiModel.element.id } - val index = state.currentTargetState.items.indexOf(element) - val emptyTileIndex = state.currentTargetState.emptyTileIndex - - @Suppress("ComplexCondition") - if (index == emptyTileIndex - 1 || - index == emptyTileIndex + 1 || - index == emptyTileIndex - 4 || - index == emptyTileIndex + 4 + Box( + modifier = Modifier + .size(60.dp) + .background(color = Color.White) ) { - Box( - modifier = Modifier.size(60.dp) - .then( - elementUiModel - .modifier - .background(color = Color.White) - ) - .pointerInput(elementUiModel.element.id) { - this.interceptOutOfBoundsChildEvents = true - detectDragGestures( - onDrag = { change, dragAmount -> - change.consume() - puzzle15.onDrag(dragAmount, this) - }, - onDragEnd = { - puzzle15.onDragEnd() - } - ) - } - ) { - Text( - color = Color.Black, - text = elementUiModel.element.interactionTarget.textValue(), - modifier = Modifier.align(Alignment.Center), - fontSize = 24.sp, - ) - } - } else { - Box( - modifier = Modifier.size(60.dp) - .then( - elementUiModel.modifier - .background(color = Color.White) - ) - ) { - Text( - color = Color.Black, - text = elementUiModel.element.interactionTarget.textValue(), - modifier = Modifier.align(Alignment.Center), - fontSize = 24.sp, - ) - } + Text( + color = Color.Black, + text = element.interactionTarget.textValue(), + modifier = Modifier.align(Alignment.Center), + fontSize = 24.sp, + ) } } } diff --git a/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Visualisation.kt b/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Visualisation.kt index 26d369359..bf726deb7 100644 --- a/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Visualisation.kt +++ b/appyx-components/experimental/puzzle15/common/src/commonMain/kotlin/com/bumble/appyx/components/experimental/puzzle15/ui/Puzzle15Visualisation.kt @@ -13,7 +13,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragDirection4 -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment.Companion.fractionAlignment import com.bumble.appyx.interactions.core.ui.property.impl.position.PositionAlignment import com.bumble.appyx.interactions.core.ui.state.MatchedTargetUiState diff --git a/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/TestDriveExperiment.kt b/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/TestDriveExperiment.kt index 1f706443d..536154b33 100644 --- a/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/TestDriveExperiment.kt +++ b/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/TestDriveExperiment.kt @@ -138,11 +138,11 @@ fun TestDriveUi( screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, appyxComponent = testDrive, - gestureValidator = gestureValidator, - ) { elementUiModel -> + gestureValidator = gestureValidator + ) { Box( - modifier = Modifier.size(60.dp) - .then(elementUiModel.modifier) + modifier = Modifier + .size(60.dp) ) } diff --git a/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/rotation/TestDriveRotationVisualisation.kt b/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/rotation/TestDriveRotationVisualisation.kt index 6ebe91405..6965cf128 100644 --- a/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/rotation/TestDriveRotationVisualisation.kt +++ b/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/rotation/TestDriveRotationVisualisation.kt @@ -11,7 +11,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.core.ui.context.UiContext -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor import com.bumble.appyx.interactions.core.ui.property.impl.RotationZ import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment diff --git a/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/simple/TestDriveSimpleVisualisation.kt b/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/simple/TestDriveSimpleVisualisation.kt index 9925988f3..7cd5d306c 100644 --- a/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/simple/TestDriveSimpleVisualisation.kt +++ b/appyx-components/internal/test-drive/common/src/commonMain/kotlin/com/bumble/appyx/components/internal/testdrive/ui/simple/TestDriveSimpleVisualisation.kt @@ -26,7 +26,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.UPRIGHT import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragDirection8 -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment import com.bumble.appyx.interactions.core.ui.property.impl.position.PositionAlignment diff --git a/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/fader/BackStackFader.kt b/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/fader/BackStackFader.kt index 875e6f4cc..fc9510fbc 100644 --- a/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/fader/BackStackFader.kt +++ b/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/fader/BackStackFader.kt @@ -3,7 +3,7 @@ package com.bumble.appyx.components.backstack.ui.fader import androidx.compose.animation.core.SpringSpec import com.bumble.appyx.components.backstack.BackStackModel import com.bumble.appyx.interactions.core.ui.context.UiContext -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.Alpha import com.bumble.appyx.interactions.core.ui.state.MatchedTargetUiState import com.bumble.appyx.transitionmodel.BaseVisualisation diff --git a/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/parallax/BackStackParallax.kt b/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/parallax/BackStackParallax.kt index 4e99bf880..d40c85ac2 100644 --- a/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/parallax/BackStackParallax.kt +++ b/appyx-components/stable/backstack/common/src/commonMain/kotlin/com/bumble/appyx/components/backstack/ui/parallax/BackStackParallax.kt @@ -12,7 +12,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragHorizontalDirection -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.Alpha import com.bumble.appyx.interactions.core.ui.property.impl.ColorOverlay import com.bumble.appyx.interactions.core.ui.property.impl.Shadow diff --git a/appyx-components/stable/spotlight/android/src/androidTest/kotlin/com/bumble/appyx/components/spotlight/android/utils/SpotlightUtils.kt b/appyx-components/stable/spotlight/android/src/androidTest/kotlin/com/bumble/appyx/components/spotlight/android/utils/SpotlightUtils.kt index 6bee27d98..cac81bc52 100644 --- a/appyx-components/stable/spotlight/android/src/androidTest/kotlin/com/bumble/appyx/components/spotlight/android/utils/SpotlightUtils.kt +++ b/appyx-components/stable/spotlight/android/src/androidTest/kotlin/com/bumble/appyx/components/spotlight/android/utils/SpotlightUtils.kt @@ -3,14 +3,12 @@ package com.bumble.appyx.components.spotlight.android.utils import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween -import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.unit.dp import com.bumble.appyx.components.spotlight.Spotlight @@ -19,9 +17,8 @@ import com.bumble.appyx.components.spotlight.ui.slider.SpotlightSlider import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup import com.bumble.appyx.interactions.sample.InteractionTarget import com.bumble.appyx.interactions.sample.android.Element -import com.bumble.appyx.interactions.sample.android.SampleChildren +import com.bumble.appyx.interactions.sample.android.SampleAppyxContainer import com.bumble.appyx.interactions.theme.appyx_dark -import com.bumble.appyx.utils.multiplatform.AppyxLogger import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -70,33 +67,19 @@ fun SpotlightUi( modifier: Modifier = Modifier, color: Color = Color.Unspecified ) { - SampleChildren( + SampleAppyxContainer( appyxComponent = spotlight, modifier = modifier .padding( horizontal = 64.dp, vertical = 12.dp ), - element = { elementUiModel -> + elementUi = { element -> Element( color = color, - elementUiModel = elementUiModel, + element = element, contentDescription = - "${SPOTLIGHT_EXPERIMENT_TEST_HELPER}_${elementUiModel.element.id}", - modifier = Modifier - .fillMaxSize() - .pointerInput(elementUiModel.element.id) { - detectDragGestures( - onDrag = { change, dragAmount -> - change.consume() - spotlight.onDrag(dragAmount, this) - }, - onDragEnd = { - AppyxLogger.d("drag", "end") - spotlight.onDragEnd() - } - ) - } + "${SPOTLIGHT_EXPERIMENT_TEST_HELPER}_${element.id}" ) } ) diff --git a/appyx-components/stable/spotlight/common/src/commonMain/kotlin/com/bumble/appyx/components/spotlight/ui/fader/SpotlightFader.kt b/appyx-components/stable/spotlight/common/src/commonMain/kotlin/com/bumble/appyx/components/spotlight/ui/fader/SpotlightFader.kt index be342ced1..3a3d26986 100644 --- a/appyx-components/stable/spotlight/common/src/commonMain/kotlin/com/bumble/appyx/components/spotlight/ui/fader/SpotlightFader.kt +++ b/appyx-components/stable/spotlight/common/src/commonMain/kotlin/com/bumble/appyx/components/spotlight/ui/fader/SpotlightFader.kt @@ -6,7 +6,7 @@ import com.bumble.appyx.components.spotlight.SpotlightModel.State.ElementState.C import com.bumble.appyx.components.spotlight.SpotlightModel.State.ElementState.DESTROYED import com.bumble.appyx.components.spotlight.SpotlightModel.State.ElementState.STANDARD import com.bumble.appyx.interactions.core.ui.context.UiContext -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.Alpha import com.bumble.appyx.interactions.core.ui.state.MatchedTargetUiState import com.bumble.appyx.transitionmodel.BaseVisualisation diff --git a/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/android/SampleChildren.kt b/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/android/SampleChildren.kt index 1974ad3b1..5746830ff 100644 --- a/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/android/SampleChildren.kt +++ b/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/android/SampleChildren.kt @@ -1,13 +1,14 @@ package com.bumble.appyx.interactions.sample.android +import androidx.compose.foundation.layout.BoxScope import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity +import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.Element import com.bumble.appyx.interactions.core.model.BaseAppyxComponent -import com.bumble.appyx.interactions.core.ui.output.ElementUiModel -import com.bumble.appyx.interactions.sample.Children import com.bumble.appyx.interactions.sample.SampleElement import com.bumble.appyx.interactions.sample.colors import kotlin.math.roundToInt @@ -18,35 +19,33 @@ import kotlin.math.roundToInt * For real-life use-cases use the [Children] wrapper directly. */ @Composable -fun SampleChildren( +fun SampleAppyxContainer( appyxComponent: BaseAppyxComponent, modifier: Modifier = Modifier, clipToBounds: Boolean = false, - element: @Composable (ElementUiModel) -> Unit = { - SampleElement(colors = colors, elementUiModel = it) + elementUi: @Composable BoxScope.(Element) -> Unit = { element -> + SampleElement(colors = colors, element = element) }, ) { - Children( + AppyxInteractionsContainer( appyxComponent = appyxComponent, screenWidthPx = (LocalConfiguration.current.screenWidthDp * LocalDensity.current.density).roundToInt(), screenHeightPx = (LocalConfiguration.current.screenHeightDp * LocalDensity.current.density).roundToInt(), modifier = modifier, clipToBounds = clipToBounds, - childWrapper = { elementUiModel -> - element(elementUiModel) - }, + elementUi = elementUi ) } @Composable fun Element( - elementUiModel: ElementUiModel<*>, + element: Element<*>, modifier: Modifier = Modifier, color: Color? = Color.Unspecified, contentDescription: String? = null ) { SampleElement( - elementUiModel = elementUiModel, + element = element, modifier = modifier, colors = colors, color = color, diff --git a/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/testing/Utils.kt b/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/testing/Utils.kt index c2d1191d4..cd109fc1f 100644 --- a/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/testing/Utils.kt +++ b/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/testing/Utils.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.test.junit4.ComposeContentTestRule import com.bumble.appyx.interactions.core.model.BaseAppyxComponent import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup -import com.bumble.appyx.interactions.sample.android.SampleChildren +import com.bumble.appyx.interactions.sample.android.SampleAppyxContainer import com.bumble.appyx.interactions.theme.appyx_dark import kotlin.random.Random @@ -54,7 +54,7 @@ private fun TestChildrenUi( ) { BoxWithConstraints { val padding = this.maxWidth * (1.0f - fraction) / 2 - SampleChildren( + SampleAppyxContainer( modifier = Modifier .align(Alignment.Center) .padding(horizontal = padding) @@ -63,14 +63,15 @@ private fun TestChildrenUi( ), appyxComponent = appyxComponent, clipToBounds = clipToBounds, - ) { + ) { element -> Box( modifier = Modifier .fillMaxSize() ) { Text( - text = "${it.element.interactionTarget}", - modifier = Modifier.align(Alignment.Center), + text = "${element.interactionTarget}", + modifier = Modifier + .align(Alignment.Center), color = Color.White ) } diff --git a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/AppyxInteractionsContainer.kt b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/AppyxInteractionsContainer.kt index d99484062..f27eed8ff 100644 --- a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/AppyxInteractionsContainer.kt +++ b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/AppyxInteractionsContainer.kt @@ -1,6 +1,7 @@ package com.bumble.appyx.interactions.core import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset import androidx.compose.material.Text @@ -8,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.key @@ -48,6 +50,11 @@ import com.bumble.appyx.interactions.core.ui.property.motionPropertyRenderValue private val defaultExtraTouch = 48f.dp +enum class GestureReferencePoint { + Container, + Element +} + @Suppress("LongMethod") @Composable fun AppyxInteractionsContainer( @@ -58,24 +65,20 @@ fun AppyxInteractionsContainer( clipToBounds: Boolean = false, gestureValidator: GestureValidator = defaultValidator, gestureExtraTouchArea: Dp = defaultExtraTouch, - element: @Composable (ElementUiModel) -> Unit = { elementUiModel -> - Box( - modifier = Modifier.fillMaxSize() - .then(elementUiModel.modifier) - ) { - Text( - modifier = Modifier.align(Alignment.Center), - text = "Customise this composable", - ) - } + gestureRelativeTo: GestureReferencePoint = GestureReferencePoint.Container, + elementUi: @Composable BoxScope.(Element) -> Unit = { _ -> + Text( + modifier = Modifier + .align(Alignment.Center), + text = "Customise this composable", + ) }, ) { val density = LocalDensity.current val elementUiModels by appyxComponent.uiModels.collectAsState() val coroutineScope = rememberCoroutineScope() val gestureExtraTouchAreaPx = with(density) { gestureExtraTouchArea.toPx() } - var containerSize by remember { mutableStateOf(IntSize.Zero) } - + val containerSize = remember { mutableStateOf(IntSize.Zero) } val saveableStateHolder = rememberSaveableStateHolder() LaunchedEffect(appyxComponent) { @@ -101,7 +104,7 @@ fun AppyxInteractionsContainer( .fillMaxSize() .then(if (clipToBounds) Modifier.clipToBounds() else Modifier) .onPlaced { - containerSize = it.size + containerSize.value = it.size appyxComponent.updateBounds( TransitionBounds( density = density, @@ -120,71 +123,41 @@ fun AppyxInteractionsContainer( ) { CompositionLocalProvider(LocalBoxScope provides this) { elementUiModels.forEach { elementUiModel -> - val id = elementUiModel.element.id - key(id) { - var transformedBoundingBox by remember(id) { mutableStateOf(Rect.Zero) } - var elementSize by remember(id) { mutableStateOf(IntSize.Zero) } - var offsetCenter by remember(id) { mutableStateOf(Offset.Zero) } - val isVisible by elementUiModel.visibleState.collectAsState() + val isGesturesEnabled = appyxComponent.isGesturesEnabled + + key(elementUiModel.element.id) { + val isVisible by elementUiModel.visibleState.collectAsState() elementUiModel.persistentContainer() + saveableStateHolder.SaveableStateProvider(key = elementUiModel.element) { + if (isVisible) { + CompositionLocalProvider( + LocalMotionProperties provides elementUiModel.motionProperties, + ) { + when { + !isGesturesEnabled -> { + Box(modifier = elementUiModel.modifier) { + elementUi(elementUiModel.element) + } + } - if (isVisible) { - CompositionLocalProvider( - LocalMotionProperties provides elementUiModel.motionProperties - ) { - val elementOffset = - offsetCenter.round() - elementOffset(elementSize, containerSize) - - saveableStateHolder.SaveableStateProvider(key = elementUiModel.element) { - element.invoke( - elementUiModel.copy( - modifier = Modifier - .offset { elementOffset } - .pointerInput(appyxComponent) { - detectDragGesturesOrCancellation( - onDragStart = { position -> - appyxComponent.onStartDrag(position) - }, - onDrag = { change, dragAmount -> - if (gestureValidator.isGestureValid( - change.position, - transformedBoundingBox.translate(-offsetCenter) - ) - ) { - change.consume() - appyxComponent.onDrag( - dragAmount, - density - ) - true - } else { - appyxComponent.onDragEnd() - false - } - }, - onDragEnd = { - appyxComponent.onDragEnd() - }, - ) - } - .offset { -elementOffset } - .then(elementUiModel.modifier) - .onPlaced { - elementSize = it.size - val localCenter = Offset( - it.size.width.toFloat(), - it.size.height.toFloat() - ) / 2f - - transformedBoundingBox = - it.boundsInParent() - .inflate(gestureExtraTouchAreaPx) - offsetCenter = - transformedBoundingBox.center - localCenter - } - ) - ) + gestureRelativeTo == GestureReferencePoint.Element -> + ElementWithGestureTransformedBoundingBox( + appyxComponent = appyxComponent, + containerSize = containerSize, + gestureExtraTouchAreaPx = gestureExtraTouchAreaPx, + gestureValidator = gestureValidator, + elementUiModel = elementUiModel, + elementUi = elementUi + ) + + gestureRelativeTo == GestureReferencePoint.Container -> + ElementWithGesture( + appyxComponent = appyxComponent, + elementUiModel = elementUiModel, + elementUi = elementUi + ) + } } } } @@ -194,17 +167,114 @@ fun AppyxInteractionsContainer( } } +@Composable +private fun ElementWithGesture( + appyxComponent: BaseAppyxComponent, + elementUiModel: ElementUiModel, + elementUi: @Composable BoxScope.(Element) -> Unit +) { + val density = LocalDensity.current + Box(modifier = Modifier + .pointerInput(appyxComponent) { + detectDragGesturesOrCancellation( + onDragStart = { position -> + appyxComponent.onStartDrag(position) + }, + onDrag = { change, dragAmount -> + change.consume() + appyxComponent.onDrag( + dragAmount, + density + ) + true + }, + onDragEnd = { + appyxComponent.onDragEnd() + } + ) + } + .then(elementUiModel.modifier) + ) { + elementUi(elementUiModel.element) + } +} + +@Composable +private fun ElementWithGestureTransformedBoundingBox( + appyxComponent: BaseAppyxComponent, + containerSize: State, + gestureExtraTouchAreaPx: Float, + gestureValidator: GestureValidator, + elementUiModel: ElementUiModel, + elementUi: @Composable BoxScope.(Element) -> Unit +) { + var transformedBoundingBox by remember(elementUiModel.element.id) { mutableStateOf(Rect.Zero) } + var elementSize by remember(elementUiModel.element.id) { mutableStateOf(IntSize.Zero) } + var offsetCenter by remember(elementUiModel.element.id) { mutableStateOf(Offset.Zero) } + val density = LocalDensity.current + val elementOffset = + offsetCenter.round() - elementOffset(elementSize, containerSize) + + Box(modifier = Modifier + .offset { elementOffset } + .pointerInput(appyxComponent) { + detectDragGesturesOrCancellation( + onDragStart = { position -> + appyxComponent.onStartDrag(position) + }, + onDrag = { change, dragAmount -> + if (gestureValidator.isGestureValid( + change.position, + transformedBoundingBox.translate(-offsetCenter) + ) + ) { + change.consume() + appyxComponent.onDrag( + dragAmount, + density + ) + true + } else { + appyxComponent.onDragEnd() + false + } + }, + onDragEnd = { + appyxComponent.onDragEnd() + } + ) + } + .offset { -elementOffset } + .then(elementUiModel.modifier) + .onPlaced { + elementSize = it.size + val localCenter = Offset( + it.size.width.toFloat(), + it.size.height.toFloat() + ) / 2f + + transformedBoundingBox = + it.boundsInParent() + .inflate(gestureExtraTouchAreaPx) + offsetCenter = + transformedBoundingBox.center - localCenter + } + ) { + elementUi(elementUiModel.element) + } +} @Composable fun elementOffset( elementSize: IntSize, - containerSize: IntSize, + containerSize: State, ): IntOffset { - val positionAlignment = motionPropertyRenderValue() + val positionAlignment = + motionPropertyRenderValue() val layoutDirection = LocalLayoutDirection.current val alignmentOffset = positionAlignment?.let { - it.align(elementSize, containerSize, layoutDirection) + it.align(elementSize, containerSize.value, layoutDirection) } ?: IntOffset.Zero return alignmentOffset diff --git a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/model/BaseAppyxComponent.kt b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/model/BaseAppyxComponent.kt index 01e10ceba..0ef3488e6 100644 --- a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/model/BaseAppyxComponent.kt +++ b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/model/BaseAppyxComponent.kt @@ -16,6 +16,7 @@ import com.bumble.appyx.interactions.core.model.transition.Operation import com.bumble.appyx.interactions.core.model.transition.Operation.Mode.IMMEDIATE import com.bumble.appyx.interactions.core.model.transition.TransitionModel import com.bumble.appyx.interactions.core.state.MutableSavedStateMap +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.Visualisation import com.bumble.appyx.interactions.core.ui.context.TransitionBounds import com.bumble.appyx.interactions.core.ui.context.TransitionBoundsAware @@ -23,8 +24,6 @@ import com.bumble.appyx.interactions.core.ui.context.UiContext import com.bumble.appyx.interactions.core.ui.context.UiContextAware import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.GestureSettleConfig -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec -import com.bumble.appyx.interactions.core.ui.helper.DisableAnimations import com.bumble.appyx.interactions.core.ui.output.ElementUiModel import com.bumble.appyx.utils.multiplatform.AppyxLogger import kotlinx.coroutines.CoroutineScope @@ -87,6 +86,8 @@ open class BaseAppyxComponent( defaultAnimationSpec = defaultAnimationSpec, ) + val isGesturesEnabled = _gestureFactory !is GestureFactory.Noop + private val _uiModels: MutableStateFlow>> = MutableStateFlow(emptyList()) val uiModels: StateFlow>> = _uiModels @@ -228,7 +229,7 @@ open class BaseAppyxComponent( ) val animatedSource = animated when { - animatedSource == null || DisableAnimations || disableAnimations -> instant.operation( + animatedSource == null || disableAnimations -> instant.operation( operation ) diff --git a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/Defaults.kt b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/Defaults.kt new file mode 100644 index 000000000..9f077d5c6 --- /dev/null +++ b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/Defaults.kt @@ -0,0 +1,6 @@ +package com.bumble.appyx.interactions.core.ui + +import androidx.compose.animation.core.SpringSpec +import androidx.compose.animation.core.spring + +val DefaultAnimationSpec: SpringSpec = spring() diff --git a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/gesture/GestureSettleConfig.kt b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/gesture/GestureSettleConfig.kt index 110c25585..76286232c 100644 --- a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/gesture/GestureSettleConfig.kt +++ b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/gesture/GestureSettleConfig.kt @@ -2,7 +2,7 @@ package com.bumble.appyx.interactions.core.ui.gesture import androidx.compose.animation.core.AnimationSpec import androidx.compose.runtime.Immutable -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec @Immutable data class GestureSettleConfig( diff --git a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/helper/Gestures.kt b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/helper/Gestures.kt deleted file mode 100644 index ddcbc3e6e..000000000 --- a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/core/ui/helper/Gestures.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.bumble.appyx.interactions.core.ui.helper - -import androidx.compose.animation.core.SpringSpec -import androidx.compose.animation.core.spring -import androidx.compose.foundation.gestures.detectDragGestures -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.composed -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalDensity -import com.bumble.appyx.interactions.core.model.BaseAppyxComponent - -// TODO consider where to keep these - -var DisableAnimations = false - -val DefaultAnimationSpec: SpringSpec = spring() - -@Composable -@Suppress("UnnecessaryComposedModifier", "ModifierComposable") -fun Modifier.gestureModifier( - appyxComponent: BaseAppyxComponent, - key: Any, -) = this.composed { - - val density = LocalDensity.current - - pointerInput(key) { - detectDragGestures( - onDragStart = { position -> appyxComponent.onStartDrag(position) }, - onDrag = { change, dragAmount -> - change.consume() - appyxComponent.onDrag(dragAmount, density) - }, - onDragEnd = { appyxComponent.onDragEnd() } - ) - } -} - diff --git a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/sample/Children.kt b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/sample/Children.kt index 305b6d236..9df8dbba5 100644 --- a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/sample/Children.kt +++ b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/interactions/sample/Children.kt @@ -7,118 +7,16 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.key import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.PointerEventType -import androidx.compose.ui.layout.onPlaced -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.bumble.appyx.interactions.core.model.BaseAppyxComponent -import com.bumble.appyx.interactions.core.modifiers.onPointerEvent -import com.bumble.appyx.interactions.core.ui.LocalBoxScope -import com.bumble.appyx.interactions.core.ui.LocalMotionProperties -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.output.ElementUiModel - - -@Composable -fun Children( - appyxComponent: BaseAppyxComponent, - screenWidthPx: Int, - screenHeightPx: Int, - modifier: Modifier = Modifier, - clipToBounds: Boolean = false, - childContent: @Composable (ElementUiModel) -> Unit = {}, - childWrapper: @Composable (ElementUiModel) -> Unit = { frameModel -> - ChildWrapper(frameModel) { - childContent(frameModel) - } - }, -) { - val density = LocalDensity.current - val elementUiModels by appyxComponent.uiModels.collectAsState() - val coroutineScope = rememberCoroutineScope() - - SideEffect { - appyxComponent.updateContext( - UiContext( - coroutineScope = coroutineScope, - clipToBounds = clipToBounds - ) - ) - } - Box( - modifier = modifier - .fillMaxSize() - .then(if (clipToBounds) Modifier.clipToBounds() else Modifier) - .onPlaced { - appyxComponent.updateBounds( - TransitionBounds( - density = density, - widthPx = it.size.width, - heightPx = it.size.height, - screenWidthPx = screenWidthPx, - screenHeightPx = screenHeightPx - ) - ) - } - .onPointerEvent { - if (it.type == PointerEventType.Release) { - appyxComponent.onRelease() - } - } - ) { - CompositionLocalProvider(LocalBoxScope provides this) { - elementUiModels - .forEach { elementUiModel -> - key(elementUiModel.element.id) { - elementUiModel.persistentContainer() - val isVisible by elementUiModel.visibleState.collectAsState() - if (isVisible) { - CompositionLocalProvider( - LocalMotionProperties provides elementUiModel.motionProperties - ) { - childWrapper.invoke(elementUiModel) - } - } - } - } - } - } -} - -@Composable -fun ChildWrapper( - elementUiModel: ElementUiModel<*>, - modifier: Modifier = Modifier.fillMaxSize(), - contentDescription: String? = null, - content: @Composable () -> Unit -) { - Box( - modifier = Modifier - .then(elementUiModel.modifier) - .then(modifier) - .semantics { - contentDescription?.let { this.contentDescription = it } - } - ) { - content() - } -} +import com.bumble.appyx.interactions.core.Element @Suppress( "MagicNumber", @@ -126,9 +24,9 @@ fun ChildWrapper( ) @Composable fun SampleElement( - elementUiModel: ElementUiModel<*>, + element: Element<*>, colors: List, - modifier: Modifier = Modifier.fillMaxSize(), + modifier: Modifier = Modifier, color: Color? = Color.Unspecified, contentDescription: String? = null ) { @@ -137,11 +35,10 @@ fun SampleElement( } Box( - modifier = Modifier - .then(elementUiModel.modifier) + modifier = modifier + .fillMaxSize() .clip(RoundedCornerShape(5)) .then(if (color == null) Modifier else Modifier.background(backgroundColor)) - .then(modifier) .padding(24.dp) .semantics { contentDescription?.let { this.contentDescription = it } @@ -149,7 +46,7 @@ fun SampleElement( ) { Text( - text = elementUiModel.element.interactionTarget.toString(), + text = element.interactionTarget.toString(), fontSize = 21.sp, color = Color.Black, fontWeight = FontWeight.Bold diff --git a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/transitionmodel/BaseVisualisation.kt b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/transitionmodel/BaseVisualisation.kt index 8883f82fd..79738770a 100644 --- a/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/transitionmodel/BaseVisualisation.kt +++ b/appyx-interactions/common/src/commonMain/kotlin/com/bumble/appyx/transitionmodel/BaseVisualisation.kt @@ -14,7 +14,7 @@ import com.bumble.appyx.interactions.core.model.transition.Update import com.bumble.appyx.interactions.core.ui.Visualisation 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.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.math.lerpFloat import com.bumble.appyx.interactions.core.ui.output.ElementUiModel import com.bumble.appyx.interactions.core.ui.property.impl.GenericFloatProperty diff --git a/appyx-interactions/common/src/commonTest/kotlin/com/bumble/appyx/interactions/core/model/progress/DragProgressControllerTest.kt b/appyx-interactions/common/src/commonTest/kotlin/com/bumble/appyx/interactions/core/model/progress/DragProgressControllerTest.kt index 51b895bac..b5cafca18 100644 --- a/appyx-interactions/common/src/commonTest/kotlin/com/bumble/appyx/interactions/core/model/progress/DragProgressControllerTest.kt +++ b/appyx-interactions/common/src/commonTest/kotlin/com/bumble/appyx/interactions/core/model/progress/DragProgressControllerTest.kt @@ -6,7 +6,7 @@ import com.bumble.appyx.InteractionTarget.Child1 import com.bumble.appyx.InteractionTarget.Child2 import com.bumble.appyx.interactions.core.TestGestures import com.bumble.appyx.interactions.core.TestTransitionModel -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import kotlin.test.Test import kotlin.test.asserter diff --git a/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/AppyxNavigationContainer.kt b/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/AppyxNavigationContainer.kt index e6f9a57ef..1b5609f1e 100644 --- a/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/AppyxNavigationContainer.kt +++ b/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/AppyxNavigationContainer.kt @@ -6,9 +6,10 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.Element +import com.bumble.appyx.interactions.core.GestureReferencePoint import com.bumble.appyx.interactions.core.gesture.GestureValidator import com.bumble.appyx.interactions.core.model.BaseAppyxComponent -import com.bumble.appyx.interactions.core.ui.output.ElementUiModel import com.bumble.appyx.navigation.integration.LocalScreenSize import com.bumble.appyx.navigation.node.LocalNode import com.bumble.appyx.navigation.node.Node @@ -25,29 +26,32 @@ fun AppyxNavigationContainer( clipToBounds: Boolean = false, gestureValidator: GestureValidator = GestureValidator.defaultValidator, gestureExtraTouchArea: Dp = defaultExtraTouch, - decorator: (@Composable ( - child: ChildRenderer, - elementUiModel: ElementUiModel - ) -> Unit) = { child, _ -> child() } + gestureRelativeTo: GestureReferencePoint = GestureReferencePoint.Container, + decorator: @Composable (child: ChildRenderer, element: Element) -> Unit = { child, _ -> + child() + } ) { val density = LocalDensity.current val screenWidthPx = (LocalScreenSize.current.widthDp * density.density).value.roundToInt() val screenHeightPx = (LocalScreenSize.current.heightDp * density.density).value.roundToInt() val node = LocalNode.current as? Node - ?: error("AppyxNavigationContainer called from outside the expected Node tree;" + - "LocalNode.current=${LocalNode.current}") + ?: error( + "AppyxNavigationContainer called from outside the expected Node tree;" + + "LocalNode.current=${LocalNode.current}" + ) - AppyxInteractionsContainer( - appyxComponent, - screenWidthPx, - screenHeightPx, - modifier, - clipToBounds, - gestureValidator, - gestureExtraTouchArea - ) { elementUiModel -> - with(node) { - Child(elementUiModel, decorator) - } + AppyxInteractionsContainer( + appyxComponent = appyxComponent, + screenWidthPx = screenWidthPx, + screenHeightPx = screenHeightPx, + modifier = modifier, + clipToBounds = clipToBounds, + gestureValidator = gestureValidator, + gestureExtraTouchArea = gestureExtraTouchArea, + gestureRelativeTo = gestureRelativeTo + ) { element -> + with(node) { + Child(element, decorator) } + } } diff --git a/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/Child.kt b/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/Child.kt index 5af73466a..cca2acbd4 100644 --- a/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/Child.kt +++ b/appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/navigation/composable/Child.kt @@ -1,46 +1,38 @@ package com.bumble.appyx.navigation.composable -import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import com.bumble.appyx.interactions.core.ui.output.ElementUiModel +import com.bumble.appyx.interactions.core.Element import com.bumble.appyx.navigation.node.Node @Composable fun Node.Child( - elementUiModel: ElementUiModel, - decorator: @Composable (child: ChildRenderer, elementUiModel: ElementUiModel) -> Unit + element: Element, + decorator: @Composable (child: ChildRenderer, element: Element) -> Unit ) { - val navElement = elementUiModel.element - val childEntry = remember(navElement.id) { childOrCreate(navElement) } + val childEntry = remember(element.id) { childOrCreate(element) } decorator( ChildRendererImpl( - node = childEntry.node, - elementUiModel = elementUiModel + node = childEntry.node ), - elementUiModel + element ) } -private class ChildRendererImpl( +private class ChildRendererImpl( private val node: Node<*>, - private val elementUiModel: ElementUiModel ) : ChildRenderer { @Suppress("ComposableNaming") // This wants to be 'Invoke' but that won't work with 'operator'. @Composable override operator fun invoke(modifier: Modifier) { - Box(modifier = elementUiModel.modifier) { - node.Compose(modifier = modifier) - } + node.Compose(modifier = modifier) } @Suppress("ComposableNaming") // This wants to be 'Invoke' but that won't work with 'operator'. @Composable override operator fun invoke() { - Box(modifier = elementUiModel.modifier) { - node.Compose(modifier = Modifier) - } + node.Compose(modifier = Modifier) } } diff --git a/benchmark/benchmark-app/src/main/kotlin/com/bumble/appyx/benchmark/app/mosaic/MosaicComponent.kt b/benchmark/benchmark-app/src/main/kotlin/com/bumble/appyx/benchmark/app/mosaic/MosaicComponent.kt index dd94a53db..43ebd6ce1 100644 --- a/benchmark/benchmark-app/src/main/kotlin/com/bumble/appyx/benchmark/app/mosaic/MosaicComponent.kt +++ b/benchmark/benchmark-app/src/main/kotlin/com/bumble/appyx/benchmark/app/mosaic/MosaicComponent.kt @@ -3,7 +3,7 @@ package com.bumble.appyx.benchmark.app.mosaic import androidx.compose.animation.core.SpringSpec import com.bumble.appyx.benchmark.app.mosaic.MosaicModel.State import com.bumble.appyx.interactions.core.model.BaseAppyxComponent -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.utils.multiplatform.SavedStateMap import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/ModalExperiment.kt b/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/ModalExperiment.kt index 1b4baa631..601249408 100644 --- a/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/ModalExperiment.kt +++ b/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/ModalExperiment.kt @@ -3,7 +3,6 @@ package com.bumble.appyx.interactions.sample import androidx.compose.animation.core.spring import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.Button @@ -90,11 +89,10 @@ fun ModalUi( clipToBounds = false, appyxComponent = modal, modifier = modifier, - element = { elementUiModel -> + elementUi = { element -> Element( color = color, - elementUiModel = elementUiModel, - modifier = Modifier.fillMaxSize() + element = element ) } ) diff --git a/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/SpotlightExperiment.kt b/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/SpotlightExperiment.kt index a4bd5914f..64140ad20 100644 --- a/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/SpotlightExperiment.kt +++ b/demos/appyx-interactions/android/src/main/kotlin/com/bumble/appyx/interactions/sample/SpotlightExperiment.kt @@ -4,19 +4,17 @@ import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import com.bumble.appyx.components.spotlight.Spotlight import com.bumble.appyx.components.spotlight.SpotlightModel @@ -29,9 +27,8 @@ import com.bumble.appyx.components.spotlight.ui.slider.SpotlightSlider import com.bumble.appyx.interactions.core.ui.gesture.GestureSettleConfig import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup import com.bumble.appyx.interactions.sample.android.Element -import com.bumble.appyx.interactions.sample.android.SampleChildren +import com.bumble.appyx.interactions.sample.android.SampleAppyxContainer import com.bumble.appyx.interactions.theme.appyx_dark -import com.bumble.appyx.utils.multiplatform.AppyxLogger import com.bumble.appyx.interactions.sample.InteractionTarget as Target @Composable @@ -65,21 +62,25 @@ fun SpotlightExperiment( Target.Child6, Target.Child7, ) - val model = SpotlightModel( - items = items, - savedStateMap = null, - ) - val spotlight = Spotlight( - model = model, - visualisation = { visualisationType.toVisualisation(it, model.currentState) }, - gestureFactory = { SpotlightSlider.Gestures(it, orientation, reverseOrientation) }, - animationSpec = spring(stiffness = Spring.StiffnessVeryLow / 4), - gestureSettleConfig = GestureSettleConfig( - completionThreshold = 0.2f, - completeGestureSpec = spring(), - revertGestureSpec = spring(), - ), - ) + val model = remember { + SpotlightModel( + items = items, + savedStateMap = null, + ) + } + val spotlight = remember { + Spotlight( + model = model, + visualisation = { visualisationType.toVisualisation(it, model.currentState) }, + gestureFactory = { SpotlightSlider.Gestures(it, orientation, reverseOrientation) }, + animationSpec = spring(stiffness = Spring.StiffnessVeryLow / 4), + gestureSettleConfig = GestureSettleConfig( + completionThreshold = 0.2f, + completeGestureSpec = spring(), + revertGestureSpec = spring(), + ), + ) + } AppyxComponentSetup(spotlight) @@ -130,7 +131,7 @@ fun SpotlightUi( modifier: Modifier = Modifier, color: Color = Color.Unspecified ) { - SampleChildren( + SampleAppyxContainer( clipToBounds = false, appyxComponent = spotlight, modifier = modifier @@ -138,26 +139,12 @@ fun SpotlightUi( horizontal = 64.dp, vertical = 12.dp ), - element = { elementUiModel -> + elementUi = { element -> Element( color = color, - elementUiModel = elementUiModel, + element = element, contentDescription = - "${SPOTLIGHT_EXPERIMENT_TEST_HELPER}_${elementUiModel.element.id}", - modifier = Modifier - .fillMaxSize() - .pointerInput(elementUiModel.element.id) { - detectDragGestures( - onDrag = { change, dragAmount -> - change.consume() - spotlight.onDrag(dragAmount, this) - }, - onDragEnd = { - AppyxLogger.d("drag", "end") - spotlight.onDragEnd() - } - ) - } + "${SPOTLIGHT_EXPERIMENT_TEST_HELPER}_${element.id}" ) } ) diff --git a/demos/appyx-interactions/desktop/src/desktopMain/kotlin/com/bumble/appyx/interactions/widgets/Widgets.kt b/demos/appyx-interactions/desktop/src/desktopMain/kotlin/com/bumble/appyx/interactions/widgets/Widgets.kt index 64bfc2af3..07ec5b46f 100644 --- a/demos/appyx-interactions/desktop/src/desktopMain/kotlin/com/bumble/appyx/interactions/widgets/Widgets.kt +++ b/demos/appyx-interactions/desktop/src/desktopMain/kotlin/com/bumble/appyx/interactions/widgets/Widgets.kt @@ -22,10 +22,10 @@ import com.bumble.appyx.demos.common.widget.CalendarWidget import com.bumble.appyx.demos.common.widget.TimerWidget import com.bumble.appyx.demos.common.widget.WeatherWidget import com.bumble.appyx.interactions.Events +import com.bumble.appyx.interactions.core.Element import com.bumble.appyx.interactions.core.AppyxInteractionsContainer import com.bumble.appyx.interactions.core.ui.gesture.GestureSettleConfig import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup -import com.bumble.appyx.interactions.core.ui.output.ElementUiModel import com.bumble.appyx.interactions.widgets.ui.WidgetsStack3D import kotlinx.coroutines.flow.Flow @@ -104,9 +104,9 @@ private fun WidgetsUi( ), screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, - element = { elementUiModel -> + elementUi = { WidgetTypeElement( - elementUiModel = elementUiModel, + element = it, modifier = Modifier .fillMaxWidth() .requiredHeight(240.dp) @@ -117,33 +117,27 @@ private fun WidgetsUi( @Composable private fun WidgetTypeElement( - elementUiModel: ElementUiModel, + element: Element, modifier: Modifier = Modifier, ) { - when (elementUiModel.element.interactionTarget) { + when (element.interactionTarget) { WidgetsType.Weather -> WeatherWidget( currentTemperature = 22.3f, lowTemperature = 16.7f, highTemperature = 31.4f, painterResource("sky.png"), - modifier = Modifier - .then(elementUiModel.modifier) - .then(modifier) + modifier = modifier ) WidgetsType.Timer -> TimerWidget( - modifier = Modifier - .then(elementUiModel.modifier) - .then(modifier) + modifier = modifier ) WidgetsType.Calendar -> CalendarWidget( - modifier = Modifier - .then(elementUiModel.modifier) - .then(modifier) + modifier = modifier ) } } diff --git a/demos/appyx-interactions/ios/src/iosMain/kotlin/AppyxSample.kt b/demos/appyx-interactions/ios/src/iosMain/kotlin/AppyxSample.kt index 4c834b362..f7f1824a3 100644 --- a/demos/appyx-interactions/ios/src/iosMain/kotlin/AppyxSample.kt +++ b/demos/appyx-interactions/ios/src/iosMain/kotlin/AppyxSample.kt @@ -1,4 +1,4 @@ -import InteractionTarget.Element + import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -19,9 +19,9 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.Element import com.bumble.appyx.interactions.core.model.BaseAppyxComponent import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup -import com.bumble.appyx.interactions.core.ui.output.ElementUiModel import theme.color_primary import theme.md_amber_500 import theme.md_blue_500 @@ -35,6 +35,7 @@ import theme.md_lime_500 import theme.md_pink_500 import theme.md_teal_500 import kotlin.random.Random +import SampleInteractionTarget.Element as SampleInteractionTargetElement @Suppress("UnstableCollections") // actions parameter @Composable @@ -44,10 +45,8 @@ internal fun AppyxSample( appyxComponent: BaseAppyxComponent, actions: Map Unit>, modifier: Modifier = Modifier, - element: @Composable (ElementUiModel) -> Unit = { - ElementUi( - elementUiModel = it, - ) + elementUi: @Composable (Element) -> Unit = { + ElementUi(element = it) } ) { AppyxComponentSetup(appyxComponent) @@ -61,8 +60,8 @@ internal fun AppyxSample( screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, modifier = Modifier.weight(0.9f).clipToBounds() - ) { elementUiModel -> - element(elementUiModel) + ) { + elementUi(it) } Row( horizontalArrangement = Arrangement.SpaceEvenly, @@ -79,17 +78,16 @@ internal fun AppyxSample( } @Composable -internal fun ElementUi( - elementUiModel: ElementUiModel, +internal fun ElementUi( + element: Element, modifier: Modifier = Modifier ) { Box( modifier = modifier .fillMaxSize() - .then(elementUiModel.modifier) .background( - color = when (val target = elementUiModel.element.interactionTarget) { - is Element -> colors.getOrElse(target.idx % colors.size) { Color.Cyan } + color = when (val target = element.interactionTarget) { + is SampleInteractionTargetElement -> colors.getOrElse(target.idx % colors.size) { Color.Cyan } else -> { Color.Cyan } @@ -98,7 +96,7 @@ internal fun ElementUi( ) { Text( modifier = Modifier.align(Alignment.Center), - text = elementUiModel.element.interactionTarget.toString(), + text = element.interactionTarget.toString(), fontSize = 12.sp, color = Color.Black ) @@ -121,8 +119,8 @@ private fun Action( } } -internal sealed class InteractionTarget { - data class Element(val idx: Int = Random.nextInt(1, 100)) : InteractionTarget() { +internal sealed class SampleInteractionTarget { + data class Element(val idx: Int = Random.nextInt(1, 100)) : SampleInteractionTarget() { override fun toString(): String = "Element $idx" } diff --git a/demos/appyx-interactions/ios/src/iosMain/kotlin/BackStackParallaxSample.kt b/demos/appyx-interactions/ios/src/iosMain/kotlin/BackStackParallaxSample.kt index ac2a386cb..5e1de2bef 100644 --- a/demos/appyx-interactions/ios/src/iosMain/kotlin/BackStackParallaxSample.kt +++ b/demos/appyx-interactions/ios/src/iosMain/kotlin/BackStackParallaxSample.kt @@ -1,4 +1,4 @@ -import InteractionTarget.Element +import SampleInteractionTarget.Element import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.runtime.Composable @@ -19,18 +19,20 @@ internal fun BackStackParallaxSample( ) { val coroutineScope = rememberCoroutineScope() val model = remember { - BackStackModel( + BackStackModel( initialTargets = List(1) { Element() }, savedStateMap = null, ) } - val backStack = BackStack( + val backStack = remember { + BackStack( scope = coroutineScope, model = model, visualisation = { BackStackParallax(it) }, gestureFactory = { BackStackParallax.Gestures(it) }, animationSpec = spring(stiffness = Spring.StiffnessVeryLow), ) + } val actions = mapOf( "Pop" to { backStack.pop() }, "Push" to { backStack.push(Element()) } diff --git a/demos/mkdocs/appyx-components/common/src/commonMain/kotlin/com/bumble/appyx/demos/common/AppyxWebSample.kt b/demos/mkdocs/appyx-components/common/src/commonMain/kotlin/com/bumble/appyx/demos/common/AppyxWebSample.kt index 4f625967c..46da9b3ec 100644 --- a/demos/mkdocs/appyx-components/common/src/commonMain/kotlin/com/bumble/appyx/demos/common/AppyxWebSample.kt +++ b/demos/mkdocs/appyx-components/common/src/commonMain/kotlin/com/bumble/appyx/demos/common/AppyxWebSample.kt @@ -24,11 +24,10 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.bumble.appyx.demos.common.InteractionTarget.Element import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.Element import com.bumble.appyx.interactions.core.model.BaseAppyxComponent import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup -import com.bumble.appyx.interactions.core.ui.output.ElementUiModel import kotlin.random.Random sealed class InteractionTarget { @@ -55,9 +54,9 @@ fun AppyxWebSample( actions: Map Unit>, modifier: Modifier = Modifier, childSize: ChildSize = ChildSize.SMALL, - element: @Composable (ElementUiModel) -> Unit = { + child: @Composable (Element) -> Unit = { ModalUi( - elementUiModel = it, + element = it, isChildMaxSize = childSize == ChildSize.MAX ) } @@ -89,8 +88,8 @@ fun AppyxWebSample( appyxComponent = appyxComponent, screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, - ) { elementUiModel -> - element(elementUiModel) + ) { + child(it) } } } @@ -127,7 +126,7 @@ val colors = listOf( @Composable fun ModalUi( - elementUiModel: ElementUiModel, + element: Element, isChildMaxSize: Boolean, modifier: Modifier = Modifier ) { @@ -135,10 +134,9 @@ fun ModalUi( modifier = modifier .fillMaxSize() .padding(if (isChildMaxSize) 0.dp else 8.dp) - .then(elementUiModel.modifier) .background( - color = when (val target = elementUiModel.element.interactionTarget) { - is Element -> colors.getOrElse(target.idx % colors.size) { Color.Cyan } + color = when (val target = element.interactionTarget) { + is com.bumble.appyx.demos.common.InteractionTarget.Element -> colors.getOrElse(target.idx % colors.size) { Color.Cyan } else -> { Color.Cyan } @@ -148,7 +146,7 @@ fun ModalUi( ) { Text( modifier = Modifier.align(Alignment.Center), - text = elementUiModel.element.interactionTarget.toString(), + text = element.interactionTarget.toString(), fontSize = 12.sp, color = Color.White ) diff --git a/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPrediction.kt b/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPrediction.kt index cc37c6b44..c5581944e 100644 --- a/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPrediction.kt +++ b/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPrediction.kt @@ -1,4 +1,5 @@ @file:Suppress("MatchingDeclarationName") + package com.bumble.appyx.demos.dragprediction import androidx.compose.animation.animateColorAsState @@ -195,10 +196,10 @@ fun ModelUi( appyxComponent = testDrive, screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, - ) { elementUiModel -> + modifier = modifier + ) { Box( modifier = Modifier.size(60.dp) - .then(elementUiModel.modifier) ) { Text( modifier = Modifier.align(Alignment.Center), diff --git a/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPredictionVisualisation.kt b/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPredictionVisualisation.kt index 5adbe2577..30383f1cc 100644 --- a/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPredictionVisualisation.kt +++ b/demos/mkdocs/appyx-interactions/gestures/dragprediction/web/src/jsMain/kotlin/com/bumble/appyx/demos/dragprediction/DragPredictionVisualisation.kt @@ -23,7 +23,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.UPLEFT import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragDirection8 -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor import com.bumble.appyx.interactions.core.ui.property.impl.RotationZ import com.bumble.appyx.interactions.core.ui.property.impl.Scale diff --git a/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDrag.kt b/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDrag.kt index 0b6f39781..354cf4289 100644 --- a/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDrag.kt +++ b/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDrag.kt @@ -1,4 +1,5 @@ @file:Suppress("MatchingDeclarationName") + package com.bumble.appyx.demos.incompletedrag import androidx.compose.animation.animateColorAsState @@ -37,6 +38,7 @@ import com.bumble.appyx.components.internal.testdrive.TestDriveModel.State.Eleme import com.bumble.appyx.components.internal.testdrive.operation.next import com.bumble.appyx.demos.incompletedrag.InteractionTarget.Child1 import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.GestureReferencePoint import com.bumble.appyx.interactions.core.model.transition.Operation.Mode.IMMEDIATE import com.bumble.appyx.interactions.core.ui.gesture.GestureSettleConfig import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup @@ -145,12 +147,13 @@ fun ModelUi( appyxComponent = testDrive, screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, + gestureRelativeTo = GestureReferencePoint.Element, + modifier = modifier ) - { elementUiModel -> + { Box( modifier = Modifier .size(60.dp) - .then(elementUiModel.modifier) ) { Text( modifier = Modifier.align(Alignment.Center), diff --git a/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDragVisualisation.kt b/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDragVisualisation.kt index 2fa70ecb2..e190cfe16 100644 --- a/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDragVisualisation.kt +++ b/demos/mkdocs/appyx-interactions/gestures/incompletedrag/web/src/jsMain/kotlin/com/bumble/appyx/demos/incompletedrag/IncompleteDragVisualisation.kt @@ -24,7 +24,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.UPRIGHT import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragDirection8 -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor import com.bumble.appyx.interactions.core.ui.property.impl.RotationZ import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment.Companion.BottomEnd diff --git a/demos/mkdocs/appyx-interactions/interactions/observemp/web/src/jsMain/kotlin/com/bumble/appyx/demos/observemp/ObserveMotionPropertiesSample.kt b/demos/mkdocs/appyx-interactions/interactions/observemp/web/src/jsMain/kotlin/com/bumble/appyx/demos/observemp/ObserveMotionPropertiesSample.kt index 7475dd849..46b3e2629 100644 --- a/demos/mkdocs/appyx-interactions/interactions/observemp/web/src/jsMain/kotlin/com/bumble/appyx/demos/observemp/ObserveMotionPropertiesSample.kt +++ b/demos/mkdocs/appyx-interactions/interactions/observemp/web/src/jsMain/kotlin/com/bumble/appyx/demos/observemp/ObserveMotionPropertiesSample.kt @@ -27,7 +27,7 @@ import com.bumble.appyx.components.spotlight.ui.sliderrotation.SpotlightSliderRo import com.bumble.appyx.demos.common.AppyxWebSample import com.bumble.appyx.demos.common.InteractionTarget import com.bumble.appyx.demos.common.colors -import com.bumble.appyx.interactions.core.ui.output.ElementUiModel +import com.bumble.appyx.interactions.core.Element import com.bumble.appyx.interactions.core.ui.property.impl.RotationY import com.bumble.appyx.interactions.core.ui.property.impl.position.PositionAlignment import com.bumble.appyx.interactions.core.ui.property.motionPropertyRenderValue @@ -75,16 +75,15 @@ fun ObserveMotionPropertiesSample( @Composable fun ModalUi( - elementUiModel: ElementUiModel, + element: Element, isChildMaxSize: Boolean, modifier: Modifier = Modifier ) { Box( modifier = modifier .fillMaxSize(if (isChildMaxSize) 1f else 0.9f) - .then(elementUiModel.modifier) .background( - color = when (val target = elementUiModel.element.interactionTarget) { + color = when (val target = element.interactionTarget) { is com.bumble.appyx.demos.common.InteractionTarget.Element -> colors.getOrElse( target.idx % colors.size ) { Color.Cyan } @@ -102,7 +101,7 @@ fun ModalUi( verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( - text = elementUiModel.element.interactionTarget.toString(), + text = element.interactionTarget.toString(), fontSize = 12.sp, color = Color.White ) diff --git a/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1.kt b/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1.kt index d13c1a929..761111964 100644 --- a/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1.kt +++ b/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1.kt @@ -37,6 +37,7 @@ import com.bumble.appyx.components.internal.testdrive.TestDriveModel.State.Eleme import com.bumble.appyx.components.internal.testdrive.operation.next import com.bumble.appyx.demos.sample1.InteractionTarget.Child1 import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.GestureReferencePoint import com.bumble.appyx.interactions.core.model.transition.Operation.Mode.IMMEDIATE import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup @@ -143,11 +144,11 @@ fun ModelUi( appyxComponent = testDrive, screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, - ) { elementUiModel -> + gestureRelativeTo = GestureReferencePoint.Element + ) { Box( modifier = Modifier .size(60.dp) - .then(elementUiModel.modifier) ) { Text( modifier = Modifier.align(Alignment.Center), diff --git a/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1Visualisation.kt b/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1Visualisation.kt index bffca138e..793baad1b 100644 --- a/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1Visualisation.kt +++ b/demos/mkdocs/appyx-interactions/interactions/sample1/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample1/Sample1Visualisation.kt @@ -24,7 +24,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.UPRIGHT import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragDirection8 -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment.Companion.BottomEnd diff --git a/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2.kt b/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2.kt index 0984c7c02..2e55d8ca8 100644 --- a/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2.kt +++ b/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2.kt @@ -1,4 +1,5 @@ @file:Suppress("MatchingDeclarationName") + package com.bumble.appyx.demos.sample2 import androidx.compose.animation.animateColorAsState @@ -37,6 +38,7 @@ import com.bumble.appyx.components.internal.testdrive.TestDriveModel.State.Eleme import com.bumble.appyx.components.internal.testdrive.operation.next import com.bumble.appyx.demos.sample2.InteractionTarget.Child1 import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.GestureReferencePoint import com.bumble.appyx.interactions.core.model.transition.Operation.Mode.IMMEDIATE import com.bumble.appyx.interactions.core.ui.helper.AppyxComponentSetup @@ -143,11 +145,11 @@ fun ModelUi( appyxComponent = testDrive, screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, - ) { elementUiModel -> + gestureRelativeTo = GestureReferencePoint.Element + ) { Box( modifier = Modifier .size(60.dp) - .then(elementUiModel.modifier) ) { Text( modifier = Modifier.align(Alignment.Center), diff --git a/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2Visualisation.kt b/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2Visualisation.kt index b5fe65ae3..8bb13318a 100644 --- a/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2Visualisation.kt +++ b/demos/mkdocs/appyx-interactions/interactions/sample2/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample2/Sample2Visualisation.kt @@ -24,7 +24,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.UPRIGHT import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragDirection8 -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor import com.bumble.appyx.interactions.core.ui.property.impl.RotationZ import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment diff --git a/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3.kt b/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3.kt index 69891bd62..69f201c47 100644 --- a/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3.kt +++ b/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3.kt @@ -46,6 +46,7 @@ import com.bumble.appyx.components.internal.testdrive.operation.next import com.bumble.appyx.demos.sample3.InteractionTarget.Child1 import com.bumble.appyx.demos.sample3.Sample3Visualisation.Companion.toTargetUiState import com.bumble.appyx.interactions.core.AppyxInteractionsContainer +import com.bumble.appyx.interactions.core.GestureReferencePoint import com.bumble.appyx.interactions.core.model.transition.Keyframes import com.bumble.appyx.interactions.core.model.transition.Operation.Mode.IMMEDIATE import com.bumble.appyx.interactions.core.model.transition.Operation.Mode.KEYFRAME @@ -199,10 +200,11 @@ fun ModelUi( appyxComponent = testDrive, screenWidthPx = screenWidthPx, screenHeightPx = screenHeightPx, - ) { elementUiModel -> + gestureRelativeTo = GestureReferencePoint.Element, + modifier = modifier + ) { Box( modifier = Modifier.size(60.dp) - .then(elementUiModel.modifier) ) { Text( modifier = Modifier.align(Alignment.Center), diff --git a/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3Visualisation.kt b/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3Visualisation.kt index 14c177296..3af8bb9ce 100644 --- a/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3Visualisation.kt +++ b/demos/mkdocs/appyx-interactions/interactions/sample3/web/src/jsMain/kotlin/com/bumble/appyx/demos/sample3/Sample3Visualisation.kt @@ -24,7 +24,7 @@ import com.bumble.appyx.interactions.core.ui.gesture.Drag.Direction8.UPRIGHT import com.bumble.appyx.interactions.core.ui.gesture.Gesture import com.bumble.appyx.interactions.core.ui.gesture.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.dragDirection8 -import com.bumble.appyx.interactions.core.ui.helper.DefaultAnimationSpec +import com.bumble.appyx.interactions.core.ui.DefaultAnimationSpec import com.bumble.appyx.interactions.core.ui.property.impl.BackgroundColor import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment.Companion.BottomEnd import com.bumble.appyx.interactions.core.ui.property.impl.position.BiasAlignment.InsideAlignment.Companion.BottomStart diff --git a/demos/sandbox-appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/demos/sandbox/navigation/node/backstack/BackStackNode.kt b/demos/sandbox-appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/demos/sandbox/navigation/node/backstack/BackStackNode.kt index f79ac7633..9d52e6915 100644 --- a/demos/sandbox-appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/demos/sandbox/navigation/node/backstack/BackStackNode.kt +++ b/demos/sandbox-appyx-navigation/common/src/commonMain/kotlin/com/bumble/appyx/demos/sandbox/navigation/node/backstack/BackStackNode.kt @@ -34,7 +34,6 @@ 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.GestureFactory import com.bumble.appyx.interactions.core.ui.gesture.GestureSettleConfig -import com.bumble.appyx.interactions.core.ui.helper.gestureModifier import com.bumble.appyx.navigation.composable.AppyxNavigationContainer import com.bumble.appyx.navigation.modality.NodeContext import com.bumble.appyx.navigation.node.Node @@ -88,7 +87,6 @@ class BackStackNode( ) .background(backgroundColor) .padding(24.dp) - .gestureModifier(backStack, navTarget.index.toString()) ) { Text( text = navTarget.index.toString(),