1 /*
2  * Copyright 2023 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.material3.adaptive.ExperimentalMaterial3AdaptiveApi
20 import androidx.compose.runtime.Immutable
21 import androidx.compose.ui.unit.LayoutDirection
22 
23 /** Represents the horizontal order of panes in a [ThreePaneScaffold] from start to end. */
24 @ExperimentalMaterial3AdaptiveApi
25 @Immutable
26 class ThreePaneScaffoldHorizontalOrder
27 internal constructor(
28     internal val firstPane: ThreePaneScaffoldRole,
29     internal val secondPane: ThreePaneScaffoldRole,
30     internal val thirdPane: ThreePaneScaffoldRole
31 ) : PaneScaffoldHorizontalOrder<ThreePaneScaffoldRole> {
32     init {
<lambda>null33         require(firstPane != secondPane && secondPane != thirdPane && firstPane != thirdPane) {
34             "invalid ThreePaneScaffoldHorizontalOrder($firstPane, $secondPane, $thirdPane)" +
35                 " - panes must be unique"
36         }
37     }
38 
39     override val size = 3
40 
getnull41     operator fun get(index: Int) =
42         when (index) {
43             0 -> firstPane
44             1 -> secondPane
45             2 -> thirdPane
46             else -> throw IndexOutOfBoundsException("Invalid pane index $index")
47         }
48 
indexOfnull49     override fun indexOf(role: ThreePaneScaffoldRole) =
50         when (role) {
51             firstPane -> 0
52             secondPane -> 1
53             thirdPane -> 2
54             else -> -1
55         }
56 
forEachnull57     override fun forEach(action: (ThreePaneScaffoldRole) -> Unit) {
58         action(firstPane)
59         action(secondPane)
60         action(thirdPane)
61     }
62 
forEachIndexednull63     override fun forEachIndexed(action: (Int, ThreePaneScaffoldRole) -> Unit) {
64         action(0, firstPane)
65         action(1, secondPane)
66         action(2, thirdPane)
67     }
68 
forEachIndexedReversednull69     override fun forEachIndexedReversed(action: (Int, ThreePaneScaffoldRole) -> Unit) {
70         action(2, thirdPane)
71         action(1, secondPane)
72         action(0, firstPane)
73     }
74 
equalsnull75     override fun equals(other: Any?): Boolean {
76         if (this === other) return true
77         if (other !is ThreePaneScaffoldHorizontalOrder) return false
78         if (firstPane != other.firstPane) return false
79         if (secondPane != other.secondPane) return false
80         if (thirdPane != other.thirdPane) return false
81         return true
82     }
83 
hashCodenull84     override fun hashCode(): Int {
85         var result = firstPane.hashCode()
86         result = 31 * result + secondPane.hashCode()
87         result = 31 * result + thirdPane.hashCode()
88         return result
89     }
90 }
91 
92 /**
93  * Converts a bidirectional [ThreePaneScaffoldHorizontalOrder] to a left-to-right order.
94  *
95  * @param layoutDirection the current [LayoutDirection]
96  */
97 @ExperimentalMaterial3AdaptiveApi
toLtrOrdernull98 internal fun ThreePaneScaffoldHorizontalOrder.toLtrOrder(
99     layoutDirection: LayoutDirection
100 ): ThreePaneScaffoldHorizontalOrder {
101     return if (layoutDirection == LayoutDirection.Rtl) {
102         ThreePaneScaffoldHorizontalOrder(thirdPane, secondPane, firstPane)
103     } else {
104         this
105     }
106 }
107 
108 /** The set of the available pane roles of [ThreePaneScaffold]. */
109 enum class ThreePaneScaffoldRole {
110     /**
111      * The primary pane of [ThreePaneScaffold]. It is supposed to have the highest priority during
112      * layout adaptation and usually contains the most important content of the screen, like content
113      * details in a list-detail settings.
114      */
115     Primary,
116 
117     /**
118      * The secondary pane of [ThreePaneScaffold]. It is supposed to have the second highest priority
119      * during layout adaptation and usually contains the supplement content of the screen, like
120      * content list in a list-detail settings.
121      */
122     Secondary,
123 
124     /**
125      * The tertiary pane of [ThreePaneScaffold]. It is supposed to have the lowest priority during
126      * layout adaptation and usually contains the additional info which will only be shown under
127      * user interaction.
128      */
129     Tertiary
130 }
131