mirror of
https://github.com/bitwarden/android.git
synced 2024-11-23 09:56:11 +03:00
Update androidx dependecies and target API (#4212)
This commit is contained in:
parent
072c3a992c
commit
911c9e4704
70 changed files with 727 additions and 771 deletions
|
@ -9,7 +9,7 @@
|
|||
## Compatibility
|
||||
|
||||
- **Minimum SDK**: 29
|
||||
- **Target SDK**: 34
|
||||
- **Target SDK**: 35
|
||||
- **Device Types Supported**: Phone and Tablet
|
||||
- **Orientations Supported**: Portrait and Landscape
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
|
@ -134,14 +133,13 @@ fun SetupAutoFillScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
SetupAutoFillContent(
|
||||
state = state,
|
||||
onAutofillServiceChanged = { handler.onAutofillServiceChanged(it) },
|
||||
onContinueClick = handler.onContinueClick,
|
||||
onTurnOnLaterClick = handler.onTurnOnLaterClick,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.fillMaxSize(),
|
||||
)
|
||||
|
|
|
@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
|
@ -62,11 +61,9 @@ fun SetupCompleteScreen(
|
|||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) { innerPadding ->
|
||||
) {
|
||||
SetupCompleteContent(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
onContinue = setupCompleteAction,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -128,15 +128,13 @@ fun SetupUnlockScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
SetupUnlockScreenContent(
|
||||
state = state,
|
||||
showBiometricsPrompt = showBiometricsPrompt,
|
||||
handler = handler,
|
||||
biometricsManager = biometricsManager,
|
||||
modifier = Modifier
|
||||
.padding(paddingValues = innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,10 +91,9 @@ fun CheckEmailScreen(
|
|||
onNavigationIconClick = handler.onBackClick,
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
|
|
|
@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
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.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
|
@ -158,10 +157,9 @@ fun CompleteRegistrationScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
|
|
|
@ -187,10 +187,9 @@ fun CreateAccountScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
|
|
|
@ -126,15 +126,13 @@ fun EnterpriseSignOnScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
EnterpriseSignOnScreenContent(
|
||||
state = state,
|
||||
onOrgIdentifierInputChange = remember(viewModel) {
|
||||
{ viewModel.trySendAction(EnterpriseSignOnAction.OrgIdentifierInputChange(it)) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,10 +98,9 @@ fun EnvironmentScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(innerPadding)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
|
|
|
@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
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.material3.ExperimentalMaterial3Api
|
||||
|
@ -72,7 +71,7 @@ fun ExpiredRegistrationLinkScreen(
|
|||
),
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
ExpiredRegistrationLinkContent(
|
||||
onNavigateToLogin = remember(viewModel) {
|
||||
{
|
||||
|
@ -87,7 +86,6 @@ fun ExpiredRegistrationLinkScreen(
|
|||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
)
|
||||
|
|
|
@ -148,7 +148,29 @@ fun LandingScreen(
|
|||
)
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
overlay = {
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onSwitchAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.SwitchAccountClick(it)) }
|
||||
},
|
||||
onLockAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.LockAccountClick(it)) }
|
||||
},
|
||||
onLogoutAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.LogoutAccountClick(it)) }
|
||||
},
|
||||
onAddAccountClick = {
|
||||
// Not available
|
||||
},
|
||||
onDismissRequest = { isAccountMenuVisible = false },
|
||||
isAddAccountAvailable = false,
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
},
|
||||
) {
|
||||
LandingScreenContent(
|
||||
state = state,
|
||||
isAppBarVisible = isAppBarVisible,
|
||||
|
@ -167,32 +189,7 @@ fun LandingScreen(
|
|||
onCreateAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.CreateAccountClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
)
|
||||
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onSwitchAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.SwitchAccountClick(it)) }
|
||||
},
|
||||
onLockAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.LockAccountClick(it)) }
|
||||
},
|
||||
onLogoutAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.LogoutAccountClick(it)) }
|
||||
},
|
||||
onAddAccountClick = {
|
||||
// Not available
|
||||
},
|
||||
onDismissRequest = { isAccountMenuVisible = false },
|
||||
isAddAccountAvailable = false,
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,28 @@ fun LoginScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
overlay = {
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onSwitchAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.SwitchAccountClick(it)) }
|
||||
},
|
||||
onLockAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.LockAccountClick(it)) }
|
||||
},
|
||||
onLogoutAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.LogoutAccountClick(it)) }
|
||||
},
|
||||
onAddAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.AddAccountClick) }
|
||||
},
|
||||
onDismissRequest = { isAccountMenuVisible = false },
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
},
|
||||
) {
|
||||
LoginScreenContent(
|
||||
state = state,
|
||||
onPasswordInputChanged = remember(viewModel) {
|
||||
|
@ -169,31 +190,7 @@ fun LoginScreen(
|
|||
onNotYouButtonClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.NotYouButtonClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
)
|
||||
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onSwitchAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.SwitchAccountClick(it)) }
|
||||
},
|
||||
onLockAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.LockAccountClick(it)) }
|
||||
},
|
||||
onLogoutAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.LogoutAccountClick(it)) }
|
||||
},
|
||||
onAddAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.AddAccountClick) }
|
||||
},
|
||||
onDismissRequest = { isAccountMenuVisible = false },
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,10 +102,7 @@ fun LoginWithDeviceScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
val modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is LoginWithDeviceState.ViewState.Content -> {
|
||||
LoginWithDeviceScreenContent(
|
||||
|
@ -116,12 +113,12 @@ fun LoginWithDeviceScreen(
|
|||
onViewAllLogInOptionsClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginWithDeviceAction.ViewAllLogInOptionsClick) }
|
||||
},
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
LoginWithDeviceState.ViewState.Loading -> BitwardenLoadingContent(
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,12 +98,11 @@ fun MasterPasswordGeneratorScreen(
|
|||
snackbarHost = {
|
||||
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(innerPadding),
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
MasterPasswordGeneratorContent(
|
||||
generatedPassword = state.generatedPassword,
|
||||
|
|
|
@ -80,12 +80,11 @@ fun MasterPasswordGuidanceScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(innerPadding)
|
||||
.standardHorizontalMargin(),
|
||||
) {
|
||||
Column(
|
||||
|
|
|
@ -111,11 +111,9 @@ fun MasterPasswordHintScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
BitwardenTextField(
|
||||
modifier = Modifier
|
||||
|
|
|
@ -74,10 +74,9 @@ fun PreventAccountLockoutScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
|
|
|
@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
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.material3.ExperimentalMaterial3Api
|
||||
|
@ -65,7 +64,7 @@ fun RemovePasswordScreen(
|
|||
navigationIcon = null,
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
RemovePasswordScreenContent(
|
||||
state = state,
|
||||
onContinueClick = remember(viewModel) {
|
||||
|
@ -74,9 +73,7 @@ fun RemovePasswordScreen(
|
|||
onInputChanged = remember(viewModel) {
|
||||
{ viewModel.trySendAction(RemovePasswordAction.InputChanged(it)) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ fun ResetPasswordScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
ResetPasswordScreenContent(
|
||||
state = state,
|
||||
onCurrentPasswordInputChanged = remember(viewModel) {
|
||||
|
@ -136,9 +136,7 @@ fun ResetPasswordScreen(
|
|||
onPasswordHintInputChanged = remember(viewModel) {
|
||||
{ viewModel.trySendAction(ResetPasswordAction.PasswordHintInputChanged(it)) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ fun SetPasswordScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
SetPasswordScreenContent(
|
||||
state = state,
|
||||
onPasswordInputChanged = remember(viewModel) {
|
||||
|
@ -97,7 +97,6 @@ fun SetPasswordScreen(
|
|||
{ viewModel.trySendAction(SetPasswordAction.PasswordHintInputChanged(it)) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.imePadding()
|
||||
.fillMaxSize(),
|
||||
)
|
||||
|
|
|
@ -177,10 +177,9 @@ fun StartRegistrationScreen(
|
|||
onNavigationIconClick = handler.onBackClick,
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
|
|
|
@ -114,10 +114,9 @@ private fun TrustedDeviceScaffold(
|
|||
),
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
|
|
|
@ -160,7 +160,7 @@ fun TwoFactorLoginScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
TwoFactorLoginScreenContent(
|
||||
state = state,
|
||||
onCodeInputChange = remember(viewModel) {
|
||||
|
@ -175,9 +175,7 @@ fun TwoFactorLoginScreen(
|
|||
onResendEmailButtonClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(TwoFactorLoginAction.ResendEmailClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.x8bit.bitwarden.ui.auth.feature.vaultunlock
|
|||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
|
@ -205,99 +204,7 @@ fun VaultUnlockScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
Box {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
if (!state.hideInput) {
|
||||
BitwardenPasswordField(
|
||||
label = state.vaultUnlockType.unlockScreenInputLabel(),
|
||||
value = state.input,
|
||||
onValueChange = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.InputChanged(it)) }
|
||||
},
|
||||
keyboardType = state.vaultUnlockType.unlockScreenKeyboardType,
|
||||
showPasswordTestTag = state
|
||||
.vaultUnlockType
|
||||
.inputFieldVisibilityToggleTestTag,
|
||||
modifier = Modifier
|
||||
.testTag(state.vaultUnlockType.unlockScreenInputTestTag)
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
autoFocus = state.showKeyboard,
|
||||
imeAction = ImeAction.Done,
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.UnlockClick) }
|
||||
},
|
||||
),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Text(
|
||||
text = state.vaultUnlockType.unlockScreenMessage(),
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.logged_in_as_on,
|
||||
state.email,
|
||||
state.environmentUrl,
|
||||
),
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier
|
||||
.testTag("UserAndEnvironmentDataLabel")
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
if (state.showBiometricLogin && biometricsManager.isBiometricsSupported) {
|
||||
BitwardenOutlinedButton(
|
||||
label = stringResource(id = R.string.use_biometrics_to_unlock),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.BiometricsUnlockClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
} else if (state.showBiometricInvalidatedMessage) {
|
||||
Text(
|
||||
text = stringResource(R.string.account_biometric_invalidated),
|
||||
textAlign = TextAlign.Start,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.status.error,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
}
|
||||
if (!state.hideInput) {
|
||||
BitwardenFilledButton(
|
||||
label = stringResource(id = R.string.unlock),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.UnlockClick) }
|
||||
},
|
||||
isEnabled = state.input.isNotEmpty(),
|
||||
modifier = Modifier
|
||||
.testTag("UnlockVaultButton")
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
|
||||
overlay = {
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = accountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
|
@ -315,10 +222,98 @@ fun VaultUnlockScreen(
|
|||
},
|
||||
onDismissRequest = { accountMenuVisible = false },
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
},
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
if (!state.hideInput) {
|
||||
BitwardenPasswordField(
|
||||
label = state.vaultUnlockType.unlockScreenInputLabel(),
|
||||
value = state.input,
|
||||
onValueChange = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.InputChanged(it)) }
|
||||
},
|
||||
keyboardType = state.vaultUnlockType.unlockScreenKeyboardType,
|
||||
showPasswordTestTag = state
|
||||
.vaultUnlockType
|
||||
.inputFieldVisibilityToggleTestTag,
|
||||
modifier = Modifier
|
||||
.testTag(state.vaultUnlockType.unlockScreenInputTestTag)
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
autoFocus = state.showKeyboard,
|
||||
imeAction = ImeAction.Done,
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.UnlockClick) }
|
||||
},
|
||||
),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Text(
|
||||
text = state.vaultUnlockType.unlockScreenMessage(),
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.logged_in_as_on,
|
||||
state.email,
|
||||
state.environmentUrl,
|
||||
),
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
modifier = Modifier
|
||||
.testTag("UserAndEnvironmentDataLabel")
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
if (state.showBiometricLogin && biometricsManager.isBiometricsSupported) {
|
||||
BitwardenOutlinedButton(
|
||||
label = stringResource(id = R.string.use_biometrics_to_unlock),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.BiometricsUnlockClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
} else if (state.showBiometricInvalidatedMessage) {
|
||||
Text(
|
||||
text = stringResource(R.string.account_biometric_invalidated),
|
||||
textAlign = TextAlign.Start,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = BitwardenTheme.colorScheme.status.error,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
}
|
||||
if (!state.hideInput) {
|
||||
BitwardenFilledButton(
|
||||
label = stringResource(id = R.string.unlock),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.UnlockClick) }
|
||||
},
|
||||
isEnabled = state.input.isNotEmpty(),
|
||||
modifier = Modifier
|
||||
.testTag("UnlockVaultButton")
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ fun WelcomeScreen(
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
containerColor = BitwardenTheme.colorScheme.background.secondary,
|
||||
contentColor = BitwardenTheme.colorScheme.text.secondary,
|
||||
) { innerPadding ->
|
||||
) {
|
||||
WelcomeScreenContent(
|
||||
state = state,
|
||||
pagerState = pagerState,
|
||||
|
@ -97,9 +97,7 @@ fun WelcomeScreen(
|
|||
onLoginClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(WelcomeAction.LoginClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,11 +14,18 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
|
@ -107,9 +114,12 @@ fun BitwardenAccountSwitcher(
|
|||
onLogoutAccountClick: (AccountSummary) -> Unit,
|
||||
onAddAccountClick: () -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
isAddAccountAvailable: Boolean = true,
|
||||
topAppBarScrollBehavior: TopAppBarScrollBehavior,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = WindowInsets.displayCutout
|
||||
.union(WindowInsets.navigationBars)
|
||||
.only(WindowInsetsSides.Horizontal),
|
||||
isAddAccountAvailable: Boolean = true,
|
||||
) {
|
||||
// Track the actual visibility (according to the internal transitions) so that we know when we
|
||||
// can safely show dialogs.
|
||||
|
@ -190,6 +200,7 @@ fun BitwardenAccountSwitcher(
|
|||
isAddAccountAvailable = isAddAccountAvailable,
|
||||
topAppBarScrollBehavior = topAppBarScrollBehavior,
|
||||
currentAnimationState = { isVisibleActual = it },
|
||||
windowInsets = windowInsets,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
@ -208,9 +219,12 @@ private fun AnimatedAccountSwitcher(
|
|||
onSwitchAccountLongClick: (AccountSummary) -> Unit,
|
||||
onAddAccountClick: () -> Unit,
|
||||
isAddAccountAvailable: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
topAppBarScrollBehavior: TopAppBarScrollBehavior,
|
||||
currentAnimationState: (isVisible: Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = WindowInsets.displayCutout
|
||||
.union(WindowInsets.navigationBars)
|
||||
.only(WindowInsetsSides.Horizontal),
|
||||
) {
|
||||
val transition = updateTransition(
|
||||
targetState = isVisible,
|
||||
|
@ -229,7 +243,8 @@ private fun AnimatedAccountSwitcher(
|
|||
// bottom padding.
|
||||
.padding(bottom = 24.dp)
|
||||
// Match the color of the switcher the different states of the app bar.
|
||||
.scrolledContainerBackground(topAppBarScrollBehavior),
|
||||
.scrolledContainerBackground(topAppBarScrollBehavior)
|
||||
.windowInsetsPadding(windowInsets),
|
||||
) {
|
||||
items(accountSummaries) { accountSummary ->
|
||||
AccountSummaryItem(
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.appbar
|
||||
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MediumTopAppBar
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -32,6 +37,7 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
|||
* @param title The text to be displayed as the title of the app bar.
|
||||
* @param scrollBehavior Defines the scrolling behavior of the app bar. It controls how the app bar
|
||||
* behaves in conjunction with scrolling content.
|
||||
* @param windowInsets The insets to be applied to this composable.
|
||||
* @param dividerStyle Determines how the bottom divider should be displayed.
|
||||
* @param actions A lambda containing the set of actions (usually icons or similar) to display
|
||||
* in the app bar's trailing side. This lambda extends [RowScope], allowing flexibility in
|
||||
|
@ -43,10 +49,13 @@ fun BitwardenMediumTopAppBar(
|
|||
title: String,
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets
|
||||
.union(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)),
|
||||
dividerStyle: TopAppBarDividerStyle = TopAppBarDividerStyle.ON_SCROLL,
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
) {
|
||||
TopAppBar(
|
||||
windowInsets = windowInsets,
|
||||
colors = bitwardenTopAppBarColors(),
|
||||
scrollBehavior = scrollBehavior,
|
||||
expandedHeight = 56.dp,
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.appbar
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
|
@ -42,6 +48,8 @@ fun BitwardenSearchTopAppBar(
|
|||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
navigationIcon: NavigationIcon?,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets
|
||||
.union(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)),
|
||||
autoFocus: Boolean = true,
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
@ -49,6 +57,7 @@ fun BitwardenSearchTopAppBar(
|
|||
modifier = modifier
|
||||
.testTag(tag = "HeaderBarComponent")
|
||||
.bottomDivider(),
|
||||
windowInsets = windowInsets,
|
||||
colors = bitwardenTopAppBarColors(),
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = {
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.appbar
|
||||
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MediumTopAppBar
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -50,6 +55,8 @@ fun BitwardenTopAppBar(
|
|||
navigationIconContentDescription: String,
|
||||
onNavigationIconClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets
|
||||
.union(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)),
|
||||
dividerStyle: TopAppBarDividerStyle = TopAppBarDividerStyle.ON_SCROLL,
|
||||
actions: @Composable RowScope.() -> Unit = { },
|
||||
) {
|
||||
|
@ -62,6 +69,7 @@ fun BitwardenTopAppBar(
|
|||
onNavigationIconClick = onNavigationIconClick,
|
||||
),
|
||||
modifier = modifier,
|
||||
windowInsets = windowInsets,
|
||||
dividerStyle = dividerStyle,
|
||||
actions = actions,
|
||||
)
|
||||
|
@ -87,6 +95,8 @@ fun BitwardenTopAppBar(
|
|||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
navigationIcon: NavigationIcon?,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets
|
||||
.union(WindowInsets.displayCutout.only(WindowInsetsSides.Horizontal)),
|
||||
dividerStyle: TopAppBarDividerStyle = TopAppBarDividerStyle.ON_SCROLL,
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
minimunHeight: Dp = 48.dp,
|
||||
|
@ -129,6 +139,7 @@ fun BitwardenTopAppBar(
|
|||
|
||||
if (titleTextHasOverflow) {
|
||||
MediumTopAppBar(
|
||||
windowInsets = windowInsets,
|
||||
colors = bitwardenTopAppBarColors(),
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = navigationIconContent,
|
||||
|
@ -149,6 +160,7 @@ fun BitwardenTopAppBar(
|
|||
)
|
||||
} else {
|
||||
TopAppBar(
|
||||
windowInsets = windowInsets,
|
||||
colors = bitwardenTopAppBarColors(),
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = navigationIconContent,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.bottomsheet
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
|
@ -45,10 +44,7 @@ fun BitwardenModalBottomSheet(
|
|||
modifier: Modifier = Modifier,
|
||||
showBottomSheet: Boolean = true,
|
||||
sheetState: SheetState = rememberModalBottomSheetState(),
|
||||
sheetContent: @Composable (
|
||||
paddingValues: PaddingValues,
|
||||
animatedOnDismiss: () -> Unit,
|
||||
) -> Unit,
|
||||
sheetContent: @Composable (animatedOnDismiss: () -> Unit) -> Unit,
|
||||
) {
|
||||
if (!showBottomSheet) return
|
||||
ModalBottomSheet(
|
||||
|
@ -79,8 +75,8 @@ fun BitwardenModalBottomSheet(
|
|||
modifier = Modifier
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
.fillMaxSize(),
|
||||
) { paddingValues ->
|
||||
sheetContent(paddingValues, animatedOnDismiss)
|
||||
) {
|
||||
sheetContent(animatedOnDismiss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.fab
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -14,6 +19,7 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
|||
* @param painter The icon for the button.
|
||||
* @param contentDescription The content description for the button.
|
||||
* @param modifier The [Modifier] to be applied to the button.
|
||||
* @param windowInsets The insets to be applied to this composable.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenFloatingActionButton(
|
||||
|
@ -21,13 +27,14 @@ fun BitwardenFloatingActionButton(
|
|||
painter: Painter,
|
||||
contentDescription: String,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = WindowInsets.displayCutout.union(WindowInsets.navigationBars),
|
||||
) {
|
||||
FloatingActionButton(
|
||||
containerColor = BitwardenTheme.colorScheme.filledButton.background,
|
||||
contentColor = BitwardenTheme.colorScheme.filledButton.foreground,
|
||||
onClick = onClick,
|
||||
shape = BitwardenTheme.shapes.fab,
|
||||
modifier = modifier,
|
||||
modifier = modifier.windowInsetsPadding(insets = windowInsets),
|
||||
) {
|
||||
Icon(
|
||||
painter = painter,
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.scaffold
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.exclude
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.Scaffold
|
||||
|
@ -22,17 +24,25 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
/**
|
||||
* Direct passthrough to [Scaffold] but contains a few specific override values. Everything is
|
||||
* still overridable if necessary.
|
||||
*
|
||||
* The [utilityBar] is a nonstandard [Composable] that is placed below the [topBar] and does not
|
||||
* scroll.
|
||||
* The [overlay] is a nonstandard [Composable] that is placed over top the `utilityBar` and
|
||||
* `content`.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun BitwardenScaffold(
|
||||
modifier: Modifier = Modifier,
|
||||
topBar: @Composable () -> Unit = { },
|
||||
utilityBar: @Composable () -> Unit = { },
|
||||
overlay: @Composable () -> Unit = { },
|
||||
bottomBar: @Composable () -> Unit = { },
|
||||
snackbarHost: @Composable () -> Unit = { },
|
||||
floatingActionButton: @Composable () -> Unit = { },
|
||||
|
@ -42,8 +52,9 @@ fun BitwardenScaffold(
|
|||
contentColor: Color = BitwardenTheme.colorScheme.text.primary,
|
||||
contentWindowInsets: WindowInsets = ScaffoldDefaults
|
||||
.contentWindowInsets
|
||||
.exclude(WindowInsets.navigationBars),
|
||||
content: @Composable (PaddingValues) -> Unit,
|
||||
.union(WindowInsets.displayCutout)
|
||||
.only(WindowInsetsSides.Horizontal),
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
|
@ -52,36 +63,38 @@ fun BitwardenScaffold(
|
|||
topBar = topBar,
|
||||
bottomBar = bottomBar,
|
||||
snackbarHost = snackbarHost,
|
||||
floatingActionButton = {
|
||||
Box(modifier = Modifier.navigationBarsPadding()) {
|
||||
floatingActionButton()
|
||||
}
|
||||
},
|
||||
floatingActionButton = floatingActionButton,
|
||||
floatingActionButtonPosition = floatingActionButtonPosition,
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
contentWindowInsets = contentWindowInsets,
|
||||
contentWindowInsets = WindowInsets(0.dp),
|
||||
content = { paddingValues ->
|
||||
val internalPullToRefreshState = rememberPullToRefreshState()
|
||||
Box(
|
||||
modifier = Modifier.pullToRefresh(
|
||||
state = internalPullToRefreshState,
|
||||
isRefreshing = pullToRefreshState.isRefreshing,
|
||||
onRefresh = pullToRefreshState.onRefresh,
|
||||
enabled = pullToRefreshState.isEnabled,
|
||||
),
|
||||
) {
|
||||
content(paddingValues)
|
||||
|
||||
PullToRefreshDefaults.Indicator(
|
||||
Column(modifier = Modifier.padding(paddingValues = paddingValues)) {
|
||||
utilityBar()
|
||||
val internalPullToRefreshState = rememberPullToRefreshState()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.align(Alignment.TopCenter),
|
||||
isRefreshing = pullToRefreshState.isRefreshing,
|
||||
state = internalPullToRefreshState,
|
||||
containerColor = BitwardenTheme.colorScheme.background.secondary,
|
||||
color = BitwardenTheme.colorScheme.icon.secondary,
|
||||
)
|
||||
.windowInsetsPadding(insets = contentWindowInsets)
|
||||
.pullToRefresh(
|
||||
state = internalPullToRefreshState,
|
||||
isRefreshing = pullToRefreshState.isRefreshing,
|
||||
onRefresh = pullToRefreshState.onRefresh,
|
||||
enabled = pullToRefreshState.isEnabled,
|
||||
),
|
||||
) {
|
||||
content()
|
||||
|
||||
PullToRefreshDefaults.Indicator(
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
isRefreshing = pullToRefreshState.isRefreshing,
|
||||
state = internalPullToRefreshState,
|
||||
containerColor = BitwardenTheme.colorScheme.background.secondary,
|
||||
color = BitwardenTheme.colorScheme.icon.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.padding(paddingValues = paddingValues)) {
|
||||
overlay()
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -3,8 +3,15 @@ package com.x8bit.bitwarden.ui.platform.components.segment
|
|||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material3.SegmentedButton
|
||||
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -23,17 +30,22 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
*
|
||||
* @param options List of options to display.
|
||||
* @param modifier Modifier.
|
||||
* @param windowInsets The insets to be applied to this composable.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenSegmentedButton(
|
||||
options: ImmutableList<SegmentedButtonState>,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = WindowInsets.displayCutout
|
||||
.union(WindowInsets.navigationBars)
|
||||
.only(WindowInsetsSides.Horizontal),
|
||||
) {
|
||||
if (options.isEmpty()) return
|
||||
Box(
|
||||
modifier = modifier
|
||||
.background(color = BitwardenTheme.colorScheme.background.secondary)
|
||||
.padding(top = 4.dp, bottom = 8.dp, start = 16.dp, end = 16.dp),
|
||||
.padding(top = 4.dp, bottom = 8.dp, start = 16.dp, end = 16.dp)
|
||||
.windowInsetsPadding(insets = windowInsets),
|
||||
) {
|
||||
SingleChoiceSegmentedButtonRow(
|
||||
modifier = Modifier
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.snackbar
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -9,15 +14,17 @@ import androidx.compose.ui.Modifier
|
|||
*
|
||||
* @param bitwardenHostState The state of this snackbar.
|
||||
* @param modifier The [Modifier] to be applied to the [SnackbarHost].
|
||||
* @param windowInsets The insets to be applied to this composable.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenSnackbarHost(
|
||||
bitwardenHostState: BitwardenSnackbarHostState,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = WindowInsets.displayCutout.union(WindowInsets.navigationBars),
|
||||
) {
|
||||
SnackbarHost(
|
||||
hostState = bitwardenHostState.snackbarHostState,
|
||||
modifier = modifier,
|
||||
modifier = modifier.windowInsetsPadding(insets = windowInsets),
|
||||
) { snackbarData ->
|
||||
val message = snackbarData.visuals.message
|
||||
val currentCustomSnackbarData = bitwardenHostState.currentSnackbarData
|
||||
|
|
|
@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
|
@ -74,11 +73,9 @@ fun DebugMenuScreen(
|
|||
),
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(innerPadding),
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
FeatureFlagContent(
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.platform.feature.search
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
|
@ -91,14 +90,7 @@ fun SearchScreen(
|
|||
),
|
||||
)
|
||||
},
|
||||
modifier = Modifier
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding),
|
||||
) {
|
||||
utilityBar = {
|
||||
val vaultFilterData = state.vaultFilterData
|
||||
if (state.viewState.hasVaultFilter && vaultFilterData != null) {
|
||||
VaultFilter(
|
||||
|
@ -116,32 +108,39 @@ fun SearchScreen(
|
|||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is SearchState.ViewState.Content -> SearchContent(
|
||||
viewState = viewState,
|
||||
searchHandlers = searchHandlers,
|
||||
searchType = state.searchType,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
)
|
||||
|
||||
val innerModifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding()
|
||||
when (val viewState = state.viewState) {
|
||||
is SearchState.ViewState.Content -> SearchContent(
|
||||
viewState = viewState,
|
||||
searchHandlers = searchHandlers,
|
||||
searchType = state.searchType,
|
||||
modifier = innerModifier,
|
||||
)
|
||||
is SearchState.ViewState.Empty -> SearchEmptyContent(
|
||||
viewState = viewState,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
)
|
||||
|
||||
is SearchState.ViewState.Empty -> SearchEmptyContent(
|
||||
viewState = viewState,
|
||||
modifier = innerModifier,
|
||||
)
|
||||
is SearchState.ViewState.Error -> BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
)
|
||||
|
||||
is SearchState.ViewState.Error -> BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
modifier = innerModifier,
|
||||
)
|
||||
|
||||
SearchState.ViewState.Loading -> BitwardenLoadingContent(
|
||||
modifier = innerModifier,
|
||||
)
|
||||
}
|
||||
SearchState.ViewState.Loading -> BitwardenLoadingContent(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,10 +80,9 @@ fun SettingsScreen(
|
|||
)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(state = rememberScrollState()),
|
||||
) {
|
||||
|
|
|
@ -111,12 +111,10 @@ fun AboutScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
ContentColumn(
|
||||
state = state,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
onHelpCenterClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AboutAction.HelpCenterClick) }
|
||||
},
|
||||
|
|
|
@ -174,10 +174,9 @@ fun AccountSecurityScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
|
|
|
@ -118,12 +118,11 @@ fun DeleteAccountScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
|
|
@ -218,13 +218,12 @@ private fun DeleteAccountConfirmationScaffold(
|
|||
onNavigationIconClick = onCloseClick,
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
DeleteAccountConfirmationContent(
|
||||
state = state,
|
||||
onDeleteAccountClick = onDeleteAccountClick,
|
||||
onResendCodeClick = onResendCodeClick,
|
||||
onVerificationCodeTextChange = onVerificationCodeTextChange,
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ fun LoginApprovalScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is LoginApprovalState.ViewState.Content -> {
|
||||
LoginApprovalContent(
|
||||
|
@ -115,26 +115,20 @@ fun LoginApprovalScreen(
|
|||
onDeclineLoginClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginApprovalAction.DeclineRequestClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is LoginApprovalState.ViewState.Error -> {
|
||||
BitwardenErrorContent(
|
||||
message = stringResource(id = R.string.generic_error_message),
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is LoginApprovalState.ViewState.Loading -> {
|
||||
BitwardenLoadingContent(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,9 +125,8 @@ fun PendingRequestsScreen(
|
|||
},
|
||||
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
) { paddingValues, animatedOnDismiss ->
|
||||
) { animatedOnDismiss ->
|
||||
PendingRequestsBottomSheetContent(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
permissionsManager = permissionsManager,
|
||||
onDismiss = animatedOnDismiss,
|
||||
)
|
||||
|
@ -150,13 +149,11 @@ fun PendingRequestsScreen(
|
|||
)
|
||||
},
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
) { innerPadding ->
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is PendingRequestsState.ViewState.Content -> {
|
||||
PendingRequestsContent(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = viewState,
|
||||
onDeclineAllRequestsConfirm = remember(viewModel) {
|
||||
{
|
||||
|
@ -176,22 +173,16 @@ fun PendingRequestsScreen(
|
|||
}
|
||||
|
||||
is PendingRequestsState.ViewState.Empty -> PendingRequestsEmpty(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
PendingRequestsState.ViewState.Error -> BitwardenErrorContent(
|
||||
message = stringResource(R.string.generic_error_message),
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
PendingRequestsState.ViewState.Loading -> BitwardenLoadingContent(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,10 +73,9 @@ fun AppearanceScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(innerPadding)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
|
|
|
@ -126,10 +126,9 @@ fun AutoFillScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(innerPadding)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
|
|
|
@ -141,11 +141,9 @@ fun BlockAutoFillScreen(
|
|||
)
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is BlockAutoFillState.ViewState.Content -> {
|
||||
|
@ -191,9 +189,7 @@ fun BlockAutoFillScreen(
|
|||
addItemClickAction = remember(viewModel) {
|
||||
{ viewModel.trySendAction(BlockAutoFillAction.AddUriClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ fun ExportVaultScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
ExportVaultScreenContent(
|
||||
state = state,
|
||||
onConfirmFilePasswordInputChanged = remember(viewModel) {
|
||||
|
@ -179,9 +179,7 @@ fun ExportVaultScreen(
|
|||
{ viewModel.trySendAction(ExportVaultAction.SendCodeClick) }
|
||||
},
|
||||
onExportVaultClick = { shouldShowConfirmationDialog = true },
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ fun FoldersScreen(
|
|||
.navigationBarsPadding(),
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
when (val viewState = state.value.viewState) {
|
||||
is FoldersState.ViewState.Content -> {
|
||||
FoldersContent(
|
||||
|
@ -106,26 +106,20 @@ fun FoldersScreen(
|
|||
onItemClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(FoldersAction.FolderClick(it)) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is FoldersState.ViewState.Error -> {
|
||||
BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is FoldersState.ViewState.Loading -> {
|
||||
BitwardenLoadingContent(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,13 +124,11 @@ fun FolderAddEditScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is FolderAddEditState.ViewState.Content -> {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.name),
|
||||
|
@ -148,17 +146,13 @@ fun FolderAddEditScreen(
|
|||
is FolderAddEditState.ViewState.Error -> {
|
||||
BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is FolderAddEditState.ViewState.Loading -> {
|
||||
BitwardenLoadingContent(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,10 +93,9 @@ fun OtherScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(innerPadding)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
|
|
|
@ -100,10 +100,9 @@ fun VaultSettingsScreen(
|
|||
bitwardenHostState = snackbarHostState,
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(innerPadding)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
|
|
|
@ -2,16 +2,14 @@ package com.x8bit.bitwarden.ui.platform.feature.vaultunlockednavbar
|
|||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.exclude
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.ScaffoldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
|
@ -21,6 +19,7 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
|
@ -35,7 +34,6 @@ import androidx.navigation.compose.currentBackStackEntryAsState
|
|||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navOptions
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.max
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toDp
|
||||
import com.x8bit.bitwarden.ui.platform.components.navigation.BitwardenNavigationBarItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
|
@ -177,10 +175,9 @@ private fun VaultUnlockedNavBarScaffold(
|
|||
var shouldDimNavBar by remember { mutableStateOf(false) }
|
||||
|
||||
// This scaffold will host screens that contain top bars while not hosting one itself.
|
||||
// We need to ignore the status bar insets here and let the content screens handle
|
||||
// it themselves.
|
||||
// We need to ignore the all insets here and let the content screens handle it themselves.
|
||||
BitwardenScaffold(
|
||||
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude(WindowInsets.statusBars),
|
||||
contentWindowInsets = WindowInsets(0.dp),
|
||||
bottomBar = {
|
||||
Box {
|
||||
var appBarHeightPx by remember { mutableIntStateOf(0) }
|
||||
|
@ -208,17 +205,16 @@ private fun VaultUnlockedNavBarScaffold(
|
|||
)
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
// Because this Scaffold has a bottom navigation bar, the NavHost will:
|
||||
// - consume the navigation bar insets.
|
||||
// - consume the vertical navigation bar insets.
|
||||
// - consume the IME insets.
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = VAULT_GRAPH_ROUTE,
|
||||
modifier = Modifier
|
||||
.consumeWindowInsets(WindowInsets.navigationBars)
|
||||
.consumeWindowInsets(WindowInsets.ime)
|
||||
.padding(innerPadding.max(WindowInsets.ime)),
|
||||
.consumeWindowInsets(WindowInsets.navigationBars.only(WindowInsetsSides.Vertical))
|
||||
.consumeWindowInsets(WindowInsets.ime),
|
||||
enterTransition = RootTransitionProviders.Enter.fadeIn,
|
||||
exitTransition = RootTransitionProviders.Exit.fadeOut,
|
||||
popEnterTransition = RootTransitionProviders.Enter.fadeIn,
|
||||
|
|
|
@ -189,12 +189,7 @@ fun GeneratorScreen(
|
|||
}
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) { innerPadding ->
|
||||
Column(modifier = Modifier.padding(innerPadding)) {
|
||||
utilityBar = {
|
||||
MainStateOptionsItem(
|
||||
selectedType = state.selectedType,
|
||||
passcodePolicyOverride = state.passcodePolicyOverride,
|
||||
|
@ -203,20 +198,25 @@ fun GeneratorScreen(
|
|||
modifier = Modifier
|
||||
.scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior),
|
||||
)
|
||||
ScrollContent(
|
||||
state = state,
|
||||
onRegenerateClick = onRegenerateClick,
|
||||
onCopyClick = onCopyClick,
|
||||
onUsernameSubStateOptionClicked = onUsernameOptionClicked,
|
||||
passwordHandlers = passwordHandlers,
|
||||
passphraseHandlers = passphraseHandlers,
|
||||
usernameTypeHandlers = usernameTypeHandlers,
|
||||
forwardedEmailAliasHandlers = forwardedEmailAliasHandlers,
|
||||
plusAddressedEmailHandlers = plusAddressedEmailHandlers,
|
||||
catchAllEmailHandlers = catchAllEmailHandlers,
|
||||
randomWordHandlers = randomWordHandlers,
|
||||
)
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) {
|
||||
ScrollContent(
|
||||
state = state,
|
||||
onRegenerateClick = onRegenerateClick,
|
||||
onCopyClick = onCopyClick,
|
||||
onUsernameSubStateOptionClicked = onUsernameOptionClicked,
|
||||
passwordHandlers = passwordHandlers,
|
||||
passphraseHandlers = passphraseHandlers,
|
||||
usernameTypeHandlers = usernameTypeHandlers,
|
||||
forwardedEmailAliasHandlers = forwardedEmailAliasHandlers,
|
||||
plusAddressedEmailHandlers = plusAddressedEmailHandlers,
|
||||
catchAllEmailHandlers = catchAllEmailHandlers,
|
||||
randomWordHandlers = randomWordHandlers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,30 +97,24 @@ fun PasswordHistoryScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
content = { innerPadding ->
|
||||
content = {
|
||||
when (val viewState = state.viewState) {
|
||||
is PasswordHistoryState.ViewState.Loading -> {
|
||||
PasswordHistoryLoading(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is PasswordHistoryState.ViewState.Error -> {
|
||||
PasswordHistoryError(
|
||||
state = viewState,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is PasswordHistoryState.ViewState.Empty -> {
|
||||
PasswordHistoryEmpty(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -129,8 +123,7 @@ fun PasswordHistoryScreen(
|
|||
state = viewState,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding()
|
||||
.padding(innerPadding),
|
||||
.imePadding(),
|
||||
onPasswordCopyClick = { password ->
|
||||
viewModel.trySendAction(
|
||||
PasswordHistoryAction.PasswordCopyClick(password),
|
||||
|
|
|
@ -6,7 +6,6 @@ import androidx.compose.animation.scaleIn
|
|||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
|
@ -161,11 +160,10 @@ fun SendScreen(
|
|||
}
|
||||
},
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
) { padding ->
|
||||
) {
|
||||
val modifier = Modifier
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
when (val viewState = state.viewState) {
|
||||
is SendState.ViewState.Content -> SendContent(
|
||||
policyDisablesSend = state.policyDisablesSend,
|
||||
|
|
|
@ -21,7 +21,6 @@ import androidx.compose.foundation.verticalScroll
|
|||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -35,22 +34,18 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.scrolledContainerBottomDivider
|
||||
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenTextButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.card.BitwardenInfoCalloutCard
|
||||
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenPasswordField
|
||||
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.segment.BitwardenSegmentedButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.segment.SegmentedButtonState
|
||||
import com.x8bit.bitwarden.ui.platform.components.stepper.BitwardenStepper
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.handlers.AddSendHandlers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Content view for the [AddSendScreen].
|
||||
|
@ -60,7 +55,6 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
@Composable
|
||||
fun AddSendContent(
|
||||
state: AddSendState.ViewState.Content,
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
policyDisablesSend: Boolean,
|
||||
policySendOptionsInEffect: Boolean,
|
||||
isAddMode: Boolean,
|
||||
|
@ -72,201 +66,177 @@ fun AddSendContent(
|
|||
val chooseFileCameraPermissionLauncher = permissionsManager.getLauncher { isGranted ->
|
||||
addSendHandlers.onChooseFileClick(isGranted)
|
||||
}
|
||||
Column(modifier = modifier) {
|
||||
if (isAddMode && !isShared) {
|
||||
BitwardenSegmentedButton(
|
||||
Column(
|
||||
modifier = modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
if (policyDisablesSend) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenInfoCalloutCard(
|
||||
text = stringResource(id = R.string.send_disabled_warning),
|
||||
modifier = Modifier
|
||||
.scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior)
|
||||
.fillMaxWidth(),
|
||||
options = persistentListOf(
|
||||
SegmentedButtonState(
|
||||
text = stringResource(id = R.string.file),
|
||||
onClick = addSendHandlers.onFileTypeSelect,
|
||||
isChecked = state.isFileType,
|
||||
testTag = "SendFileButton",
|
||||
),
|
||||
SegmentedButtonState(
|
||||
text = stringResource(id = R.string.text),
|
||||
onClick = addSendHandlers.onTextTypeSelect,
|
||||
isChecked = state.isTextType,
|
||||
testTag = "SendTextButton",
|
||||
),
|
||||
),
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth()
|
||||
.testTag("SendPolicyInEffectLabel"),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
if (policyDisablesSend) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenInfoCalloutCard(
|
||||
text = stringResource(id = R.string.send_disabled_warning),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth()
|
||||
.testTag("SendPolicyInEffectLabel"),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
if (policySendOptionsInEffect) {
|
||||
BitwardenInfoCalloutCard(
|
||||
text = stringResource(id = R.string.send_options_policy_in_effect),
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendPolicyInEffectLabel")
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
BitwardenTextField(
|
||||
if (policySendOptionsInEffect) {
|
||||
BitwardenInfoCalloutCard(
|
||||
text = stringResource(id = R.string.send_options_policy_in_effect),
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendNameEntry")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
label = stringResource(id = R.string.name),
|
||||
hint = stringResource(id = R.string.name_info),
|
||||
readOnly = policyDisablesSend,
|
||||
value = state.common.name,
|
||||
onValueChange = addSendHandlers.onNamChange,
|
||||
.testTag(tag = "SendPolicyInEffectLabel")
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
when (val type = state.selectedType) {
|
||||
is AddSendState.ViewState.Content.SendType.File -> {
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.file),
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
BitwardenTextField(
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendNameEntry")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
label = stringResource(id = R.string.name),
|
||||
hint = stringResource(id = R.string.name_info),
|
||||
readOnly = policyDisablesSend,
|
||||
value = state.common.name,
|
||||
onValueChange = addSendHandlers.onNamChange,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
when (val type = state.selectedType) {
|
||||
is AddSendState.ViewState.Content.SendType.File -> {
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.file),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (isShared) {
|
||||
Text(
|
||||
text = type.name.orEmpty(),
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.max_file_size),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
} else if (isAddMode) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendCurrentFileNameLabel")
|
||||
.align(Alignment.CenterHorizontally),
|
||||
text = type.name ?: stringResource(id = R.string.no_file_chosen),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenOutlinedButton(
|
||||
label = stringResource(id = R.string.choose_file),
|
||||
onClick = {
|
||||
@Suppress("MaxLineLength")
|
||||
if (permissionsManager.checkPermission(Manifest.permission.CAMERA)) {
|
||||
addSendHandlers.onChooseFileClick(true)
|
||||
} else {
|
||||
chooseFileCameraPermissionLauncher.launch(
|
||||
Manifest.permission.CAMERA,
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendChooseFileButton")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.max_file_size),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 32.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (isShared) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.type_file_info),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
} else {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
Text(
|
||||
text = type.name.orEmpty(),
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
style = BitwardenTheme.typography.bodyLarge,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = type.displaySize.orEmpty(),
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.max_file_size),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
} else if (isAddMode) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendCurrentFileNameLabel")
|
||||
.align(Alignment.CenterHorizontally),
|
||||
text = type.name ?: stringResource(id = R.string.no_file_chosen),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BitwardenOutlinedButton(
|
||||
label = stringResource(id = R.string.choose_file),
|
||||
onClick = {
|
||||
@Suppress("MaxLineLength")
|
||||
if (permissionsManager.checkPermission(Manifest.permission.CAMERA)) {
|
||||
addSendHandlers.onChooseFileClick(true)
|
||||
} else {
|
||||
chooseFileCameraPermissionLauncher.launch(
|
||||
Manifest.permission.CAMERA,
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendChooseFileButton")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.max_file_size),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 32.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.type_file_info),
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
} else {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
Text(
|
||||
text = type.name.orEmpty(),
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
style = BitwardenTheme.typography.bodyLarge,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = type.displaySize.orEmpty(),
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is AddSendState.ViewState.Content.SendType.Text -> {
|
||||
BitwardenTextField(
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendTextContentEntry")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
label = stringResource(id = R.string.text),
|
||||
hint = stringResource(id = R.string.type_text_info),
|
||||
readOnly = policyDisablesSend,
|
||||
value = type.input,
|
||||
singleLine = false,
|
||||
onValueChange = addSendHandlers.onTextChange,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitch(
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendHideTextByDefaultToggle")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
label = stringResource(id = R.string.hide_text_by_default),
|
||||
isChecked = type.isHideByDefaultChecked,
|
||||
onCheckedChange = addSendHandlers.onIsHideByDefaultToggle,
|
||||
readOnly = policyDisablesSend,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
AddSendOptions(
|
||||
state = state,
|
||||
sendRestrictionPolicy = policyDisablesSend,
|
||||
isAddMode = isAddMode,
|
||||
addSendHandlers = addSendHandlers,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
is AddSendState.ViewState.Content.SendType.Text -> {
|
||||
BitwardenTextField(
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendTextContentEntry")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
label = stringResource(id = R.string.text),
|
||||
hint = stringResource(id = R.string.type_text_info),
|
||||
readOnly = policyDisablesSend,
|
||||
value = type.input,
|
||||
singleLine = false,
|
||||
onValueChange = addSendHandlers.onTextChange,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenSwitch(
|
||||
modifier = Modifier
|
||||
.testTag(tag = "SendHideTextByDefaultToggle")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
label = stringResource(id = R.string.hide_text_by_default),
|
||||
isChecked = type.isHideByDefaultChecked,
|
||||
onCheckedChange = addSendHandlers.onIsHideByDefaultToggle,
|
||||
readOnly = policyDisablesSend,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
AddSendOptions(
|
||||
state = state,
|
||||
sendRestrictionPolicy = policyDisablesSend,
|
||||
isAddMode = isAddMode,
|
||||
addSendHandlers = addSendHandlers,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.x8bit.bitwarden.ui.tools.feature.send.addsend
|
|||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
|
@ -23,6 +23,7 @@ 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.scrolledContainerBottomDivider
|
||||
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||
import com.x8bit.bitwarden.ui.platform.components.appbar.NavigationIcon
|
||||
import com.x8bit.bitwarden.ui.platform.components.appbar.action.BitwardenOverflowActionItem
|
||||
|
@ -37,6 +38,8 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialo
|
|||
import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.TopAppBarDividerStyle
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.segment.BitwardenSegmentedButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.segment.SegmentedButtonState
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
|
@ -46,11 +49,12 @@ import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
|||
import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
|
||||
import com.x8bit.bitwarden.ui.platform.util.persistentListOfNotNull
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.handlers.AddSendHandlers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Displays new send UX.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AddSendScreen(
|
||||
|
@ -187,16 +191,41 @@ fun AddSendScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
utilityBar = {
|
||||
val viewState = state.viewState
|
||||
if (state.isAddMode &&
|
||||
!state.isShared &&
|
||||
viewState is AddSendState.ViewState.Content
|
||||
) {
|
||||
BitwardenSegmentedButton(
|
||||
modifier = Modifier
|
||||
.scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior)
|
||||
.fillMaxWidth(),
|
||||
options = persistentListOf(
|
||||
SegmentedButtonState(
|
||||
text = stringResource(id = R.string.file),
|
||||
onClick = addSendHandlers.onFileTypeSelect,
|
||||
isChecked = viewState.isFileType,
|
||||
testTag = "SendFileButton",
|
||||
),
|
||||
SegmentedButtonState(
|
||||
text = stringResource(id = R.string.text),
|
||||
onClick = addSendHandlers.onTextTypeSelect,
|
||||
isChecked = viewState.isTextType,
|
||||
testTag = "SendTextButton",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
) {
|
||||
val modifier = Modifier
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues = innerPadding)
|
||||
|
||||
when (val viewState = state.viewState) {
|
||||
is AddSendState.ViewState.Content -> AddSendContent(
|
||||
state = viewState,
|
||||
scrollBehavior = scrollBehavior,
|
||||
policyDisablesSend = state.policyDisablesSend,
|
||||
policySendOptionsInEffect = state.shouldDisplayPolicyWarning,
|
||||
isAddMode = state.isAddMode,
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.x8bit.bitwarden.ui.vault.feature.addedit
|
|||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
|
@ -312,7 +311,7 @@ fun VaultAddEditScreen(
|
|||
.takeUnless {
|
||||
state.isAddItemMode ||
|
||||
!state.isCipherInCollection ||
|
||||
!state.canAssociateToCollections
|
||||
!state.canAssociateToCollections
|
||||
},
|
||||
OverflowMenuItemData(
|
||||
text = stringResource(id = R.string.delete),
|
||||
|
@ -324,7 +323,7 @@ fun VaultAddEditScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is VaultAddEditState.ViewState.Content -> {
|
||||
VaultAddEditContent(
|
||||
|
@ -342,7 +341,6 @@ fun VaultAddEditScreen(
|
|||
sshKeyItemTypeHandlers = sshKeyItemTypeHandlers,
|
||||
modifier = Modifier
|
||||
.imePadding()
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
@ -350,17 +348,13 @@ fun VaultAddEditScreen(
|
|||
is VaultAddEditState.ViewState.Error -> {
|
||||
BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
VaultAddEditState.ViewState.Loading -> {
|
||||
BitwardenLoadingContent(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.x8bit.bitwarden.ui.vault.feature.attachments
|
|||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
|
@ -98,24 +97,21 @@ fun AttachmentsScreen(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
val modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is AttachmentsState.ViewState.Content -> AttachmentsContent(
|
||||
viewState = viewState,
|
||||
attachmentsHandlers = attachmentsHandlers,
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
is AttachmentsState.ViewState.Error -> BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
AttachmentsState.ViewState.Loading -> BitwardenLoadingContent(
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,10 +104,9 @@ fun ImportLoginsScreen(
|
|||
onDismiss = handler.onSuccessfulSyncAcknowledged,
|
||||
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
) { paddingValues, animatedOnDismiss ->
|
||||
) { animatedOnDismiss ->
|
||||
ImportLoginsSuccessBottomSheetContent(
|
||||
onCompleteImportLogins = animatedOnDismiss,
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -132,13 +131,11 @@ fun ImportLoginsScreen(
|
|||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
Crossfade(
|
||||
targetState = state.viewState,
|
||||
label = "CrossfadeBetweenViewStates",
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues = innerPadding),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) { viewState ->
|
||||
when (viewState) {
|
||||
ImportLoginsState.ViewState.InitialContent -> {
|
||||
|
|
|
@ -254,13 +254,12 @@ fun VaultItemScreen(
|
|||
)
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
VaultItemContent(
|
||||
viewState = state.viewState,
|
||||
modifier = Modifier
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding),
|
||||
.fillMaxSize(),
|
||||
vaultCommonItemTypeHandlers = remember(viewModel) {
|
||||
VaultCommonItemTypeHandlers.create(viewModel = viewModel)
|
||||
},
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.x8bit.bitwarden.ui.vault.feature.itemlisting
|
|||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
|
@ -456,12 +455,24 @@ private fun VaultItemListingScaffold(
|
|||
)
|
||||
}
|
||||
},
|
||||
overlay = {
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onSwitchAccountClick = vaultItemListingHandlers.switchAccountClick,
|
||||
onLockAccountClick = vaultItemListingHandlers.lockAccountClick,
|
||||
onLogoutAccountClick = vaultItemListingHandlers.logoutAccountClick,
|
||||
onAddAccountClick = {
|
||||
// Not available
|
||||
},
|
||||
onDismissRequest = { isAccountMenuVisible = false },
|
||||
isAddAccountAvailable = false,
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
},
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
) { paddingValues ->
|
||||
val modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
|
||||
) {
|
||||
when (state.viewState) {
|
||||
is VaultItemListingState.ViewState.Content -> {
|
||||
VaultItemListingContent(
|
||||
|
@ -475,7 +486,7 @@ private fun VaultItemListingScaffold(
|
|||
masterPasswordRepromptSubmit =
|
||||
vaultItemListingHandlers.masterPasswordRepromptSubmit,
|
||||
onOverflowItemClick = vaultItemListingHandlers.overflowItemClick,
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -485,7 +496,7 @@ private fun VaultItemListingScaffold(
|
|||
policyDisablesSend = state.policyDisablesSend &&
|
||||
state.itemListingType is VaultItemListingState.ItemListingType.Send,
|
||||
addItemClickAction = vaultItemListingHandlers.addVaultItemClick,
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -493,28 +504,13 @@ private fun VaultItemListingScaffold(
|
|||
BitwardenErrorContent(
|
||||
message = state.viewState.message(),
|
||||
onTryAgainClick = vaultItemListingHandlers.refreshClick,
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is VaultItemListingState.ViewState.Loading -> {
|
||||
BitwardenLoadingContent(modifier = modifier)
|
||||
BitwardenLoadingContent(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onSwitchAccountClick = vaultItemListingHandlers.switchAccountClick,
|
||||
onLockAccountClick = vaultItemListingHandlers.lockAccountClick,
|
||||
onLogoutAccountClick = vaultItemListingHandlers.logoutAccountClick,
|
||||
onAddAccountClick = {
|
||||
// Not available
|
||||
},
|
||||
onDismissRequest = { isAccountMenuVisible = false },
|
||||
isAddAccountAvailable = false,
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,9 +121,8 @@ fun ManualCodeEntryScreen(
|
|||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()),
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
Column(modifier = Modifier.padding(paddingValues)) {
|
||||
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
text = stringResource(id = R.string.enter_key_manually),
|
||||
style = BitwardenTheme.typography.titleMedium,
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.x8bit.bitwarden.ui.vault.feature.movetoorganization
|
|||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
|
@ -126,12 +125,10 @@ private fun VaultMoveToOrganizationScaffold(
|
|||
},
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
val modifier = Modifier
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
|
||||
when (state.viewState) {
|
||||
is VaultMoveToOrganizationState.ViewState.Content -> {
|
||||
VaultMoveToOrganizationContent(
|
||||
|
|
|
@ -125,24 +125,21 @@ fun QrCodeScanScreen(
|
|||
),
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
) {
|
||||
CameraPreview(
|
||||
cameraErrorReceive = remember(viewModel) {
|
||||
{ viewModel.trySendAction(QrCodeScanAction.CameraSetupErrorReceive) }
|
||||
},
|
||||
qrCodeAnalyzer = qrCodeAnalyzer,
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
)
|
||||
|
||||
if (LocalConfiguration.current.isPortrait) {
|
||||
PortraitQRCodeContent(
|
||||
onEnterCodeManuallyClick = onEnterCodeManuallyClick,
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
)
|
||||
} else {
|
||||
LandscapeQRCodeContent(
|
||||
onEnterCodeManuallyClick = onEnterCodeManuallyClick,
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,15 @@ package com.x8bit.bitwarden.ui.vault.feature.vault
|
|||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
|
@ -37,6 +44,7 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
* @param topAppBarScrollBehavior Used to derive the background color of the content and keep it in
|
||||
* sync with the associated app bar.
|
||||
* @param modifier A [Modifier] for the composable.
|
||||
* @param windowInsets The insets to be applied to this composable.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
@ -46,6 +54,9 @@ fun VaultFilter(
|
|||
onVaultFilterTypeSelect: (VaultFilterType) -> Unit,
|
||||
topAppBarScrollBehavior: TopAppBarScrollBehavior,
|
||||
modifier: Modifier = Modifier,
|
||||
windowInsets: WindowInsets = WindowInsets.displayCutout
|
||||
.union(WindowInsets.navigationBars)
|
||||
.only(WindowInsetsSides.Horizontal),
|
||||
) {
|
||||
var shouldShowSelectionDialog by remember { mutableStateOf(false) }
|
||||
|
||||
|
@ -73,7 +84,8 @@ fun VaultFilter(
|
|||
.scrolledContainerBottomDivider(topAppBarScrollBehavior = topAppBarScrollBehavior)
|
||||
.padding(vertical = 8.dp)
|
||||
.testTag("ActiveFilterRow")
|
||||
.then(modifier),
|
||||
.then(modifier)
|
||||
.windowInsetsPadding(insets = windowInsets),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.widget.Toast
|
|||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -240,6 +239,24 @@ private fun VaultScreenScaffold(
|
|||
},
|
||||
)
|
||||
},
|
||||
utilityBar = {
|
||||
state.vaultFilterDataWithFilter?.let {
|
||||
VaultFilter(
|
||||
selectedVaultFilterType = it.selectedVaultFilterType,
|
||||
vaultFilterTypes = it.vaultFilterTypes.toImmutableList(),
|
||||
onVaultFilterTypeSelect = vaultHandlers.vaultFilterTypeSelect,
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
// There is some built-in padding to the menu button that makes up
|
||||
// the visual difference here.
|
||||
end = 12.dp,
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
},
|
||||
snackbarHost = {
|
||||
BitwardenSnackbarHost(
|
||||
bitwardenHostState = snackbarHostState,
|
||||
|
@ -259,81 +276,7 @@ private fun VaultScreenScaffold(
|
|||
)
|
||||
}
|
||||
},
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) { paddingValues ->
|
||||
Box {
|
||||
val innerModifier = Modifier
|
||||
.fillMaxSize()
|
||||
val outerModifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
Column(modifier = outerModifier) {
|
||||
state.vaultFilterDataWithFilter?.let {
|
||||
VaultFilter(
|
||||
selectedVaultFilterType = it.selectedVaultFilterType,
|
||||
vaultFilterTypes = it.vaultFilterTypes.toImmutableList(),
|
||||
onVaultFilterTypeSelect = vaultHandlers.vaultFilterTypeSelect,
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
// There is some built-in padding to the menu button that makes up
|
||||
// the visual difference here.
|
||||
end = 12.dp,
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
|
||||
when (val viewState = state.viewState) {
|
||||
is VaultState.ViewState.Content -> VaultContent(
|
||||
state = viewState,
|
||||
showSshKeys = state.showSshKeys,
|
||||
vaultHandlers = vaultHandlers,
|
||||
onOverflowOptionClick = { masterPasswordRepromptAction = it },
|
||||
modifier = innerModifier,
|
||||
)
|
||||
|
||||
is VaultState.ViewState.Loading -> BitwardenLoadingContent(
|
||||
modifier = innerModifier,
|
||||
)
|
||||
|
||||
is VaultState.ViewState.NoItems -> {
|
||||
AnimatedVisibility(
|
||||
visible = state.showImportActionCard,
|
||||
exit = actionCardExitAnimation(),
|
||||
label = "VaultNoItemsActionCard",
|
||||
) {
|
||||
BitwardenActionCard(
|
||||
cardTitle = stringResource(R.string.import_saved_logins),
|
||||
cardSubtitle = stringResource(
|
||||
R.string.use_a_computer_to_import_logins,
|
||||
),
|
||||
actionText = stringResource(R.string.get_started),
|
||||
onActionClick = vaultHandlers.importActionCardClick,
|
||||
onDismissClick = vaultHandlers.dismissImportActionCard,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.padding(top = 12.dp),
|
||||
)
|
||||
}
|
||||
VaultNoItems(
|
||||
modifier = innerModifier,
|
||||
policyDisablesSend = false,
|
||||
addItemClickAction = vaultHandlers.addItemClickAction,
|
||||
)
|
||||
}
|
||||
|
||||
is VaultState.ViewState.Error -> BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
onTryAgainClick = vaultHandlers.tryAgainClick,
|
||||
modifier = innerModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
overlay = {
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = accountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
|
@ -343,8 +286,61 @@ private fun VaultScreenScaffold(
|
|||
onAddAccountClick = vaultHandlers.addAccountClickAction,
|
||||
onDismissRequest = { updateAccountMenuVisibility(false) },
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
modifier = outerModifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
},
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is VaultState.ViewState.Content -> VaultContent(
|
||||
state = viewState,
|
||||
showSshKeys = state.showSshKeys,
|
||||
vaultHandlers = vaultHandlers,
|
||||
onOverflowOptionClick = { masterPasswordRepromptAction = it },
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
is VaultState.ViewState.Loading -> BitwardenLoadingContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
is VaultState.ViewState.NoItems -> {
|
||||
AnimatedVisibility(
|
||||
visible = state.showImportActionCard,
|
||||
exit = actionCardExitAnimation(),
|
||||
label = "VaultNoItemsActionCard",
|
||||
) {
|
||||
BitwardenActionCard(
|
||||
cardTitle = stringResource(R.string.import_saved_logins),
|
||||
cardSubtitle = stringResource(
|
||||
R.string.use_a_computer_to_import_logins,
|
||||
),
|
||||
actionText = stringResource(R.string.get_started),
|
||||
onActionClick = vaultHandlers.importActionCardClick,
|
||||
onDismissClick = vaultHandlers.dismissImportActionCard,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin()
|
||||
.padding(top = 12.dp),
|
||||
)
|
||||
}
|
||||
VaultNoItems(
|
||||
policyDisablesSend = false,
|
||||
addItemClickAction = vaultHandlers.addItemClickAction,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is VaultState.ViewState.Error -> BitwardenErrorContent(
|
||||
message = viewState.message(),
|
||||
onTryAgainClick = vaultHandlers.tryAgainClick,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,18 +106,14 @@ fun VerificationCodeScreen(
|
|||
)
|
||||
},
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
) { paddingValues ->
|
||||
val modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is VerificationCodeState.ViewState.Content -> {
|
||||
VerificationCodeContent(
|
||||
items = viewState.verificationCodeDisplayItems.toImmutableList(),
|
||||
onCopyClick = verificationCodeHandler.copyClick,
|
||||
itemClick = verificationCodeHandler.itemClick,
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -125,12 +121,12 @@ fun VerificationCodeScreen(
|
|||
BitwardenErrorContent(
|
||||
message = viewState.message.invoke(),
|
||||
onTryAgainClick = verificationCodeHandler.refreshClick,
|
||||
modifier = modifier,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
is VerificationCodeState.ViewState.Loading -> {
|
||||
BitwardenLoadingContent(modifier = modifier)
|
||||
BitwardenLoadingContent(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -409,7 +409,8 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
@Test
|
||||
fun `Text segmented button click should send TextTypeClick`() {
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Text")[0]
|
||||
.onAllNodesWithText("Text")
|
||||
.filterToOne(!isEditableText)
|
||||
// A bug prevents performClick from working here so we
|
||||
// have to perform the semantic action instead.
|
||||
.performSemanticsAction(SemanticsActions.OnClick)
|
||||
|
@ -469,9 +470,13 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
@Test
|
||||
fun `text input change should send TextChange`() {
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Text")[1]
|
||||
.onAllNodesWithText("Text")
|
||||
.filterToOne(isEditableText)
|
||||
.performScrollTo()
|
||||
.performTextInput("input")
|
||||
viewModel.trySendAction(AddSendAction.TextChange("input"))
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(AddSendAction.TextChange("input"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
[versions]
|
||||
|
||||
# SDK Versions
|
||||
compileSdk = "34"
|
||||
targetSdk = "34"
|
||||
compileSdk = "35"
|
||||
targetSdk = "35"
|
||||
minSdk = "29"
|
||||
|
||||
# Dependency Versions
|
||||
|
@ -13,17 +13,17 @@ androidXBiometrics = "1.2.0-alpha05"
|
|||
androidxBrowser = "1.8.0"
|
||||
androidxCamera = "1.4.0"
|
||||
androidxComposeBom = "2024.10.01"
|
||||
androidxCore = "1.13.1"
|
||||
androidxCore = "1.15.0"
|
||||
androidxCredentials = "1.3.0"
|
||||
androidxHiltNavigationCompose = "1.2.0"
|
||||
androidxLifecycle = "2.8.6"
|
||||
androidxLifecycle = "2.8.7"
|
||||
androidxNavigation = "2.8.0"
|
||||
androidxRoom = "2.6.1"
|
||||
androidXSecurityCrypto = "1.1.0-alpha06"
|
||||
androidxSplash = "1.1.0-rc01"
|
||||
androidXAppCompat = "1.7.0"
|
||||
androdixAutofill = "1.1.0"
|
||||
androidxWork = "2.9.1"
|
||||
androidxWork = "2.10.0"
|
||||
bitwardenSdk = "1.0.0-20241030.101847-8"
|
||||
crashlytics = "3.0.2"
|
||||
detekt = "1.23.7"
|
||||
|
|
Loading…
Reference in a new issue