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