mirror of
https://github.com/bitwarden/android.git
synced 2026-03-16 17:14:25 -05:00
Bit 1207 add lock and logout to switcher (#353)
This commit is contained in:
committed by
Álison Fernandes
parent
d0205b4b59
commit
266db5cc04
@@ -34,6 +34,7 @@ import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
@@ -48,6 +49,7 @@ import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.showNotYetImplementedToast
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAccountSwitcher
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||
@@ -178,12 +180,21 @@ fun LandingScreen(
|
||||
.fillMaxSize(),
|
||||
)
|
||||
|
||||
val context = LocalContext.current
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onAccountSummaryClick = remember(viewModel) {
|
||||
onSwitchAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.SwitchAccountClick(it)) }
|
||||
},
|
||||
onLockAccountClick = {
|
||||
// TODO: Implement lock functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onLogoutAccountClick = {
|
||||
// TODO: Implement logout functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onAddAccountClick = {
|
||||
// Not available
|
||||
},
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.showNotYetImplementedToast
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAccountSwitcher
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton
|
||||
@@ -143,9 +144,17 @@ fun LoginScreen(
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = isAccountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onAccountSummaryClick = remember(viewModel) {
|
||||
onSwitchAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LoginAction.SwitchAccountClick(it)) }
|
||||
},
|
||||
onLockAccountClick = {
|
||||
// TODO: Implement lock functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onLogoutAccountClick = {
|
||||
// TODO: Implement logout functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onAddAccountClick = {
|
||||
// Not available
|
||||
},
|
||||
|
||||
@@ -32,6 +32,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.showNotYetImplementedToast
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAccountActionItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAccountSwitcher
|
||||
@@ -193,9 +194,17 @@ fun VaultUnlockScreen(
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = accountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onAccountSummaryClick = remember(viewModel) {
|
||||
onSwitchAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.SwitchAccountClick(it)) }
|
||||
},
|
||||
onLockAccountClick = {
|
||||
// TODO: Implement lock functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onLogoutAccountClick = {
|
||||
// TODO: Implement logout functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onAddAccountClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultUnlockAction.AddAccountClick) }
|
||||
},
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.x8bit.bitwarden.ui.platform.base.util
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
|
||||
/**
|
||||
* Shows a [Toast] with a message indicating something is not yet implemented.
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
fun showNotYetImplementedToast(context: Context) {
|
||||
Toast
|
||||
.makeText(
|
||||
context,
|
||||
"Not yet implemented",
|
||||
Toast.LENGTH_SHORT,
|
||||
)
|
||||
.show()
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.x8bit.bitwarden.ui.platform.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -25,7 +29,10 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
@@ -62,7 +69,12 @@ private const val MAXIMUM_ACCOUNT_LIMIT = 5
|
||||
* @param isVisible Whether or not this component is visible. Changing this value will animate the
|
||||
* component in or out of view.
|
||||
* @param accountSummaries The accounts to display in the switcher.
|
||||
* @param onAccountSummaryClick A callback when an account is clicked.
|
||||
* @param onSwitchAccountClick A callback when an account is clicked indicating that the account
|
||||
* should be switched to.
|
||||
* @param onLockAccountClick A callback when an account is clicked indicating that the account
|
||||
* should be locked.
|
||||
* @param onLogoutAccountClick A callback when an account is clicked indicating that the account
|
||||
* should be logged out.
|
||||
* @param onAddAccountClick A callback when the Add Account row is clicked.
|
||||
* @param onDismissRequest A callback when the component requests to be dismissed. This is triggered
|
||||
* whenever the user clicks on the scrim or any of the switcher items.
|
||||
@@ -78,13 +90,29 @@ private const val MAXIMUM_ACCOUNT_LIMIT = 5
|
||||
fun BitwardenAccountSwitcher(
|
||||
isVisible: Boolean,
|
||||
accountSummaries: ImmutableList<AccountSummary>,
|
||||
onAccountSummaryClick: (AccountSummary) -> Unit,
|
||||
onSwitchAccountClick: (AccountSummary) -> Unit,
|
||||
onLockAccountClick: (AccountSummary) -> Unit,
|
||||
onLogoutAccountClick: (AccountSummary) -> Unit,
|
||||
onAddAccountClick: () -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
isAddAccountAvailable: Boolean = true,
|
||||
topAppBarScrollBehavior: TopAppBarScrollBehavior,
|
||||
) {
|
||||
// Track the actual visibility (according to the internal transitions) so that we know when we
|
||||
// can safely show dialogs.
|
||||
var isVisibleActual by remember { mutableStateOf(isVisible) }
|
||||
|
||||
var lockOrLogoutAccount by remember { mutableStateOf<AccountSummary?>(null) }
|
||||
if (lockOrLogoutAccount != null && !isVisibleActual) {
|
||||
LockOrLogoutDialog(
|
||||
accountSummary = requireNotNull(lockOrLogoutAccount),
|
||||
onDismissRequest = { lockOrLogoutAccount = null },
|
||||
onLockAccountClick = onLockAccountClick,
|
||||
onLogoutAccountClick = onLogoutAccountClick,
|
||||
)
|
||||
}
|
||||
|
||||
Box(modifier = modifier) {
|
||||
BitwardenAnimatedScrim(
|
||||
isVisible = isVisible,
|
||||
@@ -95,9 +123,13 @@ fun BitwardenAccountSwitcher(
|
||||
AnimatedAccountSwitcher(
|
||||
isVisible = isVisible,
|
||||
accountSummaries = accountSummaries,
|
||||
onAccountSummaryClick = {
|
||||
onSwitchAccountClick = {
|
||||
onDismissRequest()
|
||||
onAccountSummaryClick(it)
|
||||
onSwitchAccountClick(it)
|
||||
},
|
||||
onSwitchAccountLongClick = {
|
||||
onDismissRequest()
|
||||
lockOrLogoutAccount = it
|
||||
},
|
||||
onAddAccountClick = {
|
||||
onDismissRequest()
|
||||
@@ -105,27 +137,38 @@ fun BitwardenAccountSwitcher(
|
||||
},
|
||||
isAddAccountAvailable = isAddAccountAvailable,
|
||||
topAppBarScrollBehavior = topAppBarScrollBehavior,
|
||||
currentAnimationState = { isVisibleActual = it },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@OptIn(
|
||||
ExperimentalMaterial3Api::class,
|
||||
ExperimentalAnimationApi::class,
|
||||
)
|
||||
@Composable
|
||||
private fun AnimatedAccountSwitcher(
|
||||
isVisible: Boolean,
|
||||
accountSummaries: ImmutableList<AccountSummary>,
|
||||
onAccountSummaryClick: (AccountSummary) -> Unit,
|
||||
onSwitchAccountClick: (AccountSummary) -> Unit,
|
||||
onSwitchAccountLongClick: (AccountSummary) -> Unit,
|
||||
onAddAccountClick: () -> Unit,
|
||||
isAddAccountAvailable: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
topAppBarScrollBehavior: TopAppBarScrollBehavior,
|
||||
currentAnimationState: (isVisible: Boolean) -> Unit,
|
||||
) {
|
||||
val expandedColor = MaterialTheme.colorScheme.surface
|
||||
val collapsedColor = MaterialTheme.colorScheme.surfaceContainer
|
||||
AnimatedVisibility(
|
||||
visible = isVisible,
|
||||
val transition = updateTransition(
|
||||
targetState = isVisible,
|
||||
label = "AnimatedAccountSwitcher",
|
||||
)
|
||||
.also { currentAnimationState(it.currentState) }
|
||||
transition.AnimatedVisibility(
|
||||
visible = { it },
|
||||
enter = slideInVertically { -it },
|
||||
exit = slideOutVertically { -it },
|
||||
) {
|
||||
@@ -153,7 +196,8 @@ private fun AnimatedAccountSwitcher(
|
||||
items(accountSummaries) { accountSummary ->
|
||||
AccountSummaryItem(
|
||||
accountSummary = accountSummary,
|
||||
onClick = onAccountSummaryClick,
|
||||
onSwitchAccountClick = onSwitchAccountClick,
|
||||
onSwitchAccountLongClick = onSwitchAccountLongClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
@@ -177,20 +221,23 @@ private fun AnimatedAccountSwitcher(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun AccountSummaryItem(
|
||||
accountSummary: AccountSummary,
|
||||
onClick: (AccountSummary) -> Unit,
|
||||
onSwitchAccountClick: (AccountSummary) -> Unit,
|
||||
onSwitchAccountLongClick: (AccountSummary) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
.combinedClickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onClick(accountSummary) },
|
||||
onClick = { onSwitchAccountClick(accountSummary) },
|
||||
onLongClick = { onSwitchAccountLongClick(accountSummary) },
|
||||
)
|
||||
.padding(vertical = 8.dp)
|
||||
.then(modifier),
|
||||
@@ -248,6 +295,33 @@ private fun AccountSummaryItem(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LockOrLogoutDialog(
|
||||
accountSummary: AccountSummary,
|
||||
onDismissRequest: () -> Unit,
|
||||
onLockAccountClick: (AccountSummary) -> Unit,
|
||||
onLogoutAccountClick: (AccountSummary) -> Unit,
|
||||
) {
|
||||
BitwardenSelectionDialog(
|
||||
title = "${accountSummary.email}\n${accountSummary.environmentLabel}",
|
||||
onDismissRequest = onDismissRequest,
|
||||
selectionItems = {
|
||||
BitwardenBasicDialogRow(
|
||||
text = stringResource(id = R.string.lock),
|
||||
onClick = {
|
||||
onLockAccountClick(accountSummary)
|
||||
},
|
||||
)
|
||||
BitwardenBasicDialogRow(
|
||||
text = stringResource(id = R.string.log_out),
|
||||
onClick = {
|
||||
onLogoutAccountClick(accountSummary)
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddAccountItem(
|
||||
onClick: () -> Unit,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.x8bit.bitwarden.ui.platform.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* A simple clickable row for use within a [BitwardenSelectionDialog] as an alternative to a
|
||||
* [BitwardenSelectionRow].
|
||||
*
|
||||
* @param text The text to display in the row.
|
||||
* @param onClick A callback to be invoked when the row is clicked.
|
||||
* @param modifier A [Modifier] for the composable.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenBasicDialogRow(
|
||||
text: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.padding(
|
||||
vertical = 16.dp,
|
||||
horizontal = 24.dp,
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.showNotYetImplementedToast
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAccountActionItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAccountSwitcher
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenMediumTopAppBar
|
||||
@@ -213,10 +214,19 @@ private fun VaultScreenScaffold(
|
||||
)
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
BitwardenAccountSwitcher(
|
||||
isVisible = accountMenuVisible,
|
||||
accountSummaries = state.accountSummaries.toImmutableList(),
|
||||
onAccountSummaryClick = accountSwitchClickAction,
|
||||
onSwitchAccountClick = accountSwitchClickAction,
|
||||
onLockAccountClick = {
|
||||
// TODO: Implement lock functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onLogoutAccountClick = {
|
||||
// TODO: Implement logout functionality (BIT-1207)
|
||||
showNotYetImplementedToast(context)
|
||||
},
|
||||
onAddAccountClick = addAccountClickAction,
|
||||
onDismissRequest = { updateAccountMenuVisibility(false) },
|
||||
topAppBarScrollBehavior = scrollBehavior,
|
||||
|
||||
Reference in New Issue
Block a user