1 /*
<lambda>null2 * Copyright 2024 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 androidx.compose.material3.adaptive.layout
18
19 import androidx.compose.animation.core.Transition
20 import androidx.compose.foundation.gestures.Orientation
21 import androidx.compose.foundation.gestures.draggable
22 import androidx.compose.foundation.interaction.MutableInteractionSource
23 import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
24 import androidx.compose.runtime.Composable
25 import androidx.compose.runtime.getValue
26 import androidx.compose.runtime.mutableStateOf
27 import androidx.compose.runtime.remember
28 import androidx.compose.runtime.saveable.SaveableStateHolder
29 import androidx.compose.runtime.setValue
30 import androidx.compose.ui.Modifier
31 import androidx.compose.ui.layout.LookaheadScope
32 import androidx.compose.ui.semantics.SemanticsPropertyReceiver
33 import androidx.compose.ui.semantics.semantics
34 import androidx.compose.ui.unit.Dp
35
36 /** Scope for the panes of [ThreePaneScaffold]. */
37 @ExperimentalMaterial3AdaptiveApi
38 sealed interface ThreePaneScaffoldScope :
39 ExtendedPaneScaffoldScope<ThreePaneScaffoldRole, ThreePaneScaffoldValue>
40
41 /** Scope for the panes of [ThreePaneScaffold]. */
42 @ExperimentalMaterial3AdaptiveApi
43 sealed interface ThreePaneScaffoldPaneScope :
44 ThreePaneScaffoldScope,
45 ExtendedPaneScaffoldPaneScope<ThreePaneScaffoldRole, ThreePaneScaffoldValue>
46
47 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
48 internal class ThreePaneScaffoldScopeImpl(
49 transitionScope: PaneScaffoldTransitionScope<ThreePaneScaffoldRole, ThreePaneScaffoldValue>,
50 lookaheadScope: LookaheadScope,
51 saveableStateHolder: SaveableStateHolder,
52 ) :
53 ThreePaneScaffoldScope,
54 PaneScaffoldTransitionScope<ThreePaneScaffoldRole, ThreePaneScaffoldValue> by transitionScope,
55 LookaheadScope by lookaheadScope,
56 PaneScaffoldScopeImpl(saveableStateHolder) {
57
58 @ExperimentalMaterial3AdaptiveApi
59 override fun Modifier.paneExpansionDraggable(
60 state: PaneExpansionState,
61 minTouchTargetSize: Dp,
62 interactionSource: MutableInteractionSource,
63 semanticsProperties: (SemanticsPropertyReceiver.() -> Unit)
64 ): Modifier =
65 this.draggable(
66 state = state.draggableState,
67 orientation = Orientation.Horizontal,
68 interactionSource = interactionSource,
69 onDragStopped = { velocity -> state.settleToAnchorIfNeeded(velocity) }
70 )
71 .semanticsAction(semanticsProperties, interactionSource)
72 .systemGestureExclusion()
73 .animateWithFading(
74 enabled = true,
75 animateFraction = { motionProgress },
76 lookaheadScope = this@ThreePaneScaffoldScopeImpl
77 )
78 .semantics(mergeDescendants = true, properties = semanticsProperties)
79 .then(MinTouchTargetSizeElement(minTouchTargetSize))
80 }
81
82 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
83 @Composable
rememberThreePaneScaffoldPaneScopenull84 internal fun rememberThreePaneScaffoldPaneScope(
85 paneRole: ThreePaneScaffoldRole,
86 scaffoldScope: ThreePaneScaffoldScope,
87 paneMotion: PaneMotion
88 ): ThreePaneScaffoldPaneScope =
89 remember(scaffoldScope) { ThreePaneScaffoldPaneScopeImpl(paneRole, scaffoldScope) }
<lambda>null90 .apply { this.paneMotion = paneMotion }
91
92 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
93 internal class ThreePaneScaffoldPaneScopeImpl(
94 override val paneRole: ThreePaneScaffoldRole,
95 scaffoldScope: ThreePaneScaffoldScope,
<lambda>null96 ) : ThreePaneScaffoldPaneScope, ThreePaneScaffoldScope by scaffoldScope {
97 override var paneMotion: PaneMotion by mutableStateOf(PaneMotion.ExitToLeft)
98 // TODO(conradchen): Remove this when it goes to public API of PaneScaffoldScope
99 val saveableStateHolder = (scaffoldScope as ThreePaneScaffoldScopeImpl).saveableStateHolder
100 }
101
102 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
103 internal class ThreePaneScaffoldTransitionScopeImpl(
104 override val motionDataProvider: PaneScaffoldMotionDataProvider<ThreePaneScaffoldRole>
105 ) : PaneScaffoldTransitionScope<ThreePaneScaffoldRole, ThreePaneScaffoldValue> {
106 override val motionProgress: Float
107 get() =
108 if (transitionState.currentState == transitionState.targetState) {
109 1f
110 } else {
111 transitionState.progressFraction
112 }
113
114 override lateinit var scaffoldStateTransition: Transition<ThreePaneScaffoldValue>
115 lateinit var transitionState: ThreePaneScaffoldState
116 }
117