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