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.credentialmanager.common.ui 18 19 import androidx.compose.foundation.layout.Box 20 import androidx.compose.foundation.layout.BoxWithConstraints 21 import androidx.compose.foundation.layout.Row 22 import androidx.compose.foundation.layout.fillMaxSize 23 import androidx.compose.foundation.layout.padding 24 import androidx.compose.foundation.layout.wrapContentSize 25 import androidx.compose.material.icons.Icons 26 import androidx.compose.material.icons.filled.Close 27 import androidx.compose.material3.Card 28 import androidx.compose.material3.CardDefaults 29 import androidx.compose.material3.Icon 30 import androidx.compose.material3.IconButton 31 import androidx.compose.material3.MaterialTheme 32 import androidx.compose.runtime.Composable 33 import androidx.compose.runtime.LaunchedEffect 34 import androidx.compose.ui.Alignment 35 import androidx.compose.ui.Modifier 36 import androidx.compose.ui.graphics.Color 37 import androidx.compose.ui.platform.LocalAccessibilityManager 38 import androidx.compose.ui.res.stringResource 39 import androidx.compose.ui.unit.dp 40 import com.android.compose.rememberSystemUiController 41 import com.android.credentialmanager.R 42 import com.android.credentialmanager.common.material.Scrim 43 import com.android.credentialmanager.ui.theme.Shapes 44 import kotlinx.coroutines.delay 45 46 @Composable 47 fun Snackbar( 48 contentText: String, 49 action: (@Composable () -> Unit)? = null, 50 onDismiss: () -> Unit, 51 dismissOnTimeout: Boolean = false, 52 ) { 53 val sysUiController = rememberSystemUiController() 54 setTransparentSystemBarsColor(sysUiController) 55 BoxWithConstraints { 56 Box(Modifier.fillMaxSize()) { 57 Scrim( 58 color = Color.Transparent, 59 onDismiss = onDismiss, 60 visible = true 61 ) 62 } 63 Box( 64 modifier = Modifier 65 .align(Alignment.BottomCenter).wrapContentSize().padding(bottom = 18.dp) 66 ) { 67 Card( 68 shape = Shapes.medium, 69 modifier = Modifier.wrapContentSize(), 70 colors = CardDefaults.cardColors( 71 containerColor = MaterialTheme.colorScheme.inverseSurface, 72 ) 73 ) { 74 Row( 75 modifier = Modifier.wrapContentSize(), 76 verticalAlignment = Alignment.CenterVertically, 77 ) { 78 SnackbarContentText(contentText, modifier = Modifier.padding( 79 top = 18.dp, bottom = 18.dp, start = 24.dp, 80 )) 81 if (action != null) { 82 action() 83 } 84 IconButton(onClick = onDismiss, modifier = Modifier.padding( 85 top = 4.dp, bottom = 4.dp, start = 2.dp, end = 10.dp, 86 )) { 87 Icon( 88 Icons.Filled.Close, 89 contentDescription = stringResource( 90 R.string.accessibility_snackbar_dismiss 91 ), 92 tint = MaterialTheme.colorScheme.inverseOnSurface, 93 ) 94 } 95 } 96 } 97 } 98 } 99 val accessibilityManager = LocalAccessibilityManager.current 100 LaunchedEffect(true) { 101 if (dismissOnTimeout) { 102 // Same as SnackbarDuration.Short 103 val originalDuration = 4000L 104 val duration = if (accessibilityManager == null) originalDuration else 105 accessibilityManager.calculateRecommendedTimeoutMillis( 106 originalDuration, 107 containsIcons = true, 108 containsText = true, 109 containsControls = action != null, 110 ) 111 delay(duration) 112 onDismiss() 113 } 114 } 115 }