Pin the segmented control to toolbar in AddSendScreen (#4093)

This commit is contained in:
David Perez 2024-10-15 16:13:29 -05:00 committed by GitHub
parent 970a1e14cd
commit 8eb408b140
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 190 additions and 161 deletions

View file

@ -21,10 +21,12 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.x8bit.bitwarden.R 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.mirrorIfRtl
import com.x8bit.bitwarden.ui.platform.base.util.scrolledContainerBottomDivider 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.appbar.color.bitwardenTopAppBarColors
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenStandardIconButton 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.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
@ -47,6 +49,7 @@ fun BitwardenTopAppBar(
navigationIconContentDescription: String, navigationIconContentDescription: String,
onNavigationIconClick: () -> Unit, onNavigationIconClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
dividerStyle: TopAppBarDividerStyle = TopAppBarDividerStyle.ON_SCROLL,
actions: @Composable RowScope.() -> Unit = { }, actions: @Composable RowScope.() -> Unit = { },
) { ) {
BitwardenTopAppBar( BitwardenTopAppBar(
@ -58,6 +61,7 @@ fun BitwardenTopAppBar(
onNavigationIconClick = onNavigationIconClick, onNavigationIconClick = onNavigationIconClick,
), ),
modifier = modifier, modifier = modifier,
dividerStyle = dividerStyle,
actions = actions, actions = actions,
) )
} }
@ -82,6 +86,7 @@ fun BitwardenTopAppBar(
scrollBehavior: TopAppBarScrollBehavior, scrollBehavior: TopAppBarScrollBehavior,
navigationIcon: NavigationIcon?, navigationIcon: NavigationIcon?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
dividerStyle: TopAppBarDividerStyle = TopAppBarDividerStyle.ON_SCROLL,
actions: @Composable RowScope.() -> Unit = {}, actions: @Composable RowScope.() -> Unit = {},
) { ) {
var titleTextHasOverflow by remember { 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) { if (titleTextHasOverflow) {
MediumTopAppBar( MediumTopAppBar(
@ -120,9 +143,7 @@ fun BitwardenTopAppBar(
modifier = Modifier.testTag(tag = "PageTitleLabel"), modifier = Modifier.testTag(tag = "PageTitleLabel"),
) )
}, },
modifier = modifier modifier = customModifier,
.testTag(tag = "HeaderBarComponent")
.scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior),
actions = actions, actions = actions,
) )
} else { } else {
@ -144,9 +165,7 @@ fun BitwardenTopAppBar(
}, },
) )
}, },
modifier = modifier modifier = customModifier,
.testTag(tag = "HeaderBarComponent")
.scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior),
actions = actions, actions = actions,
) )
} }

View file

@ -18,8 +18,10 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf 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.semantics.semantics
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.x8bit.bitwarden.R 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.BitwardenFilledTonalButton
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenTextButton import com.x8bit.bitwarden.ui.platform.components.button.BitwardenTextButton
import com.x8bit.bitwarden.ui.platform.components.card.BitwardenInfoCalloutCard import com.x8bit.bitwarden.ui.platform.components.card.BitwardenInfoCalloutCard
@ -52,10 +55,12 @@ import kotlinx.collections.immutable.persistentListOf
/** /**
* Content view for the [AddSendScreen]. * Content view for the [AddSendScreen].
*/ */
@OptIn(ExperimentalMaterial3Api::class)
@Suppress("LongMethod") @Suppress("LongMethod")
@Composable @Composable
fun AddSendContent( fun AddSendContent(
state: AddSendState.ViewState.Content, state: AddSendState.ViewState.Content,
scrollBehavior: TopAppBarScrollBehavior,
policyDisablesSend: Boolean, policyDisablesSend: Boolean,
policySendOptionsInEffect: Boolean, policySendOptionsInEffect: Boolean,
isAddMode: Boolean, isAddMode: Boolean,
@ -67,14 +72,12 @@ fun AddSendContent(
val chooseFileCameraPermissionLauncher = permissionsManager.getLauncher { isGranted -> val chooseFileCameraPermissionLauncher = permissionsManager.getLauncher { isGranted ->
addSendHandlers.onChooseFileClick(isGranted) addSendHandlers.onChooseFileClick(isGranted)
} }
Column(modifier = modifier) {
Column(
modifier = modifier
.verticalScroll(rememberScrollState()),
) {
if (isAddMode && !isShared) { if (isAddMode && !isShared) {
BitwardenSegmentedButton( BitwardenSegmentedButton(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
.scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior)
.fillMaxWidth(),
options = persistentListOf( options = persistentListOf(
SegmentedButtonState( SegmentedButtonState(
text = stringResource(id = R.string.file), text = stringResource(id = R.string.file),
@ -92,7 +95,11 @@ fun AddSendContent(
) )
} }
Column(
modifier = Modifier.verticalScroll(rememberScrollState()),
) {
if (policyDisablesSend) { if (policyDisablesSend) {
Spacer(modifier = Modifier.height(8.dp))
BitwardenInfoCalloutCard( BitwardenInfoCalloutCard(
text = stringResource(id = R.string.send_disabled_warning), text = stringResource(id = R.string.send_disabled_warning),
modifier = Modifier modifier = Modifier
@ -106,7 +113,7 @@ fun AddSendContent(
BitwardenInfoCalloutCard( BitwardenInfoCalloutCard(
text = stringResource(id = R.string.send_options_policy_in_effect), text = stringResource(id = R.string.send_options_policy_in_effect),
modifier = Modifier modifier = Modifier
.testTag("SendOptionsPolicyInEffectLabel") .testTag(tag = "SendOptionsPolicyInEffectLabel")
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.fillMaxWidth(), .fillMaxWidth(),
) )
@ -116,7 +123,7 @@ fun AddSendContent(
BitwardenTextField( BitwardenTextField(
modifier = Modifier modifier = Modifier
.testTag("SendNameEntry") .testTag(tag = "SendNameEntry")
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
label = stringResource(id = R.string.name), label = stringResource(id = R.string.name),
@ -157,7 +164,7 @@ fun AddSendContent(
} else if (isAddMode) { } else if (isAddMode) {
Text( Text(
modifier = Modifier modifier = Modifier
.testTag("SendCurrentFileNameLabel") .testTag(tag = "SendCurrentFileNameLabel")
.align(Alignment.CenterHorizontally), .align(Alignment.CenterHorizontally),
text = type.name ?: stringResource(id = R.string.no_file_chosen), text = type.name ?: stringResource(id = R.string.no_file_chosen),
color = BitwardenTheme.colorScheme.text.secondary, color = BitwardenTheme.colorScheme.text.secondary,
@ -167,6 +174,7 @@ fun AddSendContent(
BitwardenFilledTonalButton( BitwardenFilledTonalButton(
label = stringResource(id = R.string.choose_file), label = stringResource(id = R.string.choose_file),
onClick = { onClick = {
@Suppress("MaxLineLength")
if (permissionsManager.checkPermission(Manifest.permission.CAMERA)) { if (permissionsManager.checkPermission(Manifest.permission.CAMERA)) {
addSendHandlers.onChooseFileClick(true) addSendHandlers.onChooseFileClick(true)
} else { } else {
@ -176,7 +184,7 @@ fun AddSendContent(
} }
}, },
modifier = Modifier modifier = Modifier
.testTag("SendChooseFileButton") .testTag(tag = "SendChooseFileButton")
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
) )
@ -223,7 +231,7 @@ fun AddSendContent(
is AddSendState.ViewState.Content.SendType.Text -> { is AddSendState.ViewState.Content.SendType.Text -> {
BitwardenTextField( BitwardenTextField(
modifier = Modifier modifier = Modifier
.testTag("SendTextContentEntry") .testTag(tag = "SendTextContentEntry")
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
label = stringResource(id = R.string.text), label = stringResource(id = R.string.text),
@ -236,7 +244,7 @@ fun AddSendContent(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
BitwardenWideSwitch( BitwardenWideSwitch(
modifier = Modifier modifier = Modifier
.testTag("SendHideTextByDefaultToggle") .testTag(tag = "SendHideTextByDefaultToggle")
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
label = stringResource(id = R.string.hide_text_by_default), label = stringResource(id = R.string.hide_text_by_default),
@ -259,6 +267,7 @@ fun AddSendContent(
Spacer(modifier = Modifier.navigationBarsPadding()) Spacer(modifier = Modifier.navigationBarsPadding())
} }
} }
}
/** /**
* Displays a collapsable set of new send options. * Displays a collapsable set of new send options.

View file

@ -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.BitwardenLoadingDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog 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.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.scaffold.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager
@ -137,6 +138,7 @@ fun AddSendScreen(
}, },
) )
.takeUnless { state.isShared }, .takeUnless { state.isShared },
dividerStyle = TopAppBarDividerStyle.NONE,
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
actions = { actions = {
BitwardenTextButton( BitwardenTextButton(
@ -194,6 +196,7 @@ fun AddSendScreen(
when (val viewState = state.viewState) { when (val viewState = state.viewState) {
is AddSendState.ViewState.Content -> AddSendContent( is AddSendState.ViewState.Content -> AddSendContent(
state = viewState, state = viewState,
scrollBehavior = scrollBehavior,
policyDisablesSend = state.policyDisablesSend, policyDisablesSend = state.policyDisablesSend,
policySendOptionsInEffect = state.shouldDisplayPolicyWarning, policySendOptionsInEffect = state.shouldDisplayPolicyWarning,
isAddMode = state.isAddMode, isAddMode = state.isAddMode,

View file

@ -376,12 +376,10 @@ class AddSendScreenTest : BaseComposeTest() {
composeTestRule composeTestRule
.onAllNodesWithText("File") .onAllNodesWithText("File")
.filterToOne(!isEditableText) .filterToOne(!isEditableText)
.performScrollTo()
.assertIsDisplayed() .assertIsDisplayed()
composeTestRule composeTestRule
.onAllNodesWithText("Text") .onAllNodesWithText("Text")
.filterToOne(!isEditableText) .filterToOne(!isEditableText)
.performScrollTo()
.assertIsDisplayed() .assertIsDisplayed()
mutableStateFlow.update { mutableStateFlow.update {