• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 com.android.permissioncontroller.wear.permission.components.material2
18 
19 import androidx.compose.foundation.layout.fillMaxWidth
20 import androidx.compose.runtime.Composable
21 import androidx.compose.runtime.remember
22 import androidx.compose.ui.Modifier
23 import androidx.compose.ui.platform.LocalConfiguration
24 import androidx.compose.ui.platform.LocalDensity
25 import androidx.compose.ui.semantics.heading
26 import androidx.compose.ui.semantics.semantics
27 import androidx.compose.ui.text.rememberTextMeasurer
28 import androidx.compose.ui.text.style.TextAlign
29 import androidx.compose.ui.text.style.TextOverflow
30 import androidx.compose.ui.unit.Constraints
31 import androidx.compose.ui.unit.dp
32 import androidx.wear.compose.foundation.lazy.ScalingLazyListScope
33 import androidx.wear.compose.foundation.lazy.ScalingLazyListState
34 import androidx.wear.compose.material.LocalTextStyle
35 import androidx.wear.compose.material.MaterialTheme
36 import androidx.wear.compose.material.Text
37 import androidx.wear.compose.material.dialog.Dialog
38 import com.android.permissioncontroller.wear.permission.components.material2.layout.ScalingLazyColumnDefaults
39 import com.android.permissioncontroller.wear.permission.components.material2.layout.ScalingLazyColumnState
40 import com.android.permissioncontroller.wear.permission.components.material2.layout.rememberColumnState
41 import com.android.permissioncontroller.wear.permission.components.material3.DialogButtonContent
42 import com.android.permissioncontroller.wear.permission.components.material3.WearPermissionIconBuilder
43 
44 /**
45  * This component is an alternative to [AlertContent], providing the following:
46  * - a convenient way of passing a title and a message;
47  * - additional content can be specified between the message and the buttons
48  * - default positive and negative buttons;
49  * - wrapped in a [Dialog];
50  */
51 @Composable
AlertDialognull52 fun AlertDialog(
53     title: String? = null,
54     message: String,
55     positiveButtonContent: DialogButtonContent?,
56     negativeButtonContent: DialogButtonContent?,
57     showDialog: Boolean,
58     modifier: Modifier = Modifier,
59     iconRes: WearPermissionIconBuilder? = null,
60     scalingLazyListState: ScalingLazyListState,
61 ) {
62     Dialog(
63         showDialog = showDialog,
64         onDismissRequest = { negativeButtonContent?.onClick?.invoke() },
65         scrollState = scalingLazyListState,
66         modifier = modifier,
67     ) {
68         AlertContent(
69             title = title,
70             icon = { iconRes?.build() },
71             message = message,
72             positiveButtonContent = positiveButtonContent,
73             negativeButtonContent = negativeButtonContent,
74         )
75     }
76 }
77 
78 @Composable
AlertContentnull79 fun AlertContent(
80     icon: @Composable (() -> Unit)? = null,
81     title: String? = null,
82     message: String? = null,
83     positiveButtonContent: DialogButtonContent?,
84     negativeButtonContent: DialogButtonContent?,
85     state: ScalingLazyColumnState =
86         rememberColumnState(ScalingLazyColumnDefaults.responsive(additionalPaddingAtBottom = 0.dp)),
87     showPositionIndicator: Boolean = true,
88     content: (ScalingLazyListScope.() -> Unit)? = null,
89 ) {
90     val density = LocalDensity.current
91     val maxScreenWidthPx = with(density) { LocalConfiguration.current.screenWidthDp.dp.toPx() }
92 
93     ResponsiveDialogContent(
94         icon = icon,
95         title =
96             title?.let {
97                 {
98                     Text(
99                         modifier = Modifier.fillMaxWidth().semantics() { heading() },
100                         text = it,
101                         color = MaterialTheme.colors.onBackground,
102                         textAlign = TextAlign.Center,
103                         overflow = TextOverflow.Ellipsis,
104                     )
105                 }
106             },
107         message =
108             message?.let {
109                 {
110                     // Should message be start or center aligned?
111                     val textMeasurer = rememberTextMeasurer()
112                     val textStyle = LocalTextStyle.current
113                     val totalPaddingPercentage =
114                         globalHorizontalPadding + messageExtraHorizontalPadding
115                     val lineCount =
116                         remember(it, density, textStyle, textMeasurer) {
117                             textMeasurer
118                                 .measure(
119                                     text = it,
120                                     style = textStyle,
121                                     constraints =
122                                         Constraints(
123                                             // Available width is reduced by responsive dialog
124                                             // horizontal
125                                             // padding.
126                                             maxWidth =
127                                                 (maxScreenWidthPx *
128                                                         (1f - totalPaddingPercentage * 2f / 100f))
129                                                     .toInt()
130                                         ),
131                                 )
132                                 .lineCount
133                         }
134                     val textAlign = if (lineCount <= 3) TextAlign.Center else TextAlign.Start
135                     Text(
136                         modifier = Modifier.fillMaxWidth(),
137                         text = it,
138                         color = MaterialTheme.colors.onBackground,
139                         textAlign = textAlign,
140                     )
141                 }
142             },
143         content = content,
144         positiveButtonContent = positiveButtonContent,
145         negativeButtonContent = negativeButtonContent,
146         state = state,
147         showPositionIndicator = showPositionIndicator,
148     )
149 }
150