mirror of
https://github.com/bitwarden/android.git
synced 2025-02-17 04:19:54 +03:00
Migrate VaultAddItemScreen to use a LazyColumn (#345)
This commit is contained in:
parent
a91de90fcd
commit
446b0f9da4
6 changed files with 596 additions and 468 deletions
|
@ -0,0 +1,282 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.additem
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledTonalButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledTonalButtonWithIcon
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenIconButtonWithResource
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenMultiSelectButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordFieldWithActions
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitchWithActions
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextFieldWithActions
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.IconResource
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* The UI for adding and editing a login cipher.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
fun LazyListScope.addEditLoginItems(
|
||||
state: VaultAddItemState.ItemType.Login,
|
||||
loginItemTypeHandlers: VaultAddLoginItemTypeHandlers,
|
||||
) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.name),
|
||||
value = state.name,
|
||||
onValueChange = loginItemTypeHandlers.onNameTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextFieldWithActions(
|
||||
label = stringResource(id = R.string.username),
|
||||
value = state.username,
|
||||
onValueChange = loginItemTypeHandlers.onUsernameTextChange,
|
||||
actions = {
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_generator),
|
||||
contentDescription = stringResource(id = R.string.generate_username),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onOpenUsernameGeneratorClick,
|
||||
)
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenPasswordFieldWithActions(
|
||||
label = stringResource(id = R.string.password),
|
||||
value = state.password,
|
||||
onValueChange = loginItemTypeHandlers.onPasswordTextChange,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_check_mark),
|
||||
contentDescription = stringResource(id = R.string.check_password),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onPasswordCheckerClick,
|
||||
)
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_generator),
|
||||
contentDescription = stringResource(id = R.string.generate_password),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onOpenPasswordGeneratorClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.authenticator_key),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButtonWithIcon(
|
||||
label = stringResource(id = R.string.setup_totp),
|
||||
icon = painterResource(id = R.drawable.ic_light_bulb),
|
||||
onClick = loginItemTypeHandlers.onSetupTotpClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.ur_is),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextFieldWithActions(
|
||||
label = stringResource(id = R.string.uri),
|
||||
value = state.uri,
|
||||
onValueChange = loginItemTypeHandlers.onUriTextChange,
|
||||
actions = {
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_settings),
|
||||
contentDescription = stringResource(id = R.string.options),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onUriSettingsClick,
|
||||
)
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButton(
|
||||
label = stringResource(id = R.string.new_uri),
|
||||
onClick = loginItemTypeHandlers.onAddNewUriClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.miscellaneous),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.folder),
|
||||
options = state.availableFolders.toImmutableList(),
|
||||
selectedOption = state.folder,
|
||||
onOptionSelected = loginItemTypeHandlers.onFolderTextChange,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitch(
|
||||
label = stringResource(
|
||||
id = R.string.favorite,
|
||||
),
|
||||
isChecked = state.favorite,
|
||||
onCheckedChange = loginItemTypeHandlers.onToggleFavorite,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitchWithActions(
|
||||
label = stringResource(id = R.string.password_prompt),
|
||||
isChecked = state.masterPasswordReprompt,
|
||||
onCheckedChange = loginItemTypeHandlers.onToggleMasterPasswordReprompt,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
actions = {
|
||||
IconButton(onClick = loginItemTypeHandlers.onTooltipClick) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_tooltip),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = stringResource(
|
||||
id = R.string.master_password_re_prompt_help,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.notes),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
singleLine = false,
|
||||
label = stringResource(id = R.string.notes),
|
||||
value = state.notes,
|
||||
onValueChange = loginItemTypeHandlers.onNotesTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.custom_fields),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButton(
|
||||
label = stringResource(id = R.string.new_custom_field),
|
||||
onClick = loginItemTypeHandlers.onAddNewCustomFieldClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.ownership),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.who_owns_this_item),
|
||||
options = state.availableOwners.toImmutableList(),
|
||||
selectedOption = state.ownership,
|
||||
onOptionSelected = loginItemTypeHandlers.onOwnershipTextChange,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.additem
|
||||
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledTonalButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenMultiSelectButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitchWithActions
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* The UI for adding and editing a secure notes cipher.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
fun LazyListScope.addEditSecureNotesItems(
|
||||
state: VaultAddItemState.ItemType.SecureNotes,
|
||||
secureNotesTypeHandlers: VaultAddSecureNotesItemTypeHandlers,
|
||||
) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.name),
|
||||
value = state.name,
|
||||
onValueChange = secureNotesTypeHandlers.onNameTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.miscellaneous),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.folder),
|
||||
options = state.availableFolders.map { it.invoke() }.toImmutableList(),
|
||||
selectedOption = state.folderName.invoke(),
|
||||
onOptionSelected = secureNotesTypeHandlers.onFolderTextChange,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitch(
|
||||
label = stringResource(id = R.string.favorite),
|
||||
isChecked = state.favorite,
|
||||
onCheckedChange = secureNotesTypeHandlers.onToggleFavorite,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitchWithActions(
|
||||
label = stringResource(id = R.string.password_prompt),
|
||||
isChecked = state.masterPasswordReprompt,
|
||||
onCheckedChange = secureNotesTypeHandlers.onToggleMasterPasswordReprompt,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
actions = {
|
||||
IconButton(onClick = secureNotesTypeHandlers.onTooltipClick) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_tooltip),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = stringResource(
|
||||
id = R.string.master_password_re_prompt_help,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.notes),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
singleLine = false,
|
||||
label = stringResource(id = R.string.notes),
|
||||
value = state.notes,
|
||||
onValueChange = secureNotesTypeHandlers.onNotesTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.custom_fields),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButton(
|
||||
label = stringResource(id = R.string.new_custom_field),
|
||||
onClick = secureNotesTypeHandlers.onAddNewCustomFieldClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.ownership),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.who_owns_this_item),
|
||||
options = state.availableOwners.toImmutableList(),
|
||||
selectedOption = state.ownership,
|
||||
onOptionSelected = secureNotesTypeHandlers.onOwnershipTextChange,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ fun NavGraphBuilder.vaultAddItemDestination(
|
|||
onNavigateBack: () -> Unit,
|
||||
) {
|
||||
composable(
|
||||
ADD_ITEM_ROUTE,
|
||||
route = ADD_ITEM_ROUTE,
|
||||
enterTransition = TransitionProviders.Enter.slideUp,
|
||||
exitTransition = TransitionProviders.Exit.slideDown,
|
||||
popEnterTransition = TransitionProviders.Enter.slideUp,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.additem
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -10,12 +8,8 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -31,20 +25,11 @@ 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.components.BitwardenFilledTonalButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledTonalButtonWithIcon
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenIconButtonWithResource
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenMultiSelectButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordFieldWithActions
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitchWithActions
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextFieldWithActions
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.IconResource
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
|
@ -58,7 +43,6 @@ fun VaultAddItemScreen(
|
|||
viewModel: VaultAddItemViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val scrollState = rememberScrollState()
|
||||
val context = LocalContext.current
|
||||
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
|
@ -80,10 +64,8 @@ fun VaultAddItemScreen(
|
|||
}
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
|
||||
BitwardenScaffold(
|
||||
modifier = Modifier
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
topBar = {
|
||||
|
@ -106,32 +88,36 @@ fun VaultAddItemScreen(
|
|||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.imePadding()
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState),
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.item_information),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
TypeOptionsItem(
|
||||
selectedType = state.selectedType,
|
||||
onTypeOptionClicked = remember(viewModel) {
|
||||
{ typeOption: VaultAddItemState.ItemTypeOption ->
|
||||
viewModel.trySendAction(VaultAddItemAction.TypeOptionSelect(typeOption))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
item {
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.item_information),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
TypeOptionsItem(
|
||||
selectedType = state.selectedType,
|
||||
onTypeOptionClicked = remember(viewModel) {
|
||||
{ typeOption: VaultAddItemState.ItemTypeOption ->
|
||||
viewModel.trySendAction(VaultAddItemAction.TypeOptionSelect(typeOption))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
when (val selectedType = state.selectedType) {
|
||||
is VaultAddItemState.ItemType.Login -> {
|
||||
AddLoginTypeItemContent(
|
||||
addEditLoginItems(
|
||||
state = selectedType,
|
||||
loginItemTypeHandlers = loginItemTypeHandlers,
|
||||
)
|
||||
|
@ -146,12 +132,16 @@ fun VaultAddItemScreen(
|
|||
}
|
||||
|
||||
is VaultAddItemState.ItemType.SecureNotes -> {
|
||||
AddSecureNotesTypeItemContent(
|
||||
addEditSecureNotesItems(
|
||||
state = selectedType,
|
||||
secureNotesTypeHandlers = secureNotesTypeHandlers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,340 +169,3 @@ private fun TypeOptionsItem(
|
|||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun ColumnScope.AddLoginTypeItemContent(
|
||||
state: VaultAddItemState.ItemType.Login,
|
||||
loginItemTypeHandlers: VaultAddLoginItemTypeHandlers,
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.name),
|
||||
value = state.name,
|
||||
onValueChange = loginItemTypeHandlers.onNameTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextFieldWithActions(
|
||||
label = stringResource(id = R.string.username),
|
||||
value = state.username,
|
||||
onValueChange = loginItemTypeHandlers.onUsernameTextChange,
|
||||
actions = {
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_generator),
|
||||
contentDescription = stringResource(id = R.string.generate_username),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onOpenUsernameGeneratorClick,
|
||||
)
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenPasswordFieldWithActions(
|
||||
label = stringResource(id = R.string.password),
|
||||
value = state.password,
|
||||
onValueChange = loginItemTypeHandlers.onPasswordTextChange,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_check_mark),
|
||||
contentDescription = stringResource(id = R.string.check_password),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onPasswordCheckerClick,
|
||||
)
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_generator),
|
||||
contentDescription = stringResource(id = R.string.generate_password),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onOpenPasswordGeneratorClick,
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.authenticator_key),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButtonWithIcon(
|
||||
label = stringResource(id = R.string.setup_totp),
|
||||
icon = painterResource(id = R.drawable.ic_light_bulb),
|
||||
onClick = loginItemTypeHandlers.onSetupTotpClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.ur_is),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextFieldWithActions(
|
||||
label = stringResource(id = R.string.uri),
|
||||
value = state.uri,
|
||||
onValueChange = loginItemTypeHandlers.onUriTextChange,
|
||||
actions = {
|
||||
BitwardenIconButtonWithResource(
|
||||
iconRes = IconResource(
|
||||
iconPainter = painterResource(id = R.drawable.ic_settings),
|
||||
contentDescription = stringResource(id = R.string.options),
|
||||
),
|
||||
onClick = loginItemTypeHandlers.onUriSettingsClick,
|
||||
)
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButton(
|
||||
label = stringResource(id = R.string.new_uri),
|
||||
onClick = loginItemTypeHandlers.onAddNewUriClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.miscellaneous),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.folder),
|
||||
options = state.availableFolders.toImmutableList(),
|
||||
selectedOption = state.folder,
|
||||
onOptionSelected = loginItemTypeHandlers.onFolderTextChange,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitch(
|
||||
label = stringResource(
|
||||
id = R.string.favorite,
|
||||
),
|
||||
isChecked = state.favorite,
|
||||
onCheckedChange = loginItemTypeHandlers.onToggleFavorite,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitchWithActions(
|
||||
label = stringResource(id = R.string.password_prompt),
|
||||
isChecked = state.masterPasswordReprompt,
|
||||
onCheckedChange = loginItemTypeHandlers.onToggleMasterPasswordReprompt,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
actions = {
|
||||
IconButton(onClick = loginItemTypeHandlers.onTooltipClick) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_tooltip),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = stringResource(
|
||||
id = R.string.master_password_re_prompt_help,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.notes),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
singleLine = false,
|
||||
label = stringResource(id = R.string.notes),
|
||||
value = state.notes,
|
||||
onValueChange = loginItemTypeHandlers.onNotesTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.custom_fields),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButton(
|
||||
label = stringResource(id = R.string.new_custom_field),
|
||||
onClick = loginItemTypeHandlers.onAddNewCustomFieldClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.ownership),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.who_owns_this_item),
|
||||
options = state.availableOwners.toImmutableList(),
|
||||
selectedOption = state.ownership,
|
||||
onOptionSelected = loginItemTypeHandlers.onOwnershipTextChange,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun ColumnScope.AddSecureNotesTypeItemContent(
|
||||
state: VaultAddItemState.ItemType.SecureNotes,
|
||||
secureNotesTypeHandlers: VaultAddSecureNotesItemTypeHandlers,
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.name),
|
||||
value = state.name,
|
||||
onValueChange = secureNotesTypeHandlers.onNameTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.miscellaneous),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.folder),
|
||||
options = state.availableFolders.map { it.invoke() }.toImmutableList(),
|
||||
selectedOption = state.folderName.invoke(),
|
||||
onOptionSelected = secureNotesTypeHandlers.onFolderTextChange,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitch(
|
||||
label = stringResource(id = R.string.favorite),
|
||||
isChecked = state.favorite,
|
||||
onCheckedChange = secureNotesTypeHandlers.onToggleFavorite,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitchWithActions(
|
||||
label = stringResource(id = R.string.password_prompt),
|
||||
isChecked = state.masterPasswordReprompt,
|
||||
onCheckedChange = secureNotesTypeHandlers.onToggleMasterPasswordReprompt,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
actions = {
|
||||
IconButton(onClick = secureNotesTypeHandlers.onTooltipClick) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_tooltip),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
contentDescription = stringResource(
|
||||
id = R.string.master_password_re_prompt_help,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.notes),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenTextField(
|
||||
singleLine = false,
|
||||
label = stringResource(id = R.string.notes),
|
||||
value = state.notes,
|
||||
onValueChange = secureNotesTypeHandlers.onNotesTextChange,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.custom_fields),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenFilledTonalButton(
|
||||
label = stringResource(id = R.string.new_custom_field),
|
||||
onClick = secureNotesTypeHandlers.onAddNewCustomFieldClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.ownership),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenMultiSelectButton(
|
||||
label = stringResource(id = R.string.who_owns_this_item),
|
||||
options = state.availableOwners.toImmutableList(),
|
||||
selectedOption = state.ownership,
|
||||
onOptionSelected = secureNotesTypeHandlers.onOwnershipTextChange,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
|
|
|
@ -4,11 +4,15 @@ import androidx.compose.ui.semantics.SemanticsProperties
|
|||
import androidx.compose.ui.semantics.getOrNull
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import androidx.compose.ui.test.SemanticsNodeInteraction
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionCollection
|
||||
import androidx.compose.ui.test.hasContentDescription
|
||||
import androidx.compose.ui.test.hasScrollToNodeAction
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import androidx.compose.ui.test.onAllNodesWithContentDescription
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onFirst
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
|
@ -44,11 +48,44 @@ fun ComposeContentTestRule.onNodeWithTextAfterScroll(text: String): SemanticsNod
|
|||
return onNodeWithText(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper used to scroll to and get the matching node in a scrollable list. This is intended to
|
||||
* be used with lazy lists that would otherwise fail when calling [performScrollToNode].
|
||||
*/
|
||||
fun ComposeContentTestRule.onNodeWithContentDescriptionAfterScroll(
|
||||
label: String,
|
||||
): SemanticsNodeInteraction {
|
||||
onNode(hasScrollToNodeAction()).performScrollToNode(hasContentDescription(label))
|
||||
return onNodeWithContentDescription(label)
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper used to scroll to and get a thr first matching node in a scrollable list. This is
|
||||
* intended to be used with lazy lists that would otherwise fail when calling [performScrollToNode].
|
||||
*/
|
||||
fun ComposeContentTestRule.onFirstNodeWithTextAfterScroll(text: String): SemanticsNodeInteraction {
|
||||
fun ComposeContentTestRule.onAllNodesWithTextAfterScroll(
|
||||
text: String,
|
||||
): SemanticsNodeInteractionCollection {
|
||||
onNode(hasScrollToNodeAction()).performScrollToNode(hasText(text))
|
||||
return onAllNodesWithText(text).onFirst()
|
||||
return onAllNodesWithText(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper used to scroll to and get a thr first matching node in a scrollable list. This is
|
||||
* intended to be used with lazy lists that would otherwise fail when calling [performScrollToNode].
|
||||
*/
|
||||
fun ComposeContentTestRule.onAllNodesWithContentDescriptionAfterScroll(
|
||||
label: String,
|
||||
): SemanticsNodeInteractionCollection {
|
||||
onNode(hasScrollToNodeAction()).performScrollToNode(hasContentDescription(label))
|
||||
return onAllNodesWithContentDescription(label)
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper used to scroll to and get all matching nodes in a scrollable list. This is intended
|
||||
* to be used with lazy lists that would otherwise fail when calling [performScrollToNode].
|
||||
*/
|
||||
fun ComposeContentTestRule.onFirstNodeWithTextAfterScroll(
|
||||
text: String,
|
||||
): SemanticsNodeInteraction =
|
||||
onAllNodesWithTextAfterScroll(text).onFirst()
|
||||
|
|
|
@ -9,7 +9,6 @@ import androidx.compose.ui.test.click
|
|||
import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasContentDescription
|
||||
import androidx.compose.ui.test.hasSetTextAction
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onFirst
|
||||
import androidx.compose.ui.test.onLast
|
||||
|
@ -22,6 +21,9 @@ import androidx.compose.ui.test.performTextInput
|
|||
import androidx.compose.ui.test.performTouchInput
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.util.onAllNodesWithTextAfterScroll
|
||||
import com.x8bit.bitwarden.ui.util.onNodeWithContentDescriptionAfterScroll
|
||||
import com.x8bit.bitwarden.ui.util.onNodeWithTextAfterScroll
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
|
@ -85,7 +87,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
|
||||
// Opens the menu
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Type, Login")
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Type, Login")
|
||||
.performClick()
|
||||
|
||||
// Choose the option from the menu
|
||||
|
@ -109,13 +111,13 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Type, Login")
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Type, Login")
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { it.copy(selectedType = VaultAddItemState.ItemType.Card) }
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Type, Card")
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Type, Card")
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
|
@ -126,7 +128,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Name")
|
||||
.onNodeWithTextAfterScroll(text = "Name")
|
||||
.performTextInput(text = "TestName")
|
||||
|
||||
verify {
|
||||
|
@ -143,7 +145,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Name")
|
||||
.onNodeWithTextAfterScroll(text = "Name")
|
||||
.assertTextContains("")
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -151,7 +153,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Name")
|
||||
.onNodeWithTextAfterScroll(text = "Name")
|
||||
.assertTextContains("NewName")
|
||||
}
|
||||
|
||||
|
@ -162,7 +164,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Username")
|
||||
.onNodeWithTextAfterScroll(text = "Username")
|
||||
.performTextInput(text = "TestUsername")
|
||||
|
||||
verify {
|
||||
|
@ -179,7 +181,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Username")
|
||||
.onNodeWithTextAfterScroll(text = "Username")
|
||||
.assertTextContains("")
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -187,7 +189,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Username")
|
||||
.onNodeWithTextAfterScroll(text = "Username")
|
||||
.assertTextContains("NewUsername")
|
||||
}
|
||||
|
||||
|
@ -199,7 +201,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Generate username")
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Generate username")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -217,10 +219,9 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Password")
|
||||
.onNodeWithTextAfterScroll(text = "Password")
|
||||
.onSiblings()
|
||||
.onFirst()
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -236,10 +237,9 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Password")
|
||||
.onNodeWithTextAfterScroll(text = "Password")
|
||||
.onSiblings()
|
||||
.onLast()
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -256,7 +256,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Password")
|
||||
.onNodeWithTextAfterScroll(text = "Password")
|
||||
.performTextInput(text = "TestPassword")
|
||||
|
||||
verify {
|
||||
|
@ -273,7 +273,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Password")
|
||||
.onNodeWithTextAfterScroll(text = "Password")
|
||||
.assertTextContains("")
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -281,7 +281,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Password")
|
||||
.onNodeWithTextAfterScroll(text = "Password")
|
||||
.assertTextContains("•••••••••••")
|
||||
}
|
||||
|
||||
|
@ -292,8 +292,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Set up TOTP")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll(text = "Set up TOTP")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -310,8 +309,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("URI")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll("URI")
|
||||
.performTextInput("TestURI")
|
||||
|
||||
verify {
|
||||
|
@ -328,7 +326,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "URI")
|
||||
.onNodeWithTextAfterScroll("URI")
|
||||
.assertTextContains("")
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -336,7 +334,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "URI")
|
||||
.onNodeWithTextAfterScroll(text = "URI")
|
||||
.assertTextContains("NewURI")
|
||||
}
|
||||
|
||||
|
@ -348,10 +346,9 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "URI")
|
||||
.onNodeWithTextAfterScroll(text = "URI")
|
||||
.onSiblings()
|
||||
.filterToOne(hasContentDescription(value = "Options"))
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -368,8 +365,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "New URI")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll(text = "New URI")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -387,8 +383,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
|
||||
// Opens the menu
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Folder, No Folder")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Folder, No Folder")
|
||||
.performClick()
|
||||
|
||||
// Choose the option from the menu
|
||||
|
@ -412,8 +407,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Folder, No Folder")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Folder, No Folder")
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -421,8 +415,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Folder, Folder 2")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Folder, Folder 2")
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
|
@ -433,8 +426,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
VaultAddItemScreen(viewModel = viewModel, onNavigateBack = {})
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText("Favorite")
|
||||
.performScrollTo()
|
||||
composeTestRule
|
||||
.onNodeWithTextAfterScroll("Favorite")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -453,7 +446,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Favorite")
|
||||
.onNodeWithTextAfterScroll("Favorite")
|
||||
.assertIsOff()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -461,7 +454,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Favorite")
|
||||
.onNodeWithTextAfterScroll("Favorite")
|
||||
.assertIsOn()
|
||||
}
|
||||
|
||||
|
@ -473,8 +466,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Master password re-prompt")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll("Master password re-prompt")
|
||||
.performTouchInput {
|
||||
click(position = Offset(x = 1f, y = center.y))
|
||||
}
|
||||
|
@ -496,7 +488,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Master password re-prompt")
|
||||
.onNodeWithTextAfterScroll("Master password re-prompt")
|
||||
.assertIsOff()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -504,7 +496,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Master password re-prompt")
|
||||
.onNodeWithTextAfterScroll("Master password re-prompt")
|
||||
.assertIsOn()
|
||||
}
|
||||
|
||||
|
@ -515,8 +507,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
VaultAddItemScreen(viewModel = viewModel, onNavigateBack = {})
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithContentDescription(label = "Master password re-prompt help")
|
||||
.performScrollTo()
|
||||
composeTestRule
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Master password re-prompt help")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -533,8 +525,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasSetTextAction() and hasText("Notes"))
|
||||
.performScrollTo()
|
||||
.onAllNodesWithTextAfterScroll("Notes")
|
||||
.filterToOne(hasSetTextAction())
|
||||
.performTextInput("TestNotes")
|
||||
|
||||
verify {
|
||||
|
@ -551,15 +543,17 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasSetTextAction() and hasText("Notes"))
|
||||
.assertTextContains("")
|
||||
.onAllNodesWithTextAfterScroll("Notes")
|
||||
.filterToOne(hasSetTextAction())
|
||||
.performTextInput("")
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateLoginType(currentState) { copy(notes = "NewNote") }
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasSetTextAction() and hasText("Notes"))
|
||||
.onAllNodesWithTextAfterScroll("Notes")
|
||||
.filterToOne(hasSetTextAction())
|
||||
.assertTextContains("NewNote")
|
||||
}
|
||||
|
||||
|
@ -571,8 +565,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "New custom field")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll(text = "New custom field")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -588,8 +581,9 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
|
||||
// Opens the menu
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Who owns this item?, placeholder@email.com")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(
|
||||
label = "Who owns this item?, placeholder@email.com",
|
||||
)
|
||||
.performClick()
|
||||
|
||||
// Choose the option from the menu
|
||||
|
@ -613,8 +607,9 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Who owns this item?, placeholder@email.com")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(
|
||||
label = "Who owns this item?, placeholder@email.com",
|
||||
)
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -622,8 +617,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Who owns this item?, Owner 2")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Who owns this item?, Owner 2")
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
|
@ -637,7 +631,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Name")
|
||||
.onNodeWithTextAfterScroll(text = "Name")
|
||||
.performTextInput(text = "TestName")
|
||||
|
||||
verify {
|
||||
|
@ -657,7 +651,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Name")
|
||||
.onNodeWithTextAfterScroll(text = "Name")
|
||||
.assertTextContains("")
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -665,7 +659,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "Name")
|
||||
.onNodeWithTextAfterScroll(text = "Name")
|
||||
.assertTextContains("NewName")
|
||||
}
|
||||
|
||||
|
@ -680,8 +674,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
|
||||
// Opens the menu
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Folder, No Folder")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Folder, No Folder")
|
||||
.performClick()
|
||||
|
||||
// Choose the option from the menu
|
||||
|
@ -709,8 +702,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Folder, No Folder")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Folder, No Folder")
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -718,8 +710,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Folder, Folder 2")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Folder, Folder 2")
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
|
@ -734,8 +725,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Favorite")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll("Favorite")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -758,7 +748,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Favorite")
|
||||
.onNodeWithTextAfterScroll("Favorite")
|
||||
.assertIsOff()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -766,7 +756,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Favorite")
|
||||
.onNodeWithTextAfterScroll("Favorite")
|
||||
.assertIsOn()
|
||||
}
|
||||
|
||||
|
@ -781,8 +771,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Master password re-prompt")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll("Master password re-prompt")
|
||||
.performTouchInput {
|
||||
click(position = Offset(x = 1f, y = center.y))
|
||||
}
|
||||
|
@ -807,7 +796,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Master password re-prompt")
|
||||
.onNodeWithTextAfterScroll("Master password re-prompt")
|
||||
.assertIsOff()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -815,7 +804,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Master password re-prompt")
|
||||
.onNodeWithTextAfterScroll("Master password re-prompt")
|
||||
.assertIsOn()
|
||||
}
|
||||
|
||||
|
@ -830,8 +819,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Master password re-prompt help")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Master password re-prompt help")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -851,8 +839,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasSetTextAction() and hasText("Notes"))
|
||||
.performScrollTo()
|
||||
.onAllNodesWithTextAfterScroll("Notes")
|
||||
.filterToOne(hasSetTextAction())
|
||||
.performTextInput("TestNotes")
|
||||
|
||||
verify {
|
||||
|
@ -873,7 +861,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasSetTextAction() and hasText("Notes"))
|
||||
.onAllNodesWithTextAfterScroll("Notes")
|
||||
.filterToOne(hasSetTextAction())
|
||||
.assertTextContains("")
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -881,7 +870,8 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasSetTextAction() and hasText("Notes"))
|
||||
.onAllNodesWithTextAfterScroll("Notes")
|
||||
.filterToOne(hasSetTextAction())
|
||||
.assertTextContains("NewNote")
|
||||
}
|
||||
|
||||
|
@ -896,8 +886,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(text = "New custom field")
|
||||
.performScrollTo()
|
||||
.onNodeWithTextAfterScroll(text = "New custom field")
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
|
@ -919,8 +908,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
|
||||
// Opens the menu
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Who owns this item?, placeholder@email.com")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Who owns this item?, placeholder@email.com")
|
||||
.performClick()
|
||||
|
||||
// Choose the option from the menu
|
||||
|
@ -948,8 +936,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Who owns this item?, placeholder@email.com")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Who owns this item?, placeholder@email.com")
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
|
@ -957,8 +944,7 @@ class VaultAddItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(label = "Who owns this item?, Owner 2")
|
||||
.performScrollTo()
|
||||
.onNodeWithContentDescriptionAfterScroll(label = "Who owns this item?, Owner 2")
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue