mirror of
https://github.com/bitwarden/android.git
synced 2025-02-18 13:00:01 +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
README.md
app/src
main/java/com/x8bit/bitwarden/ui
auth/feature
accountsetup
checkemail
completeregistration
createaccount
enterprisesignon
environment
expiredregistrationlink
landing
login
loginwithdevice
masterpasswordgenerator
masterpasswordguidance
masterpasswordhint
preventaccountlockout
removepassword
resetpassword
setpassword
startregistration
trusteddevice
twofactorlogin
vaultunlock
welcome
platform
components
account
appbar
bottomsheet
fab
scaffold
segment
snackbar
feature
debugmenu
search
settings
SettingsScreen.kt
about
accountsecurity
appearance
autofill
exportvault
folders
other
vault
vaultunlockednavbar
tools/feature
generator
send
vault/feature
addedit
attachments
importlogins
item
itemlisting
manualcodeentry
movetoorganization
qrcodescan
vault
verificationcode
test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend
gradle
|
@ -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…
Add table
Reference in a new issue