mirror of
https://github.com/bitwarden/android.git
synced 2026-03-11 20:54:58 -05:00
PM-17721: Update app dropdown menus (#4646)
This commit is contained in:
@@ -25,6 +25,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.semantics.CustomAccessibilityAction
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
@@ -68,6 +69,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
* @param supportingText A optional supporting text that will appear below the text field.
|
||||
* @param tooltip A nullable [TooltipData], representing the tooltip icon.
|
||||
* @param insets Inner padding to be applied withing the card.
|
||||
* @param textFieldTestTag The optional test tag associated with the inner text field.
|
||||
* @param cardStyle Indicates the type of card style to be applied.
|
||||
* @param actionsPadding Padding to be applied to the [actions] block.
|
||||
* @param actions A lambda containing the set of actions (usually icons or similar) to display
|
||||
@@ -86,6 +88,7 @@ fun BitwardenMultiSelectButton(
|
||||
supportingText: String? = null,
|
||||
tooltip: TooltipData? = null,
|
||||
insets: PaddingValues = PaddingValues(),
|
||||
textFieldTestTag: String? = null,
|
||||
cardStyle: CardStyle? = null,
|
||||
actionsPadding: PaddingValues = PaddingValues(),
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
@@ -161,6 +164,7 @@ fun BitwardenMultiSelectButton(
|
||||
},
|
||||
colors = bitwardenTextFieldButtonColors(),
|
||||
modifier = Modifier
|
||||
.run { textFieldTestTag?.let { testTag(tag = it) } ?: this }
|
||||
.weight(weight = 1f)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.widget.Toast
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -47,10 +48,9 @@ import com.x8bit.bitwarden.ui.platform.components.card.actionCardExitAnimation
|
||||
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.BitwardenLogoutConfirmationDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenSelectionDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTimePickerDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.row.BitwardenSelectionRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.dropdown.BitwardenMultiSelectButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
|
||||
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenExternalLinkRow
|
||||
@@ -68,6 +68,7 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import com.x8bit.bitwarden.ui.platform.util.displayLabel
|
||||
import com.x8bit.bitwarden.ui.platform.util.minutes
|
||||
import com.x8bit.bitwarden.ui.platform.util.toFormattedPattern
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.time.LocalTime
|
||||
import javax.crypto.Cipher
|
||||
|
||||
@@ -497,75 +498,51 @@ private fun SessionTimeoutPolicyRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SessionTimeoutRow(
|
||||
vaultTimeoutPolicyMinutes: Int?,
|
||||
selectedVaultTimeoutType: VaultTimeout.Type,
|
||||
onVaultTimeoutTypeSelect: (VaultTimeout.Type) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
resources: Resources = LocalContext.current.resources,
|
||||
) {
|
||||
var shouldShowSelectionDialog by remember { mutableStateOf(false) }
|
||||
var shouldShowNeverTimeoutConfirmationDialog by remember { mutableStateOf(false) }
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.session_timeout),
|
||||
onClick = { shouldShowSelectionDialog = true },
|
||||
val vaultTimeoutOptions = VaultTimeout.Type
|
||||
.entries
|
||||
.filter { it.minutes <= (vaultTimeoutPolicyMinutes ?: Int.MAX_VALUE) }
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.session_timeout),
|
||||
options = vaultTimeoutOptions.map { it.displayLabel() }.toImmutableList(),
|
||||
selectedOption = selectedVaultTimeoutType.displayLabel(),
|
||||
onOptionSelected = { selectedType ->
|
||||
val selectedOption = vaultTimeoutOptions.first {
|
||||
it.displayLabel.toString(resources) == selectedType
|
||||
}
|
||||
if (selectedOption == VaultTimeout.Type.NEVER) {
|
||||
shouldShowNeverTimeoutConfirmationDialog = true
|
||||
} else {
|
||||
onVaultTimeoutTypeSelect(selectedOption)
|
||||
}
|
||||
},
|
||||
textFieldTestTag = "SessionTimeoutStatusLabel",
|
||||
cardStyle = CardStyle.Top(),
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
text = selectedVaultTimeoutType.displayLabel(),
|
||||
style = BitwardenTheme.typography.labelSmall,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier.testTag("SessionTimeoutStatusLabel"),
|
||||
)
|
||||
|
||||
if (shouldShowNeverTimeoutConfirmationDialog) {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.warning),
|
||||
message = stringResource(id = R.string.never_lock_warning),
|
||||
confirmButtonText = stringResource(id = R.string.ok),
|
||||
dismissButtonText = stringResource(id = R.string.cancel),
|
||||
onConfirmClick = {
|
||||
shouldShowNeverTimeoutConfirmationDialog = false
|
||||
onVaultTimeoutTypeSelect(VaultTimeout.Type.NEVER)
|
||||
},
|
||||
onDismissClick = { shouldShowNeverTimeoutConfirmationDialog = false },
|
||||
onDismissRequest = { shouldShowNeverTimeoutConfirmationDialog = false },
|
||||
)
|
||||
}
|
||||
|
||||
when {
|
||||
shouldShowSelectionDialog -> {
|
||||
val vaultTimeoutOptions = VaultTimeout.Type.entries
|
||||
.filter {
|
||||
it.minutes <= (vaultTimeoutPolicyMinutes ?: Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
BitwardenSelectionDialog(
|
||||
title = stringResource(id = R.string.session_timeout),
|
||||
onDismissRequest = { shouldShowSelectionDialog = false },
|
||||
) {
|
||||
vaultTimeoutOptions.forEach { vaultTimeoutOption ->
|
||||
BitwardenSelectionRow(
|
||||
text = vaultTimeoutOption.displayLabel,
|
||||
onClick = {
|
||||
shouldShowSelectionDialog = false
|
||||
val selectedType =
|
||||
vaultTimeoutOptions.first { it == vaultTimeoutOption }
|
||||
if (selectedType == VaultTimeout.Type.NEVER) {
|
||||
shouldShowNeverTimeoutConfirmationDialog = true
|
||||
} else {
|
||||
onVaultTimeoutTypeSelect(selectedType)
|
||||
}
|
||||
},
|
||||
isSelected = selectedVaultTimeoutType == vaultTimeoutOption,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldShowNeverTimeoutConfirmationDialog -> {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.warning),
|
||||
message = stringResource(id = R.string.never_lock_warning),
|
||||
confirmButtonText = stringResource(id = R.string.ok),
|
||||
dismissButtonText = stringResource(id = R.string.cancel),
|
||||
onConfirmClick = {
|
||||
shouldShowNeverTimeoutConfirmationDialog = false
|
||||
onVaultTimeoutTypeSelect(VaultTimeout.Type.NEVER)
|
||||
},
|
||||
onDismissClick = { shouldShowNeverTimeoutConfirmationDialog = false },
|
||||
onDismissRequest = { shouldShowNeverTimeoutConfirmationDialog = false },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@@ -640,7 +617,6 @@ private fun SessionCustomTimeoutRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun SessionTimeoutActionRow(
|
||||
isEnabled: Boolean,
|
||||
@@ -648,78 +624,52 @@ private fun SessionTimeoutActionRow(
|
||||
selectedVaultTimeoutAction: VaultTimeoutAction,
|
||||
onVaultTimeoutActionSelect: (VaultTimeoutAction) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
resources: Resources = LocalContext.current.resources,
|
||||
) {
|
||||
var shouldShowSelectionDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var shouldShowLogoutActionConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
BitwardenTextRow(
|
||||
BitwardenMultiSelectButton(
|
||||
isEnabled = isEnabled,
|
||||
text = stringResource(id = R.string.session_timeout_action),
|
||||
description = stringResource(
|
||||
label = stringResource(id = R.string.session_timeout_action),
|
||||
options = VaultTimeoutAction.entries.map { it.displayLabel() }.toImmutableList(),
|
||||
selectedOption = selectedVaultTimeoutAction.displayLabel(),
|
||||
onOptionSelected = { action ->
|
||||
// The option is not selectable if there's a policy in place.
|
||||
if (vaultTimeoutPolicyAction != null) return@BitwardenMultiSelectButton
|
||||
val selectedAction = VaultTimeoutAction.entries.first {
|
||||
it.displayLabel.toString(resources) == action
|
||||
}
|
||||
if (selectedAction == VaultTimeoutAction.LOGOUT) {
|
||||
shouldShowLogoutActionConfirmationDialog = true
|
||||
} else {
|
||||
onVaultTimeoutActionSelect(selectedAction)
|
||||
}
|
||||
},
|
||||
supportingText = stringResource(
|
||||
id = R.string.set_up_an_unlock_option_to_change_your_vault_timeout_action,
|
||||
)
|
||||
.takeUnless { isEnabled },
|
||||
onClick = {
|
||||
// The option is not selectable if there's a policy in place.
|
||||
if (vaultTimeoutPolicyAction != null) return@BitwardenTextRow
|
||||
shouldShowSelectionDialog = true
|
||||
},
|
||||
textFieldTestTag = "SessionTimeoutActionStatusLabel",
|
||||
cardStyle = CardStyle.Bottom,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
text = selectedVaultTimeoutAction.displayLabel(),
|
||||
style = BitwardenTheme.typography.labelSmall,
|
||||
color = if (isEnabled) {
|
||||
BitwardenTheme.colorScheme.text.primary
|
||||
} else {
|
||||
BitwardenTheme.colorScheme.filledButton.foregroundDisabled
|
||||
},
|
||||
modifier = Modifier.testTag("SessionTimeoutActionStatusLabel"),
|
||||
)
|
||||
}
|
||||
when {
|
||||
shouldShowSelectionDialog -> {
|
||||
BitwardenSelectionDialog(
|
||||
title = stringResource(id = R.string.vault_timeout_action),
|
||||
onDismissRequest = { shouldShowSelectionDialog = false },
|
||||
) {
|
||||
val vaultTimeoutActionOptions = VaultTimeoutAction.entries
|
||||
vaultTimeoutActionOptions.forEach { option ->
|
||||
BitwardenSelectionRow(
|
||||
text = option.displayLabel,
|
||||
isSelected = option == selectedVaultTimeoutAction,
|
||||
onClick = {
|
||||
shouldShowSelectionDialog = false
|
||||
val selectedAction = vaultTimeoutActionOptions.first { it == option }
|
||||
if (selectedAction == VaultTimeoutAction.LOGOUT) {
|
||||
shouldShowLogoutActionConfirmationDialog = true
|
||||
} else {
|
||||
onVaultTimeoutActionSelect(selectedAction)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
shouldShowLogoutActionConfirmationDialog -> {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.warning),
|
||||
message = stringResource(id = R.string.vault_timeout_log_out_confirmation),
|
||||
confirmButtonText = stringResource(id = R.string.yes),
|
||||
dismissButtonText = stringResource(id = R.string.cancel),
|
||||
onConfirmClick = {
|
||||
shouldShowLogoutActionConfirmationDialog = false
|
||||
onVaultTimeoutActionSelect(VaultTimeoutAction.LOGOUT)
|
||||
},
|
||||
onDismissClick = {
|
||||
shouldShowLogoutActionConfirmationDialog = false
|
||||
},
|
||||
onDismissRequest = {
|
||||
shouldShowLogoutActionConfirmationDialog = false
|
||||
},
|
||||
)
|
||||
}
|
||||
if (shouldShowLogoutActionConfirmationDialog) {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.warning),
|
||||
message = stringResource(id = R.string.vault_timeout_log_out_confirmation),
|
||||
confirmButtonText = stringResource(id = R.string.yes),
|
||||
dismissButtonText = stringResource(id = R.string.cancel),
|
||||
onConfirmClick = {
|
||||
shouldShowLogoutActionConfirmationDialog = false
|
||||
onVaultTimeoutActionSelect(VaultTimeoutAction.LOGOUT)
|
||||
},
|
||||
onDismissClick = {
|
||||
shouldShowLogoutActionConfirmationDialog = false
|
||||
},
|
||||
onDismissRequest = {
|
||||
shouldShowLogoutActionConfirmationDialog = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.appearance
|
||||
|
||||
import android.content.res.Resources
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -9,7 +10,6 @@ import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -27,21 +28,18 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
||||
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenSelectionDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.row.BitwardenSelectionRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.dropdown.BitwardenMultiSelectButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
|
||||
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenTextRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import com.x8bit.bitwarden.ui.platform.util.displayLabel
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* Displays the appearance screen.
|
||||
@@ -128,48 +126,30 @@ private fun LanguageSelectionRow(
|
||||
currentSelection: AppLanguage,
|
||||
onLanguageSelection: (AppLanguage) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
resources: Resources = LocalContext.current.resources,
|
||||
) {
|
||||
var languageChangedDialogOption: Text? by rememberSaveable { mutableStateOf(value = null) }
|
||||
var shouldShowLanguageSelectionDialog by rememberSaveable { mutableStateOf(value = false) }
|
||||
var languageChangedDialogOption: String? by rememberSaveable { mutableStateOf(value = null) }
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.language),
|
||||
options = AppLanguage.entries.map { it.text() }.toImmutableList(),
|
||||
selectedOption = currentSelection.text(),
|
||||
onOptionSelected = { selectedLanguage ->
|
||||
onLanguageSelection(
|
||||
AppLanguage.entries.first { selectedLanguage == it.text.toString(resources) },
|
||||
)
|
||||
languageChangedDialogOption = selectedLanguage
|
||||
},
|
||||
cardStyle = CardStyle.Full,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
languageChangedDialogOption?.let {
|
||||
BitwardenBasicDialog(
|
||||
title = stringResource(id = R.string.language),
|
||||
message = stringResource(id = R.string.language_change_x_description, it.invoke()),
|
||||
message = stringResource(id = R.string.language_change_x_description, it),
|
||||
onDismissRequest = { languageChangedDialogOption = null },
|
||||
)
|
||||
}
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.language),
|
||||
onClick = { shouldShowLanguageSelectionDialog = true },
|
||||
cardStyle = CardStyle.Full,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
text = currentSelection.text(),
|
||||
style = BitwardenTheme.typography.labelSmall,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
)
|
||||
}
|
||||
|
||||
if (shouldShowLanguageSelectionDialog) {
|
||||
BitwardenSelectionDialog(
|
||||
title = stringResource(id = R.string.language),
|
||||
onDismissRequest = { shouldShowLanguageSelectionDialog = false },
|
||||
) {
|
||||
AppLanguage.entries.forEach { option ->
|
||||
BitwardenSelectionRow(
|
||||
text = option.text,
|
||||
isSelected = option == currentSelection,
|
||||
onClick = {
|
||||
shouldShowLanguageSelectionDialog = false
|
||||
onLanguageSelection(option)
|
||||
languageChangedDialogOption = option.text
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -177,40 +157,19 @@ private fun ThemeSelectionRow(
|
||||
currentSelection: AppTheme,
|
||||
onThemeSelection: (AppTheme) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
resources: Resources = LocalContext.current.resources,
|
||||
) {
|
||||
var shouldShowThemeSelectionDialog by remember { mutableStateOf(false) }
|
||||
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.theme),
|
||||
description = stringResource(id = R.string.theme_description),
|
||||
onClick = { shouldShowThemeSelectionDialog = true },
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.theme),
|
||||
options = AppTheme.entries.map { it.displayLabel() }.toImmutableList(),
|
||||
selectedOption = currentSelection.displayLabel(),
|
||||
onOptionSelected = { selectedTheme ->
|
||||
onThemeSelection(
|
||||
AppTheme.entries.first { selectedTheme == it.displayLabel.toString(resources) },
|
||||
)
|
||||
},
|
||||
supportingText = stringResource(id = R.string.theme_description),
|
||||
cardStyle = CardStyle.Full,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
text = currentSelection.displayLabel(),
|
||||
style = BitwardenTheme.typography.labelSmall,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
)
|
||||
}
|
||||
|
||||
if (shouldShowThemeSelectionDialog) {
|
||||
BitwardenSelectionDialog(
|
||||
title = stringResource(id = R.string.theme),
|
||||
onDismissRequest = { shouldShowThemeSelectionDialog = false },
|
||||
) {
|
||||
AppTheme.entries.forEach { option ->
|
||||
BitwardenSelectionRow(
|
||||
text = option.displayLabel,
|
||||
isSelected = option == currentSelection,
|
||||
onClick = {
|
||||
shouldShowThemeSelectionDialog = false
|
||||
onThemeSelection(
|
||||
AppTheme.entries.first { it == option },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.autofill
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.widget.Toast
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -11,7 +12,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -37,9 +37,8 @@ import com.x8bit.bitwarden.ui.platform.components.badge.NotificationBadge
|
||||
import com.x8bit.bitwarden.ui.platform.components.card.BitwardenActionCard
|
||||
import com.x8bit.bitwarden.ui.platform.components.card.actionCardExitAnimation
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenSelectionDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.row.BitwardenSelectionRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.dropdown.BitwardenMultiSelectButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
|
||||
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenExternalLinkRow
|
||||
@@ -50,7 +49,7 @@ import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.autofill.util.displayLabel
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* Displays the auto-fill screen.
|
||||
@@ -336,41 +335,21 @@ private fun DefaultUriMatchTypeRow(
|
||||
selectedUriMatchType: UriMatchType,
|
||||
onUriMatchTypeSelect: (UriMatchType) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
resources: Resources = LocalContext.current.resources,
|
||||
) {
|
||||
var shouldShowDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.default_uri_match_detection),
|
||||
description = stringResource(id = R.string.default_uri_match_detection_description),
|
||||
onClick = { shouldShowDialog = true },
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.default_uri_match_detection),
|
||||
options = UriMatchType.entries.map { it.displayLabel() }.toImmutableList(),
|
||||
selectedOption = selectedUriMatchType.displayLabel(),
|
||||
onOptionSelected = { selectedOption ->
|
||||
onUriMatchTypeSelect(
|
||||
UriMatchType
|
||||
.entries
|
||||
.first { it.displayLabel.toString(resources) == selectedOption },
|
||||
)
|
||||
},
|
||||
supportingText = stringResource(id = R.string.default_uri_match_detection_description),
|
||||
cardStyle = CardStyle.Full,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
text = selectedUriMatchType.displayLabel(),
|
||||
style = BitwardenTheme.typography.labelSmall,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
)
|
||||
}
|
||||
|
||||
if (shouldShowDialog) {
|
||||
BitwardenSelectionDialog(
|
||||
title = stringResource(id = R.string.default_uri_match_detection),
|
||||
onDismissRequest = { shouldShowDialog = false },
|
||||
) {
|
||||
val uriMatchTypes = UriMatchType.entries
|
||||
uriMatchTypes.forEach { option ->
|
||||
BitwardenSelectionRow(
|
||||
text = option.displayLabel,
|
||||
isSelected = option == selectedUriMatchType,
|
||||
onClick = {
|
||||
shouldShowDialog = false
|
||||
onUriMatchTypeSelect(
|
||||
uriMatchTypes.first { it == option },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.other
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -39,15 +40,14 @@ import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
|
||||
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.BitwardenSelectionDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.row.BitwardenSelectionRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.dropdown.BitwardenMultiSelectButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
|
||||
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenTextRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* Displays the other screen.
|
||||
@@ -169,7 +169,7 @@ fun OtherScreen(
|
||||
.standardHorizontalMargin(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(height = 16.dp))
|
||||
Spacer(modifier = Modifier.height(height = 8.dp))
|
||||
|
||||
ScreenCaptureRow(
|
||||
currentValue = state.allowScreenCapture,
|
||||
@@ -182,6 +182,7 @@ fun OtherScreen(
|
||||
.standardHorizontalMargin(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(height = 16.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
@@ -230,43 +231,24 @@ private fun ClearClipboardFrequencyRow(
|
||||
currentSelection: ClearClipboardFrequency,
|
||||
onFrequencySelection: (ClearClipboardFrequency) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
resources: Resources = LocalContext.current.resources,
|
||||
) {
|
||||
var shouldShowClearClipboardDialog by remember { mutableStateOf(false) }
|
||||
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.clear_clipboard),
|
||||
description = stringResource(id = R.string.clear_clipboard_description),
|
||||
onClick = { shouldShowClearClipboardDialog = true },
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.clear_clipboard),
|
||||
supportingText = stringResource(id = R.string.clear_clipboard_description),
|
||||
options = ClearClipboardFrequency.entries.map { it.displayLabel() }.toImmutableList(),
|
||||
selectedOption = currentSelection.displayLabel(),
|
||||
onOptionSelected = { selectedFrequency ->
|
||||
onFrequencySelection(
|
||||
ClearClipboardFrequency
|
||||
.entries
|
||||
.first { it.displayLabel.toString(resources) == selectedFrequency },
|
||||
)
|
||||
},
|
||||
textFieldTestTag = "ClearClipboardAfterLabel",
|
||||
cardStyle = CardStyle.Full,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
text = currentSelection.displayLabel.invoke(),
|
||||
style = BitwardenTheme.typography.labelSmall,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier.testTag("ClearClipboardAfterLabel"),
|
||||
)
|
||||
}
|
||||
|
||||
if (shouldShowClearClipboardDialog) {
|
||||
BitwardenSelectionDialog(
|
||||
title = stringResource(id = R.string.clear_clipboard),
|
||||
onDismissRequest = { shouldShowClearClipboardDialog = false },
|
||||
) {
|
||||
ClearClipboardFrequency.entries.forEach { option ->
|
||||
BitwardenSelectionRow(
|
||||
text = option.displayLabel,
|
||||
isSelected = option == currentSelection,
|
||||
onClick = {
|
||||
shouldShowClearClipboardDialog = false
|
||||
onFrequencySelection(
|
||||
ClearClipboardFrequency.entries.first { it == option },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -5,10 +5,8 @@ import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsFocused
|
||||
import androidx.compose.ui.test.assertIsOff
|
||||
import androidx.compose.ui.test.assertIsOn
|
||||
import androidx.compose.ui.test.assertTextEquals
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.hasClickAction
|
||||
import androidx.compose.ui.test.hasTextExactly
|
||||
import androidx.compose.ui.test.isDialog
|
||||
import androidx.compose.ui.test.isDisplayed
|
||||
@@ -552,16 +550,14 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
@Test
|
||||
fun `session timeout should be updated on or off according to state`() {
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.assertTextEquals("Session timeout", "30 minutes")
|
||||
.assertIsDisplayed()
|
||||
mutableStateFlow.update { it.copy(vaultTimeout = VaultTimeout.FourHours) }
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "4 hours. Session timeout")
|
||||
.performScrollTo()
|
||||
.assertTextEquals("Session timeout", "4 hours")
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -569,8 +565,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -634,8 +629,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -688,8 +682,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -707,8 +700,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -731,8 +723,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -769,8 +760,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -799,8 +789,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
.onNodeWithContentDescription(label = "30 minutes. Session timeout")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -981,12 +970,12 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Lock. Session timeout action")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Vault timeout action")
|
||||
.onAllNodesWithText("Session timeout action")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule
|
||||
@@ -1009,12 +998,12 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Lock. Session timeout action")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Vault timeout action")
|
||||
.onAllNodesWithText("Session timeout action")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule
|
||||
@@ -1033,12 +1022,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on session timeout action dialog Logout click should open a confirmation dialog`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Lock. Session timeout action")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -1077,7 +1065,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
fun `on session timeout action Logout confirmation dialog cancel click should dismiss the dialog`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Lock. Session timeout action")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -1106,7 +1094,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
fun `on session timeout action Logout confirmation dialog Yes click should dismiss the dialog and send VaultTimeoutActionSelect`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Lock. Session timeout action")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -1136,18 +1124,17 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on session timeout action dialog cancel click should close the dialog`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Lock. Session timeout action")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Vault timeout action")
|
||||
.onAllNodesWithText("Session timeout action")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule
|
||||
@@ -1163,14 +1150,14 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
@Test
|
||||
fun `session timeout action should be updated according to state`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Lock. Session timeout action")
|
||||
.performScrollTo()
|
||||
.assertTextEquals("Session timeout action", "Lock")
|
||||
.assertIsDisplayed()
|
||||
mutableStateFlow.update { it.copy(vaultTimeoutAction = VaultTimeoutAction.LOGOUT) }
|
||||
composeTestRule
|
||||
.onNodeWithText("Session timeout action")
|
||||
.onNodeWithContentDescription(label = "Log out. Session timeout action")
|
||||
.performScrollTo()
|
||||
.assertTextEquals("Session timeout action", "Log out")
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
||||
@@ -8,7 +8,10 @@ import androidx.compose.ui.test.isDialog
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.onRoot
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.printToLog
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
@@ -50,7 +53,10 @@ class AppearanceScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on language row click should display language selection dialog`() {
|
||||
composeTestRule.onNodeWithText("Language").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Default (System). Language")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Language")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
@@ -60,7 +66,10 @@ class AppearanceScreenTest : BaseComposeTest() {
|
||||
@Test
|
||||
fun `on language selection dialog item click should send LanguageChange and show dialog`() {
|
||||
// Clicking the Language row shows the language selection dialog
|
||||
composeTestRule.onNodeWithText("Language").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Default (System). Language")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
// Selecting a language dismisses this dialog and displays the confirmation
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Afrikaans")
|
||||
@@ -93,7 +102,10 @@ class AppearanceScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on language selection dialog cancel click should dismiss dialog`() {
|
||||
composeTestRule.onNodeWithText("Language").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Default (System). Language")
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Cancel")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
@@ -103,7 +115,13 @@ class AppearanceScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on theme row click should display theme selection dialog`() {
|
||||
composeTestRule.onNodeWithText("Theme").performClick()
|
||||
composeTestRule.onRoot().printToLog("Brian")
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "Default (System). Theme. Change the application's color theme.",
|
||||
)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Theme")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
@@ -112,7 +130,12 @@ class AppearanceScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on theme selection dialog item click should send ThemeChange`() {
|
||||
composeTestRule.onNodeWithText("Theme").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "Default (System). Theme. Change the application's color theme.",
|
||||
)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Dark")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
@@ -130,7 +153,12 @@ class AppearanceScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on theme selection dialog cancel click should dismiss dialog`() {
|
||||
composeTestRule.onNodeWithText("Theme").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "Default (System). Theme. Change the application's color theme.",
|
||||
)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Cancel")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
|
||||
@@ -369,7 +369,7 @@ class AutoFillScreenTest : BaseComposeTest() {
|
||||
fun `on default URI match type click should display dialog`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
composeTestRule
|
||||
.onNodeWithText("Default URI match detection")
|
||||
.onNodeWithContentDescription(label = "Default URI match detection.", substring = true)
|
||||
.performScrollTo()
|
||||
.assert(!hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
@@ -383,7 +383,7 @@ class AutoFillScreenTest : BaseComposeTest() {
|
||||
@Test
|
||||
fun `on default URI match type dialog item click should send DefaultUriMatchTypeSelect and close the dialog`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Default URI match detection")
|
||||
.onNodeWithContentDescription(label = "Default URI match detection.", substring = true)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -402,11 +402,10 @@ class AutoFillScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on default URI match type dialog cancel click should close the dialog`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Default URI match detection")
|
||||
.onNodeWithContentDescription(label = "Default URI match detection.", substring = true)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
@@ -422,19 +421,19 @@ class AutoFillScreenTest : BaseComposeTest() {
|
||||
@Test
|
||||
fun `default URI match type should update according to state`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Base domain")
|
||||
.onNodeWithContentDescription(label = "Base domain", substring = true)
|
||||
.assertExists()
|
||||
composeTestRule
|
||||
.onNodeWithText("Starts with")
|
||||
.onNodeWithContentDescription(label = "Starts with", substring = true)
|
||||
.assertDoesNotExist()
|
||||
mutableStateFlow.update {
|
||||
it.copy(defaultUriMatchType = UriMatchType.STARTS_WITH)
|
||||
}
|
||||
composeTestRule
|
||||
.onNodeWithText("Base domain")
|
||||
.onNodeWithContentDescription(label = "Base domain", substring = true)
|
||||
.assertDoesNotExist()
|
||||
composeTestRule
|
||||
.onNodeWithText("Starts with")
|
||||
.onNodeWithContentDescription(label = "Starts with", substring = true)
|
||||
.assertExists()
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,13 @@ class OtherScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on clear clipboard row click should show show clipboard selection dialog`() {
|
||||
composeTestRule.onNodeWithText("Clear clipboard").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "Never. Clear clipboard. " +
|
||||
"Automatically clear copied values from your clipboard.",
|
||||
)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Clear clipboard")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
@@ -97,7 +103,13 @@ class OtherScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on clear clipboard dialog item click should send ClearClipboardFrequencyChange`() {
|
||||
composeTestRule.onNodeWithText("Clear clipboard").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "Never. Clear clipboard. " +
|
||||
"Automatically clear copied values from your clipboard.",
|
||||
)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("10 seconds")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
@@ -115,7 +127,13 @@ class OtherScreenTest : BaseComposeTest() {
|
||||
|
||||
@Test
|
||||
fun `on clear clipboard dialog cancel should dismiss dialog`() {
|
||||
composeTestRule.onNodeWithText("Clear clipboard").performClick()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "Never. Clear clipboard. " +
|
||||
"Automatically clear copied values from your clipboard.",
|
||||
)
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
composeTestRule.onNodeWithText("Cancel").performClick()
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user