Handle different window sizes.
Bug: 265887886 Test: manual Change-Id: I2e4c33a0a601859ab7871ab449d1b24f3cb43609
This commit is contained in:
@@ -64,7 +64,7 @@ class CredentialManagerRepo(
|
||||
requestInfo = intent.extras?.getParcelable(
|
||||
RequestInfo.EXTRA_REQUEST_INFO,
|
||||
RequestInfo::class.java
|
||||
) ?: testCreatePasswordRequestInfo()
|
||||
) ?: testGetRequestInfo()
|
||||
|
||||
providerEnabledList = when (requestInfo.type) {
|
||||
RequestInfo.TYPE_CREATE ->
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -40,6 +41,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
@@ -131,7 +133,7 @@ class ModalBottomSheetState(
|
||||
if (isSkipHalfExpanded) {
|
||||
require(initialValue != HalfExpanded) {
|
||||
"The initial value must not be set to HalfExpanded if skipHalfExpanded is set to" +
|
||||
" true."
|
||||
" true."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,10 +211,10 @@ class ModalBottomSheetState(
|
||||
message = "Please specify the skipHalfExpanded parameter",
|
||||
replaceWith = ReplaceWith(
|
||||
"ModalBottomSheetState.Saver(" +
|
||||
"animationSpec = animationSpec," +
|
||||
"skipHalfExpanded = ," +
|
||||
"confirmStateChange = confirmStateChange" +
|
||||
")"
|
||||
"animationSpec = animationSpec," +
|
||||
"skipHalfExpanded = ," +
|
||||
"confirmStateChange = confirmStateChange" +
|
||||
")"
|
||||
)
|
||||
)
|
||||
fun Saver(
|
||||
@@ -339,55 +341,77 @@ fun ModalBottomSheetLayout(
|
||||
visible = sheetState.targetValue != Hidden
|
||||
)
|
||||
}
|
||||
Surface(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.nestedScroll(sheetState.nestedScrollConnection)
|
||||
.offset {
|
||||
val y = if (sheetState.anchors.isEmpty()) {
|
||||
// if we don't know our anchors yet, render the sheet as hidden
|
||||
fullHeight.roundToInt()
|
||||
} else {
|
||||
// if we do know our anchors, respect them
|
||||
sheetState.offset.value.roundToInt()
|
||||
}
|
||||
IntOffset(0, y)
|
||||
}
|
||||
.bottomSheetSwipeable(sheetState, fullHeight, sheetHeightState)
|
||||
.onGloballyPositioned {
|
||||
sheetHeightState.value = it.size.height.toFloat()
|
||||
}
|
||||
.semantics {
|
||||
if (sheetState.isVisible) {
|
||||
dismiss {
|
||||
if (sheetState.confirmStateChange(Hidden)) {
|
||||
scope.launch { sheetState.hide() }
|
||||
}
|
||||
true
|
||||
}
|
||||
if (sheetState.currentValue == HalfExpanded) {
|
||||
expand {
|
||||
if (sheetState.confirmStateChange(Expanded)) {
|
||||
scope.launch { sheetState.expand() }
|
||||
}
|
||||
true
|
||||
}
|
||||
} else if (sheetState.hasHalfExpandedState) {
|
||||
collapse {
|
||||
if (sheetState.confirmStateChange(HalfExpanded)) {
|
||||
scope.launch { sheetState.halfExpand() }
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
shape = sheetShape,
|
||||
shadowElevation = sheetElevation,
|
||||
color = sheetBackgroundColor,
|
||||
contentColor = sheetContentColor
|
||||
|
||||
// For large screen, allow enough horizontal scrim space.
|
||||
// Manually calculate the > compact width due to lack of corresponding jetpack dependency.
|
||||
val maxSheetContentWidth: Dp =
|
||||
if (maxWidth >= ModalBottomSheetDefaults.MaxCompactWidth &&
|
||||
maxWidth <= ModalBottomSheetDefaults.MaxCompactWidth +
|
||||
ModalBottomSheetDefaults.StartPadding + ModalBottomSheetDefaults.EndPadding
|
||||
)
|
||||
(maxWidth - ModalBottomSheetDefaults.StartPadding -
|
||||
ModalBottomSheetDefaults.EndPadding)
|
||||
else ModalBottomSheetDefaults.MaxSheetWidth
|
||||
val maxSheetContentHeight = maxHeight - ModalBottomSheetDefaults.MinScrimHeight
|
||||
Box(
|
||||
Modifier.sizeIn(
|
||||
maxWidth = maxSheetContentWidth,
|
||||
// Allow enough vertical scrim space.
|
||||
maxHeight = maxSheetContentHeight
|
||||
).align(Alignment.TopCenter)
|
||||
) {
|
||||
Column(content = sheetContent)
|
||||
Surface(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.nestedScroll(sheetState.nestedScrollConnection)
|
||||
.offset {
|
||||
val y = if (sheetState.anchors.isEmpty()) {
|
||||
// if we don't know our anchors yet, render the sheet as hidden
|
||||
fullHeight.roundToInt()
|
||||
} else {
|
||||
// if we do know our anchors, respect them
|
||||
sheetState.offset.value.roundToInt()
|
||||
}
|
||||
IntOffset(0, y)
|
||||
}
|
||||
.bottomSheetSwipeable(sheetState, fullHeight, sheetHeightState)
|
||||
.onGloballyPositioned {
|
||||
sheetHeightState.value = it.size.height.toFloat()
|
||||
}
|
||||
.semantics {
|
||||
if (sheetState.isVisible) {
|
||||
dismiss {
|
||||
if (sheetState.confirmStateChange(Hidden)) {
|
||||
scope.launch { sheetState.hide() }
|
||||
}
|
||||
true
|
||||
}
|
||||
if (sheetState.currentValue == HalfExpanded) {
|
||||
expand {
|
||||
if (sheetState.confirmStateChange(Expanded)) {
|
||||
scope.launch { sheetState.expand() }
|
||||
}
|
||||
true
|
||||
}
|
||||
} else if (sheetState.hasHalfExpandedState) {
|
||||
collapse {
|
||||
if (sheetState.confirmStateChange(HalfExpanded)) {
|
||||
scope.launch { sheetState.halfExpand() }
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
shape = sheetShape,
|
||||
shadowElevation = sheetElevation,
|
||||
color = sheetBackgroundColor,
|
||||
contentColor = sheetContentColor
|
||||
) {
|
||||
Column(
|
||||
content = sheetContent
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,6 +489,11 @@ private fun Scrim(
|
||||
* Contains useful Defaults for [ModalBottomSheetLayout].
|
||||
*/
|
||||
object ModalBottomSheetDefaults {
|
||||
val MaxCompactWidth = 600.dp
|
||||
val MaxSheetWidth = 640.dp
|
||||
val MinScrimHeight = 56.dp
|
||||
val StartPadding = 56.dp
|
||||
val EndPadding = 56.dp
|
||||
|
||||
/**
|
||||
* The default elevation used by [ModalBottomSheetLayout].
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.credentialmanager.common.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.android.credentialmanager.common.material.ModalBottomSheetLayout
|
||||
import com.android.credentialmanager.common.material.ModalBottomSheetValue
|
||||
import com.android.credentialmanager.common.material.rememberModalBottomSheetState
|
||||
import com.android.credentialmanager.ui.theme.EntryShape
|
||||
|
||||
/** Draws a modal bottom sheet with the same styles and effects shared by various flows. */
|
||||
@Composable
|
||||
fun ModalBottomSheet(
|
||||
sheetContent: @Composable ColumnScope.() -> Unit,
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
val state = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Expanded,
|
||||
skipHalfExpanded = true
|
||||
)
|
||||
ModalBottomSheetLayout(
|
||||
sheetBackgroundColor = MaterialTheme.colorScheme.surface,
|
||||
modifier = Modifier.background(Color.Transparent),
|
||||
sheetState = state,
|
||||
sheetContent = sheetContent,
|
||||
scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
|
||||
sheetShape = EntryShape.TopRoundedCorner,
|
||||
) {}
|
||||
LaunchedEffect(state.currentValue) {
|
||||
if (state.currentValue == ModalBottomSheetValue.Hidden) {
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,9 @@ package com.android.credentialmanager.common.ui
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -30,7 +30,6 @@ import androidx.compose.ui.graphics.Shape
|
||||
* By default the card is filled with surfaceVariant color. This container card instead fills the
|
||||
* background color with surface corlor.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ContainerCard(
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -39,7 +38,7 @@ fun ContainerCard(
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = shape,
|
||||
border = border,
|
||||
colors = CardDefaults.cardColors(
|
||||
|
||||
@@ -45,18 +45,15 @@ import androidx.core.graphics.drawable.toBitmap
|
||||
import com.android.credentialmanager.R
|
||||
import com.android.credentialmanager.common.CredentialType
|
||||
import com.android.credentialmanager.common.ProviderActivityState
|
||||
import com.android.credentialmanager.common.material.ModalBottomSheetLayout
|
||||
import com.android.credentialmanager.common.material.ModalBottomSheetValue
|
||||
import com.android.credentialmanager.common.material.rememberModalBottomSheetState
|
||||
import com.android.credentialmanager.common.ui.ActionButton
|
||||
import com.android.credentialmanager.common.ui.ConfirmButton
|
||||
import com.android.credentialmanager.common.ui.Entry
|
||||
import com.android.credentialmanager.common.ui.ModalBottomSheet
|
||||
import com.android.credentialmanager.common.ui.TextOnSurface
|
||||
import com.android.credentialmanager.common.ui.TextSecondary
|
||||
import com.android.credentialmanager.common.ui.TextOnSurfaceVariant
|
||||
import com.android.credentialmanager.common.ui.ContainerCard
|
||||
import com.android.credentialmanager.common.ui.ToggleVisibilityButton
|
||||
import com.android.credentialmanager.ui.theme.EntryShape
|
||||
import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -65,13 +62,7 @@ fun CreateCredentialScreen(
|
||||
viewModel: CreateCredentialViewModel,
|
||||
providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
|
||||
) {
|
||||
val state = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Expanded,
|
||||
skipHalfExpanded = true
|
||||
)
|
||||
ModalBottomSheetLayout(
|
||||
sheetBackgroundColor = MaterialTheme.colorScheme.surface,
|
||||
sheetState = state,
|
||||
ModalBottomSheet(
|
||||
sheetContent = {
|
||||
val uiState = viewModel.uiState
|
||||
// Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
|
||||
@@ -153,14 +144,8 @@ fun CreateCredentialScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
|
||||
sheetShape = EntryShape.TopRoundedCorner,
|
||||
) {}
|
||||
LaunchedEffect(state.currentValue) {
|
||||
if (state.currentValue == ModalBottomSheetValue.Hidden) {
|
||||
viewModel.onCancel()
|
||||
}
|
||||
}
|
||||
onDismiss = viewModel::onCancel
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
@@ -22,7 +22,6 @@ import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.IntentSenderRequest
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -60,12 +59,10 @@ import androidx.core.graphics.drawable.toBitmap
|
||||
import com.android.credentialmanager.R
|
||||
import com.android.credentialmanager.common.CredentialType
|
||||
import com.android.credentialmanager.common.ProviderActivityState
|
||||
import com.android.credentialmanager.common.material.ModalBottomSheetLayout
|
||||
import com.android.credentialmanager.common.material.ModalBottomSheetValue
|
||||
import com.android.credentialmanager.common.material.rememberModalBottomSheetState
|
||||
import com.android.credentialmanager.common.ui.ActionButton
|
||||
import com.android.credentialmanager.common.ui.ConfirmButton
|
||||
import com.android.credentialmanager.common.ui.Entry
|
||||
import com.android.credentialmanager.common.ui.ModalBottomSheet
|
||||
import com.android.credentialmanager.common.ui.TextOnSurface
|
||||
import com.android.credentialmanager.common.ui.TextSecondary
|
||||
import com.android.credentialmanager.common.ui.TextOnSurfaceVariant
|
||||
@@ -79,16 +76,9 @@ fun GetCredentialScreen(
|
||||
viewModel: GetCredentialViewModel,
|
||||
providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
|
||||
) {
|
||||
val state = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Expanded,
|
||||
skipHalfExpanded = true
|
||||
)
|
||||
val uiState = viewModel.uiState
|
||||
if (uiState.currentScreenState != GetScreenState.REMOTE_ONLY) {
|
||||
ModalBottomSheetLayout(
|
||||
sheetBackgroundColor = MaterialTheme.colorScheme.surface,
|
||||
modifier = Modifier.background(Color.Transparent),
|
||||
sheetState = state,
|
||||
ModalBottomSheet(
|
||||
sheetContent = {
|
||||
// Hide the sheet content as opposed to the whole bottom sheet to maintain the scrim
|
||||
// background color even when the content should be hidden while waiting for
|
||||
@@ -128,14 +118,8 @@ fun GetCredentialScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
|
||||
sheetShape = EntryShape.TopRoundedCorner,
|
||||
) {}
|
||||
LaunchedEffect(state.currentValue) {
|
||||
if (state.currentValue == ModalBottomSheetValue.Hidden) {
|
||||
viewModel.onCancel()
|
||||
}
|
||||
}
|
||||
onDismiss = viewModel::onCancel,
|
||||
)
|
||||
} else {
|
||||
SnackBarScreen(
|
||||
onClick = viewModel::onMoreOptionOnSnackBarSelected,
|
||||
|
||||
Reference in New Issue
Block a user