1 /*
2 * Copyright (C) 2025 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.mechanics.demo.staging
18
19 import androidx.compose.runtime.Composable
20 import androidx.compose.runtime.LaunchedEffect
21 import androidx.compose.runtime.SideEffect
22 import androidx.compose.runtime.remember
23 import androidx.compose.ui.platform.LocalViewConfiguration
24 import com.android.mechanics.DistanceGestureContext
25 import com.android.mechanics.GestureContext
26 import com.android.mechanics.MotionValue
27 import com.android.mechanics.spec.InputDirection
28 import com.android.mechanics.spec.MotionSpec
29
30 @Composable
rememberMotionValuenull31 fun rememberMotionValue(
32 input: () -> Float,
33 spec: () -> MotionSpec,
34 gestureContext: GestureContext,
35 stableThreshold: Float = 0.01f,
36 label: String? = null,
37 ): MotionValue {
38 val motionValue =
39 remember(input) {
40 MotionValue(
41 input,
42 gestureContext,
43 initialSpec = spec(),
44 label = label,
45 stableThreshold = stableThreshold,
46 )
47 }
48
49 val currentSpec = spec()
50 SideEffect {
51 // New spec is intentionally only applied after recomposition.
52 motionValue.spec = currentSpec
53 }
54
55 LaunchedEffect(motionValue) { motionValue.keepRunning() }
56 return motionValue
57 }
58
59 @Composable
rememberDerivedMotionValuenull60 fun rememberDerivedMotionValue(
61 input: MotionValue,
62 spec: () -> MotionSpec,
63 stableThreshold: Float = 0.01f,
64 label: String? = null,
65 ): MotionValue {
66 val motionValue =
67 remember(input) {
68 MotionValue.createDerived(
69 input,
70 initialSpec = spec(),
71 label = label,
72 stableThreshold = stableThreshold,
73 )
74 }
75
76 val currentSpec = spec()
77 SideEffect {
78 // New spec is intentionally only applied after recomposition.
79 motionValue.spec = currentSpec
80 }
81
82 LaunchedEffect(motionValue) { motionValue.keepRunning() }
83 return motionValue
84 }
85
86 @Composable
rememberDistanceGestureContextnull87 fun rememberDistanceGestureContext(
88 initDistance: Float = 0f,
89 initialDirection: InputDirection = InputDirection.Max,
90 ): DistanceGestureContext {
91 val touchSlop = LocalViewConfiguration.current.touchSlop
92 val gestureContext = remember {
93 DistanceGestureContext(initDistance, initialDirection, touchSlop)
94 }
95
96 return gestureContext
97 }
98