From 8eb408b140199bccde4b5978990ed6ac5aa8b6cc Mon Sep 17 00:00:00 2001 From: David Perez Date: Tue, 15 Oct 2024 16:13:29 -0500 Subject: [PATCH] Pin the segmented control to toolbar in AddSendScreen (#4093) --- .../components/appbar/BitwardenTopAppBar.kt | 31 +- .../feature/send/addsend/AddSendContent.kt | 315 +++++++++--------- .../feature/send/addsend/AddSendScreen.kt | 3 + .../feature/send/addsend/AddSendScreenTest.kt | 2 - 4 files changed, 190 insertions(+), 161 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/appbar/BitwardenTopAppBar.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/appbar/BitwardenTopAppBar.kt index a1f426bbf..8abd9f4bf 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/appbar/BitwardenTopAppBar.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/appbar/BitwardenTopAppBar.kt @@ -21,10 +21,12 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.x8bit.bitwarden.R +import com.x8bit.bitwarden.ui.platform.base.util.bottomDivider import com.x8bit.bitwarden.ui.platform.base.util.mirrorIfRtl import com.x8bit.bitwarden.ui.platform.base.util.scrolledContainerBottomDivider import com.x8bit.bitwarden.ui.platform.components.appbar.color.bitwardenTopAppBarColors import com.x8bit.bitwarden.ui.platform.components.button.BitwardenStandardIconButton +import com.x8bit.bitwarden.ui.platform.components.model.TopAppBarDividerStyle import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme @@ -47,6 +49,7 @@ fun BitwardenTopAppBar( navigationIconContentDescription: String, onNavigationIconClick: () -> Unit, modifier: Modifier = Modifier, + dividerStyle: TopAppBarDividerStyle = TopAppBarDividerStyle.ON_SCROLL, actions: @Composable RowScope.() -> Unit = { }, ) { BitwardenTopAppBar( @@ -58,6 +61,7 @@ fun BitwardenTopAppBar( onNavigationIconClick = onNavigationIconClick, ), modifier = modifier, + dividerStyle = dividerStyle, actions = actions, ) } @@ -82,6 +86,7 @@ fun BitwardenTopAppBar( scrollBehavior: TopAppBarScrollBehavior, navigationIcon: NavigationIcon?, modifier: Modifier = Modifier, + dividerStyle: TopAppBarDividerStyle = TopAppBarDividerStyle.ON_SCROLL, actions: @Composable RowScope.() -> Unit = {}, ) { var titleTextHasOverflow by remember { @@ -102,6 +107,24 @@ fun BitwardenTopAppBar( } } } + val customModifier = modifier + .testTag(tag = "HeaderBarComponent") + .scrolledContainerBottomDivider( + topAppBarScrollBehavior = scrollBehavior, + enabled = when (dividerStyle) { + TopAppBarDividerStyle.NONE -> false + TopAppBarDividerStyle.STATIC -> false + TopAppBarDividerStyle.ON_SCROLL -> true + }, + ) + .bottomDivider( + enabled = when (dividerStyle) { + TopAppBarDividerStyle.NONE -> false + TopAppBarDividerStyle.STATIC -> true + TopAppBarDividerStyle.ON_SCROLL -> false + }, + thickness = (0.5).dp, + ) if (titleTextHasOverflow) { MediumTopAppBar( @@ -120,9 +143,7 @@ fun BitwardenTopAppBar( modifier = Modifier.testTag(tag = "PageTitleLabel"), ) }, - modifier = modifier - .testTag(tag = "HeaderBarComponent") - .scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior), + modifier = customModifier, actions = actions, ) } else { @@ -144,9 +165,7 @@ fun BitwardenTopAppBar( }, ) }, - modifier = modifier - .testTag(tag = "HeaderBarComponent") - .scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior), + modifier = customModifier, actions = actions, ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt index f686cedfe..07fcd1a91 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendContent.kt @@ -18,8 +18,10 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -33,6 +35,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.x8bit.bitwarden.R +import com.x8bit.bitwarden.ui.platform.base.util.scrolledContainerBottomDivider import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledTonalButton import com.x8bit.bitwarden.ui.platform.components.button.BitwardenTextButton import com.x8bit.bitwarden.ui.platform.components.card.BitwardenInfoCalloutCard @@ -52,10 +55,12 @@ import kotlinx.collections.immutable.persistentListOf /** * Content view for the [AddSendScreen]. */ +@OptIn(ExperimentalMaterial3Api::class) @Suppress("LongMethod") @Composable fun AddSendContent( state: AddSendState.ViewState.Content, + scrollBehavior: TopAppBarScrollBehavior, policyDisablesSend: Boolean, policySendOptionsInEffect: Boolean, isAddMode: Boolean, @@ -67,14 +72,12 @@ fun AddSendContent( val chooseFileCameraPermissionLauncher = permissionsManager.getLauncher { isGranted -> addSendHandlers.onChooseFileClick(isGranted) } - - Column( - modifier = modifier - .verticalScroll(rememberScrollState()), - ) { + Column(modifier = modifier) { if (isAddMode && !isShared) { BitwardenSegmentedButton( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior) + .fillMaxWidth(), options = persistentListOf( SegmentedButtonState( text = stringResource(id = R.string.file), @@ -92,171 +95,177 @@ fun AddSendContent( ) } - if (policyDisablesSend) { - BitwardenInfoCalloutCard( - text = stringResource(id = R.string.send_disabled_warning), - modifier = Modifier - .padding(horizontal = 16.dp) - .fillMaxWidth(), - ) - Spacer(modifier = Modifier.height(16.dp)) - } - - if (policySendOptionsInEffect) { - BitwardenInfoCalloutCard( - text = stringResource(id = R.string.send_options_policy_in_effect), - modifier = Modifier - .testTag("SendOptionsPolicyInEffectLabel") - .padding(horizontal = 16.dp) - .fillMaxWidth(), - ) - - Spacer(modifier = Modifier.height(16.dp)) - } - - BitwardenTextField( - modifier = Modifier - .testTag("SendNameEntry") - .fillMaxWidth() - .padding(horizontal = 16.dp), - label = stringResource(id = R.string.name), - hint = stringResource(id = R.string.name_info), - readOnly = policyDisablesSend, - value = state.common.name, - onValueChange = addSendHandlers.onNamChange, - ) - - Spacer(modifier = Modifier.height(8.dp)) - when (val type = state.selectedType) { - is AddSendState.ViewState.Content.SendType.File -> { - BitwardenListHeaderText( - label = stringResource(id = R.string.file), + Column( + modifier = Modifier.verticalScroll(rememberScrollState()), + ) { + if (policyDisablesSend) { + Spacer(modifier = Modifier.height(8.dp)) + BitwardenInfoCalloutCard( + text = stringResource(id = R.string.send_disabled_warning), modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + .padding(horizontal = 16.dp) + .fillMaxWidth(), ) Spacer(modifier = Modifier.height(16.dp)) - if (isShared) { - Text( - text = type.name.orEmpty(), - color = BitwardenTheme.colorScheme.text.primary, - style = BitwardenTheme.typography.bodyMedium, + } + + if (policySendOptionsInEffect) { + BitwardenInfoCalloutCard( + text = stringResource(id = R.string.send_options_policy_in_effect), + modifier = Modifier + .testTag(tag = "SendOptionsPolicyInEffectLabel") + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + + Spacer(modifier = Modifier.height(16.dp)) + } + + BitwardenTextField( + modifier = Modifier + .testTag(tag = "SendNameEntry") + .fillMaxWidth() + .padding(horizontal = 16.dp), + label = stringResource(id = R.string.name), + hint = stringResource(id = R.string.name_info), + readOnly = policyDisablesSend, + value = state.common.name, + onValueChange = addSendHandlers.onNamChange, + ) + + Spacer(modifier = Modifier.height(8.dp)) + when (val type = state.selectedType) { + is AddSendState.ViewState.Content.SendType.File -> { + BitwardenListHeaderText( + label = stringResource(id = R.string.file), modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = stringResource(id = R.string.max_file_size), - color = BitwardenTheme.colorScheme.text.secondary, - style = BitwardenTheme.typography.bodySmall, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) - } else if (isAddMode) { - Text( - modifier = Modifier - .testTag("SendCurrentFileNameLabel") - .align(Alignment.CenterHorizontally), - text = type.name ?: stringResource(id = R.string.no_file_chosen), - color = BitwardenTheme.colorScheme.text.secondary, - style = BitwardenTheme.typography.bodySmall, - ) - Spacer(modifier = Modifier.height(8.dp)) - BitwardenFilledTonalButton( - label = stringResource(id = R.string.choose_file), - onClick = { - if (permissionsManager.checkPermission(Manifest.permission.CAMERA)) { - addSendHandlers.onChooseFileClick(true) - } else { - chooseFileCameraPermissionLauncher.launch( - Manifest.permission.CAMERA, - ) - } - }, - modifier = Modifier - .testTag("SendChooseFileButton") - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = stringResource(id = R.string.max_file_size), - color = BitwardenTheme.colorScheme.text.secondary, - style = BitwardenTheme.typography.bodySmall, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp), - ) Spacer(modifier = Modifier.height(16.dp)) - Text( - text = stringResource(id = R.string.type_file_info), - color = BitwardenTheme.colorScheme.text.secondary, - style = BitwardenTheme.typography.bodySmall, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) - } else { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) { + if (isShared) { Text( text = type.name.orEmpty(), color = BitwardenTheme.colorScheme.text.primary, - style = BitwardenTheme.typography.bodyLarge, - modifier = Modifier.weight(1f), - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = type.displaySize.orEmpty(), - color = BitwardenTheme.colorScheme.text.primary, style = BitwardenTheme.typography.bodyMedium, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(id = R.string.max_file_size), + color = BitwardenTheme.colorScheme.text.secondary, + style = BitwardenTheme.typography.bodySmall, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + } else if (isAddMode) { + Text( + modifier = Modifier + .testTag(tag = "SendCurrentFileNameLabel") + .align(Alignment.CenterHorizontally), + text = type.name ?: stringResource(id = R.string.no_file_chosen), + color = BitwardenTheme.colorScheme.text.secondary, + style = BitwardenTheme.typography.bodySmall, + ) + Spacer(modifier = Modifier.height(8.dp)) + BitwardenFilledTonalButton( + label = stringResource(id = R.string.choose_file), + onClick = { + @Suppress("MaxLineLength") + if (permissionsManager.checkPermission(Manifest.permission.CAMERA)) { + addSendHandlers.onChooseFileClick(true) + } else { + chooseFileCameraPermissionLauncher.launch( + Manifest.permission.CAMERA, + ) + } + }, + modifier = Modifier + .testTag(tag = "SendChooseFileButton") + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = stringResource(id = R.string.max_file_size), + color = BitwardenTheme.colorScheme.text.secondary, + style = BitwardenTheme.typography.bodySmall, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.type_file_info), + color = BitwardenTheme.colorScheme.text.secondary, + style = BitwardenTheme.typography.bodySmall, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + } else { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) { + Text( + text = type.name.orEmpty(), + color = BitwardenTheme.colorScheme.text.primary, + style = BitwardenTheme.typography.bodyLarge, + modifier = Modifier.weight(1f), + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = type.displaySize.orEmpty(), + color = BitwardenTheme.colorScheme.text.primary, + style = BitwardenTheme.typography.bodyMedium, + ) + } } } + + is AddSendState.ViewState.Content.SendType.Text -> { + BitwardenTextField( + modifier = Modifier + .testTag(tag = "SendTextContentEntry") + .fillMaxWidth() + .padding(horizontal = 16.dp), + label = stringResource(id = R.string.text), + hint = stringResource(id = R.string.type_text_info), + readOnly = policyDisablesSend, + value = type.input, + singleLine = false, + onValueChange = addSendHandlers.onTextChange, + ) + Spacer(modifier = Modifier.height(16.dp)) + BitwardenWideSwitch( + modifier = Modifier + .testTag(tag = "SendHideTextByDefaultToggle") + .fillMaxWidth() + .padding(horizontal = 16.dp), + label = stringResource(id = R.string.hide_text_by_default), + isChecked = type.isHideByDefaultChecked, + onCheckedChange = addSendHandlers.onIsHideByDefaultToggle, + readOnly = policyDisablesSend, + ) + } } - is AddSendState.ViewState.Content.SendType.Text -> { - BitwardenTextField( - modifier = Modifier - .testTag("SendTextContentEntry") - .fillMaxWidth() - .padding(horizontal = 16.dp), - label = stringResource(id = R.string.text), - hint = stringResource(id = R.string.type_text_info), - readOnly = policyDisablesSend, - value = type.input, - singleLine = false, - onValueChange = addSendHandlers.onTextChange, - ) - Spacer(modifier = Modifier.height(16.dp)) - BitwardenWideSwitch( - modifier = Modifier - .testTag("SendHideTextByDefaultToggle") - .fillMaxWidth() - .padding(horizontal = 16.dp), - label = stringResource(id = R.string.hide_text_by_default), - isChecked = type.isHideByDefaultChecked, - onCheckedChange = addSendHandlers.onIsHideByDefaultToggle, - readOnly = policyDisablesSend, - ) - } + Spacer(modifier = Modifier.height(16.dp)) + AddSendOptions( + state = state, + sendRestrictionPolicy = policyDisablesSend, + isAddMode = isAddMode, + addSendHandlers = addSendHandlers, + ) + + Spacer(modifier = Modifier.height(24.dp)) + Spacer(modifier = Modifier.navigationBarsPadding()) } - - Spacer(modifier = Modifier.height(16.dp)) - AddSendOptions( - state = state, - sendRestrictionPolicy = policyDisablesSend, - isAddMode = isAddMode, - addSendHandlers = addSendHandlers, - ) - - Spacer(modifier = Modifier.height(24.dp)) - Spacer(modifier = Modifier.navigationBarsPadding()) } } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt index ed1245c62..1aa631e55 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt @@ -35,6 +35,7 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState +import com.x8bit.bitwarden.ui.platform.components.model.TopAppBarDividerStyle import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager @@ -137,6 +138,7 @@ fun AddSendScreen( }, ) .takeUnless { state.isShared }, + dividerStyle = TopAppBarDividerStyle.NONE, scrollBehavior = scrollBehavior, actions = { BitwardenTextButton( @@ -194,6 +196,7 @@ fun AddSendScreen( when (val viewState = state.viewState) { is AddSendState.ViewState.Content -> AddSendContent( state = viewState, + scrollBehavior = scrollBehavior, policyDisablesSend = state.policyDisablesSend, policySendOptionsInEffect = state.shouldDisplayPolicyWarning, isAddMode = state.isAddMode, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt index 36a49e733..0238980a5 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreenTest.kt @@ -376,12 +376,10 @@ class AddSendScreenTest : BaseComposeTest() { composeTestRule .onAllNodesWithText("File") .filterToOne(!isEditableText) - .performScrollTo() .assertIsDisplayed() composeTestRule .onAllNodesWithText("Text") .filterToOne(!isEditableText) - .performScrollTo() .assertIsDisplayed() mutableStateFlow.update {