Refactor BitwardenOverflowTopAppBar for better re-use (#156)

This commit is contained in:
joshua-livefront 2023-10-24 15:54:11 -04:00 committed by Álison Fernandes
parent 8864315342
commit fe0fae4496
5 changed files with 47 additions and 137 deletions

View file

@ -62,8 +62,9 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordField import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordField
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButtonTopAppBar import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButton
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
import com.x8bit.bitwarden.ui.platform.components.BitwardenTwoButtonDialog import com.x8bit.bitwarden.ui.platform.components.BitwardenTwoButtonDialog
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
import com.x8bit.bitwarden.ui.platform.theme.clickableSpanStyle import com.x8bit.bitwarden.ui.platform.theme.clickableSpanStyle
@ -157,18 +158,21 @@ fun CreateAccountScreen(
.background(MaterialTheme.colorScheme.surface) .background(MaterialTheme.colorScheme.surface)
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
) { ) {
BitwardenTextButtonTopAppBar( BitwardenTopAppBar(
title = stringResource(id = R.string.create_account), title = stringResource(id = R.string.create_account),
navigationIcon = painterResource(id = R.drawable.ic_close), navigationIcon = painterResource(id = R.drawable.ic_close),
navigationIconContentDescription = stringResource(id = R.string.close), navigationIconContentDescription = stringResource(id = R.string.close),
onNavigationIconClick = remember(viewModel) { onNavigationIconClick = remember(viewModel) {
{ viewModel.trySendAction(CloseClick) } { viewModel.trySendAction(CloseClick) }
}, },
buttonText = stringResource(id = R.string.submit), actions = {
onButtonClick = remember(viewModel) { BitwardenTextButton(
{ viewModel.trySendAction(SubmitClick) } label = stringResource(id = R.string.submit),
onClick = remember(viewModel) {
{ viewModel.trySendAction(SubmitClick) }
},
)
}, },
isButtonEnabled = true,
) )
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
BitwardenTextField( BitwardenTextField(

View file

@ -31,8 +31,9 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenOutlinedButtonWithIcon import com.x8bit.bitwarden.ui.platform.components.BitwardenOutlinedButtonWithIcon
import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowTopAppBar import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordField import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordField
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
/** /**
* The top level composable for the Login screen. * The top level composable for the Login screen.
@ -74,20 +75,24 @@ fun LoginScreen(
visibilityState = state.errorDialogState, visibilityState = state.errorDialogState,
onDismissRequest = { viewModel.trySendAction(LoginAction.ErrorDialogDismiss) }, onDismissRequest = { viewModel.trySendAction(LoginAction.ErrorDialogDismiss) },
) )
BitwardenOverflowTopAppBar( BitwardenTopAppBar(
title = stringResource(id = R.string.app_name), title = stringResource(id = R.string.app_name),
navigationIcon = painterResource(id = R.drawable.ic_close), navigationIcon = painterResource(id = R.drawable.ic_close),
navigationIconContentDescription = stringResource(id = R.string.close), navigationIconContentDescription = stringResource(id = R.string.close),
onNavigationIconClick = remember(viewModel) { onNavigationIconClick = remember(viewModel) {
{ viewModel.trySendAction(LoginAction.CloseButtonClick) } { viewModel.trySendAction(LoginAction.CloseButtonClick) }
}, },
dropdownMenuItemContent = { actions = {
DropdownMenuItem( BitwardenOverflowActionItem(
text = { dropdownMenuItemContent = {
Text(text = stringResource(id = R.string.get_password_hint)) DropdownMenuItem(
}, text = {
onClick = remember(viewModel) { Text(text = stringResource(id = R.string.get_password_hint))
{ viewModel.trySendAction(LoginAction.MasterPasswordHintClick) } },
onClick = remember(viewModel) {
{ viewModel.trySendAction(LoginAction.MasterPasswordHintClick) }
},
)
}, },
) )
}, },

View file

@ -1,96 +0,0 @@
package com.x8bit.bitwarden.ui.platform.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
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.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
/**
* Represents a Bitwarden-styled [TopAppBar] that assumes the following components:
*
* - a single navigation control in the upper-left defined by [navigationIcon],
* [navigationIconContentDescription], and [onNavigationIconClick].
* - a [title] in the middle.
* - a single overflow menu in the right with contents defined by the [dropdownMenuItemContent]. It
* is strongly recommended that this content be a stack of [DropdownMenuItem].
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BitwardenOverflowTopAppBar(
title: String,
navigationIcon: Painter,
navigationIconContentDescription: String,
onNavigationIconClick: () -> Unit,
dropdownMenuItemContent: @Composable ColumnScope.() -> Unit,
) {
var isOverflowMenuVisible by remember { mutableStateOf(false) }
TopAppBar(
navigationIcon = {
IconButton(
onClick = { onNavigationIconClick() },
) {
Icon(
painter = navigationIcon,
contentDescription = navigationIconContentDescription,
tint = MaterialTheme.colorScheme.onSurface,
)
}
},
title = {
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurface,
)
},
actions = {
Box {
IconButton(
onClick = { isOverflowMenuVisible = !isOverflowMenuVisible },
) {
Icon(
painter = painterResource(id = R.drawable.ic_more),
contentDescription = stringResource(id = R.string.more),
tint = MaterialTheme.colorScheme.onSurface,
)
}
DropdownMenu(
expanded = isOverflowMenuVisible,
onDismissRequest = { isOverflowMenuVisible = false },
content = dropdownMenuItemContent,
)
}
},
)
}
@Preview
@Composable
private fun BitwardenOverflowTopAppBar_preview() {
BitwardenTheme {
BitwardenOverflowTopAppBar(
title = "Title",
navigationIcon = painterResource(id = R.drawable.ic_close),
navigationIconContentDescription = stringResource(id = R.string.close),
onNavigationIconClick = {},
dropdownMenuItemContent = {},
)
}
}

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.ui.platform.components package com.x8bit.bitwarden.ui.platform.components
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@ -12,6 +13,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import com.x8bit.bitwarden.R import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
/** /**
* Represents a Bitwarden styled [TopAppBar] that assumes the following components: * Represents a Bitwarden styled [TopAppBar] that assumes the following components:
@ -19,19 +21,18 @@ import com.x8bit.bitwarden.R
* - a single navigation control in the upper-left defined by [navigationIcon], * - a single navigation control in the upper-left defined by [navigationIcon],
* [navigationIconContentDescription], and [onNavigationIconClick]. * [navigationIconContentDescription], and [onNavigationIconClick].
* - a [title] in the middle. * - a [title] in the middle.
* - a [BitwardenTextButton] on the right that will display [buttonText] and call [onButtonClick] * - a [actions] lambda containing the set of actions (usually icons or similar) to display
* when clicked and [isButtonEnabled] is true. * in the app bar's trailing side. This lambda extends [RowScope], allowing flexibility in
* defining the layout of the actions.
*/ */
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun BitwardenTextButtonTopAppBar( fun BitwardenTopAppBar(
title: String, title: String,
navigationIcon: Painter, navigationIcon: Painter,
navigationIconContentDescription: String, navigationIconContentDescription: String,
onNavigationIconClick: () -> Unit, onNavigationIconClick: () -> Unit,
buttonText: String, actions: @Composable RowScope.() -> Unit = {},
onButtonClick: () -> Unit,
isButtonEnabled: Boolean,
) { ) {
TopAppBar( TopAppBar(
navigationIcon = { navigationIcon = {
@ -52,26 +53,19 @@ fun BitwardenTextButtonTopAppBar(
color = MaterialTheme.colorScheme.onSurface, color = MaterialTheme.colorScheme.onSurface,
) )
}, },
actions = { actions = actions,
BitwardenTextButton(
label = buttonText,
onClick = onButtonClick,
isEnabled = isButtonEnabled,
)
},
) )
} }
@Preview @Preview
@Composable @Composable
private fun BitwardenTextButtonTopAppBar_preview() { private fun BitwardenTopAppBar_preview() {
BitwardenTextButtonTopAppBar( BitwardenTheme {
title = "Title", BitwardenTopAppBar(
navigationIcon = painterResource(id = R.drawable.ic_close), title = "Title",
navigationIconContentDescription = stringResource(id = R.string.close), navigationIcon = painterResource(id = R.drawable.ic_close),
onNavigationIconClick = {}, navigationIconContentDescription = stringResource(id = R.string.close),
buttonText = "Button", onNavigationIconClick = {},
onButtonClick = {}, )
isButtonEnabled = true, }
)
} }

View file

@ -23,7 +23,8 @@ 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.Text import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowTopAppBar import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
/** /**
* Displays the account security screen. * Displays the account security screen.
@ -43,14 +44,16 @@ fun AccountSecurityScreen(
.fillMaxSize() .fillMaxSize()
.background(color = MaterialTheme.colorScheme.surface), .background(color = MaterialTheme.colorScheme.surface),
) { ) {
BitwardenOverflowTopAppBar( BitwardenTopAppBar(
title = stringResource(id = R.string.account), title = stringResource(id = R.string.account),
navigationIcon = painterResource(id = R.drawable.ic_back), navigationIcon = painterResource(id = R.drawable.ic_back),
navigationIconContentDescription = stringResource(id = R.string.back), navigationIconContentDescription = stringResource(id = R.string.back),
onNavigationIconClick = remember(viewModel) { onNavigationIconClick = remember(viewModel) {
{ viewModel.trySendAction(AccountSecurityAction.BackClick) } { viewModel.trySendAction(AccountSecurityAction.BackClick) }
}, },
dropdownMenuItemContent = {}, actions = {
BitwardenOverflowActionItem()
},
) )
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
AccountSecurityRow( AccountSecurityRow(