mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
PM-13943 : PT1 Custom snackbar UI (#4135)
This commit is contained in:
parent
c5a266dfc0
commit
a23fc319de
8 changed files with 243 additions and 45 deletions
|
@ -12,7 +12,6 @@ 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
|
||||||
import androidx.compose.material3.SnackbarDuration
|
import androidx.compose.material3.SnackbarDuration
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
@ -22,7 +21,6 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
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 androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
@ -36,7 +34,9 @@ import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledButtonWi
|
||||||
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.field.BitwardenTextField
|
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||||
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.snackbar.BitwardenSnackbarData
|
||||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.rememberBitwardenSnackbarHostState
|
||||||
import com.x8bit.bitwarden.ui.platform.components.text.BitwardenClickableText
|
import com.x8bit.bitwarden.ui.platform.components.text.BitwardenClickableText
|
||||||
import com.x8bit.bitwarden.ui.platform.components.util.nonLetterColorVisualTransformation
|
import com.x8bit.bitwarden.ui.platform.components.util.nonLetterColorVisualTransformation
|
||||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||||
|
@ -55,18 +55,14 @@ fun MasterPasswordGeneratorScreen(
|
||||||
viewModel: MasterPasswordGeneratorViewModel = hiltViewModel(),
|
viewModel: MasterPasswordGeneratorViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
val context = LocalContext.current
|
val snackbarHostState = rememberBitwardenSnackbarHostState()
|
||||||
val resources = context.resources
|
|
||||||
val snackbarHostState = remember {
|
|
||||||
SnackbarHostState()
|
|
||||||
}
|
|
||||||
EventsEffect(viewModel = viewModel) { event ->
|
EventsEffect(viewModel = viewModel) { event ->
|
||||||
when (event) {
|
when (event) {
|
||||||
MasterPasswordGeneratorEvent.NavigateBack -> onNavigateBack()
|
MasterPasswordGeneratorEvent.NavigateBack -> onNavigateBack()
|
||||||
MasterPasswordGeneratorEvent.NavigateToPreventLockout -> onNavigateToPreventLockout()
|
MasterPasswordGeneratorEvent.NavigateToPreventLockout -> onNavigateToPreventLockout()
|
||||||
is MasterPasswordGeneratorEvent.ShowSnackbar -> {
|
is MasterPasswordGeneratorEvent.ShowSnackbar -> {
|
||||||
snackbarHostState.showSnackbar(
|
snackbarHostState.showSnackbar(
|
||||||
message = event.text.toString(resources),
|
snackbarData = BitwardenSnackbarData(message = event.text),
|
||||||
duration = SnackbarDuration.Short,
|
duration = SnackbarDuration.Short,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +96,7 @@ fun MasterPasswordGeneratorScreen(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
snackbarHost = {
|
snackbarHost = {
|
||||||
BitwardenSnackbarHost(hostState = snackbarHostState)
|
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
Column(
|
Column(
|
||||||
|
|
|
@ -2,10 +2,13 @@ package com.x8bit.bitwarden.ui.platform.components.button
|
||||||
|
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.material3.ButtonColors
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
@ -26,6 +29,7 @@ fun BitwardenOutlinedButton(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
isEnabled: Boolean = true,
|
isEnabled: Boolean = true,
|
||||||
|
colors: BitwardenOutlinedButtonColors = bitwardenOutlinedButtonColors(),
|
||||||
) {
|
) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
|
@ -36,13 +40,13 @@ fun BitwardenOutlinedButton(
|
||||||
vertical = 10.dp,
|
vertical = 10.dp,
|
||||||
horizontal = 24.dp,
|
horizontal = 24.dp,
|
||||||
),
|
),
|
||||||
colors = bitwardenOutlinedButtonColors(),
|
colors = colors.materialButtonColors,
|
||||||
border = BorderStroke(
|
border = BorderStroke(
|
||||||
width = 1.dp,
|
width = 1.dp,
|
||||||
color = if (isEnabled) {
|
color = if (isEnabled) {
|
||||||
BitwardenTheme.colorScheme.outlineButton.border
|
colors.outlineBorderColor
|
||||||
} else {
|
} else {
|
||||||
BitwardenTheme.colorScheme.outlineButton.borderDisabled
|
colors.outlinedDisabledBorderColor
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
|
@ -53,6 +57,16 @@ fun BitwardenOutlinedButton(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colors for a [BitwardenOutlinedButton].
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
data class BitwardenOutlinedButtonColors(
|
||||||
|
val materialButtonColors: ButtonColors,
|
||||||
|
val outlineBorderColor: Color,
|
||||||
|
val outlinedDisabledBorderColor: Color,
|
||||||
|
)
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun BitwardenOutlinedButton_preview_isEnabled() {
|
private fun BitwardenOutlinedButton_preview_isEnabled() {
|
||||||
|
|
|
@ -33,6 +33,7 @@ fun BitwardenOutlinedButtonWithIcon(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
isEnabled: Boolean = true,
|
isEnabled: Boolean = true,
|
||||||
|
colors: BitwardenOutlinedButtonColors = bitwardenOutlinedButtonColors(),
|
||||||
) {
|
) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
|
@ -43,13 +44,13 @@ fun BitwardenOutlinedButtonWithIcon(
|
||||||
vertical = 10.dp,
|
vertical = 10.dp,
|
||||||
horizontal = 24.dp,
|
horizontal = 24.dp,
|
||||||
),
|
),
|
||||||
colors = bitwardenOutlinedButtonColors(),
|
colors = colors.materialButtonColors,
|
||||||
border = BorderStroke(
|
border = BorderStroke(
|
||||||
width = 1.dp,
|
width = 1.dp,
|
||||||
color = if (isEnabled) {
|
color = if (isEnabled) {
|
||||||
BitwardenTheme.colorScheme.outlineButton.border
|
colors.outlineBorderColor
|
||||||
} else {
|
} else {
|
||||||
BitwardenTheme.colorScheme.outlineButton.borderDisabled
|
colors.outlinedDisabledBorderColor
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.platform.components.button.color
|
||||||
import androidx.compose.material3.ButtonColors
|
import androidx.compose.material3.ButtonColors
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenOutlinedButtonColors
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,12 +43,21 @@ fun bitwardenFilledTonalButtonColors(): ButtonColors = ButtonColors(
|
||||||
* Provides a default set of Bitwarden-styled colors for an outlined button.
|
* Provides a default set of Bitwarden-styled colors for an outlined button.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun bitwardenOutlinedButtonColors(): ButtonColors = ButtonColors(
|
fun bitwardenOutlinedButtonColors(
|
||||||
containerColor = Color.Transparent,
|
contentColor: Color = BitwardenTheme.colorScheme.outlineButton.foreground,
|
||||||
contentColor = BitwardenTheme.colorScheme.outlineButton.foreground,
|
outlineColor: Color = BitwardenTheme.colorScheme.outlineButton.border,
|
||||||
disabledContainerColor = Color.Transparent,
|
outlineColorDisabled: Color = BitwardenTheme.colorScheme.outlineButton.borderDisabled,
|
||||||
disabledContentColor = BitwardenTheme.colorScheme.outlineButton.foregroundDisabled,
|
): BitwardenOutlinedButtonColors =
|
||||||
)
|
BitwardenOutlinedButtonColors(
|
||||||
|
materialButtonColors = ButtonColors(
|
||||||
|
containerColor = Color.Transparent,
|
||||||
|
contentColor = contentColor,
|
||||||
|
disabledContainerColor = Color.Transparent,
|
||||||
|
disabledContentColor = BitwardenTheme.colorScheme.outlineButton.foregroundDisabled,
|
||||||
|
),
|
||||||
|
outlineBorderColor = outlineColor,
|
||||||
|
outlinedDisabledBorderColor = outlineColorDisabled,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a default set of Bitwarden-styled colors for an outlined error button.
|
* Provides a default set of Bitwarden-styled colors for an outlined error button.
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.components.snackbar
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.button.color.bitwardenOutlinedButtonColors
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||||
|
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom snackbar for Bitwarden.
|
||||||
|
* Shows a message with an optional actions and title.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun BitwardenSnackbar(
|
||||||
|
bitwardenSnackbarData: BitwardenSnackbarData,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onDismiss: () -> Unit = {},
|
||||||
|
onActionClick: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier.padding(12.dp),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(
|
||||||
|
color = BitwardenTheme.colorScheme.background.alert,
|
||||||
|
shape = BitwardenTheme.shapes.snackbar,
|
||||||
|
)
|
||||||
|
.padding(16.dp),
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
bitwardenSnackbarData.messageHeader?.let {
|
||||||
|
Text(
|
||||||
|
text = it(),
|
||||||
|
color = BitwardenTheme.colorScheme.text.reversed,
|
||||||
|
style = BitwardenTheme.typography.titleSmall,
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(4.dp))
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = bitwardenSnackbarData.message(),
|
||||||
|
color = BitwardenTheme.colorScheme.text.reversed,
|
||||||
|
style = BitwardenTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
bitwardenSnackbarData.actionLabel?.let {
|
||||||
|
Spacer(Modifier.height(12.dp))
|
||||||
|
BitwardenOutlinedButton(
|
||||||
|
label = it(),
|
||||||
|
onClick = onActionClick,
|
||||||
|
colors = bitwardenOutlinedButtonColors(
|
||||||
|
contentColor = BitwardenTheme.colorScheme.text.reversed,
|
||||||
|
outlineColor = BitwardenTheme
|
||||||
|
.colorScheme
|
||||||
|
.outlineButton
|
||||||
|
.borderReversed,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bitwardenSnackbarData.withDismissAction) {
|
||||||
|
Spacer(Modifier.weight(1f))
|
||||||
|
IconButton(
|
||||||
|
onClick = onDismiss,
|
||||||
|
content = {
|
||||||
|
Icon(
|
||||||
|
rememberVectorPainter(R.drawable.ic_close),
|
||||||
|
contentDescription = stringResource(R.string.close),
|
||||||
|
tint = BitwardenTheme.colorScheme.icon.reversed,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun BitwardenCustomSnackbar_preview() {
|
||||||
|
BitwardenTheme {
|
||||||
|
Surface {
|
||||||
|
BitwardenSnackbar(
|
||||||
|
BitwardenSnackbarData(
|
||||||
|
messageHeader = "Header".asText(),
|
||||||
|
message = "Message".asText(),
|
||||||
|
actionLabel = "Action".asText(),
|
||||||
|
withDismissAction = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,35 +1,32 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.components.snackbar
|
package com.x8bit.bitwarden.ui.platform.components.snackbar
|
||||||
|
|
||||||
import androidx.compose.material3.Snackbar
|
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom Bitwarden-themed snackbar.
|
* A custom Bitwarden-themed snackbar.
|
||||||
*
|
*
|
||||||
* @param hostState The state of this snackbar.
|
* @param bitwardenHostState The state of this snackbar.
|
||||||
* @param modifier The [Modifier] to be applied to this radio button.
|
* @param modifier The [Modifier] to be applied to the [SnackbarHost].
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun BitwardenSnackbarHost(
|
fun BitwardenSnackbarHost(
|
||||||
hostState: SnackbarHostState,
|
bitwardenHostState: BitwardenSnackbarHostState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
SnackbarHost(
|
SnackbarHost(
|
||||||
hostState = hostState,
|
hostState = bitwardenHostState.snackbarHostState,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) { snackbarData ->
|
||||||
Snackbar(
|
val message = snackbarData.visuals.message
|
||||||
snackbarData = it,
|
val currentCustomSnackbarData = bitwardenHostState.currentSnackbarData
|
||||||
shape = BitwardenTheme.shapes.snackbar,
|
if (currentCustomSnackbarData?.key == message) {
|
||||||
containerColor = BitwardenTheme.colorScheme.background.alert,
|
BitwardenSnackbar(
|
||||||
contentColor = BitwardenTheme.colorScheme.text.reversed,
|
bitwardenSnackbarData = currentCustomSnackbarData,
|
||||||
actionColor = BitwardenTheme.colorScheme.background.alert,
|
onDismiss = snackbarData::dismiss,
|
||||||
actionContentColor = BitwardenTheme.colorScheme.icon.reversed,
|
onActionClick = snackbarData::performAction,
|
||||||
dismissActionContentColor = BitwardenTheme.colorScheme.icon.reversed,
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.components.snackbar
|
||||||
|
|
||||||
|
import androidx.compose.material3.SnackbarDuration
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.SnackbarResult
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom state holder for [BitwardenSnackbarData] and manging a snackbar host with the
|
||||||
|
* passed in [SnackbarHostState].
|
||||||
|
*/
|
||||||
|
@Stable
|
||||||
|
class BitwardenSnackbarHostState(
|
||||||
|
val snackbarHostState: SnackbarHostState,
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* The current snackbar data to be displayed.
|
||||||
|
*/
|
||||||
|
var currentSnackbarData: BitwardenSnackbarData? by mutableStateOf(null)
|
||||||
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a snackbar with the given [snackbarData]. Passes the [BitwardenSnackbarData.key]
|
||||||
|
* through the message parameter of the [SnackbarHostState.showSnackbar] method. This key
|
||||||
|
* can be used to identify the correct snackbar data to show in the host.
|
||||||
|
*/
|
||||||
|
suspend fun showSnackbar(
|
||||||
|
snackbarData: BitwardenSnackbarData,
|
||||||
|
duration: SnackbarDuration = SnackbarDuration.Short,
|
||||||
|
): SnackbarResult {
|
||||||
|
currentSnackbarData = snackbarData
|
||||||
|
return snackbarHostState
|
||||||
|
.showSnackbar(message = snackbarData.key, duration = duration)
|
||||||
|
.also { currentSnackbarData = null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models possible data to show in a custom bitwarden snackbar.
|
||||||
|
* @property message The text to show in the snackbar.
|
||||||
|
* @property messageHeader The optional title text to show.
|
||||||
|
* @property actionLabel The optional text to show in the action button.
|
||||||
|
* @property withDismissAction Whether to show the dismiss action.
|
||||||
|
* @property key The unique key for the [BitwardenSnackbarData].
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
data class BitwardenSnackbarData(
|
||||||
|
val message: Text,
|
||||||
|
val messageHeader: Text? = null,
|
||||||
|
val actionLabel: Text? = null,
|
||||||
|
val withDismissAction: Boolean = false,
|
||||||
|
) {
|
||||||
|
val key: String = this.hashCode().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [BitwardenSnackbarHostState] that is remembered across compositions.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun rememberBitwardenSnackbarHostState(
|
||||||
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
|
) = remember {
|
||||||
|
BitwardenSnackbarHostState(snackbarHostState)
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ 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
|
||||||
import androidx.compose.material3.SnackbarDuration
|
import androidx.compose.material3.SnackbarDuration
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
|
@ -24,7 +23,6 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
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
|
||||||
|
@ -55,7 +53,9 @@ 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.BitwardenSegmentedButton
|
||||||
import com.x8bit.bitwarden.ui.platform.components.segment.SegmentedButtonState
|
import com.x8bit.bitwarden.ui.platform.components.segment.SegmentedButtonState
|
||||||
import com.x8bit.bitwarden.ui.platform.components.slider.BitwardenSlider
|
import com.x8bit.bitwarden.ui.platform.components.slider.BitwardenSlider
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.rememberBitwardenSnackbarHostState
|
||||||
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.BitwardenWideSwitch
|
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch
|
||||||
import com.x8bit.bitwarden.ui.platform.components.util.nonLetterColorVisualTransformation
|
import com.x8bit.bitwarden.ui.platform.components.util.nonLetterColorVisualTransformation
|
||||||
|
@ -86,9 +86,7 @@ fun GeneratorScreen(
|
||||||
intentManager: IntentManager = LocalIntentManager.current,
|
intentManager: IntentManager = LocalIntentManager.current,
|
||||||
) {
|
) {
|
||||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
val context = LocalContext.current
|
val snackbarHostState = rememberBitwardenSnackbarHostState()
|
||||||
val resources = context.resources
|
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
|
||||||
|
|
||||||
LivecycleEventEffect { _, event ->
|
LivecycleEventEffect { _, event ->
|
||||||
when (event) {
|
when (event) {
|
||||||
|
@ -106,7 +104,7 @@ fun GeneratorScreen(
|
||||||
|
|
||||||
is GeneratorEvent.ShowSnackbar -> {
|
is GeneratorEvent.ShowSnackbar -> {
|
||||||
snackbarHostState.showSnackbar(
|
snackbarHostState.showSnackbar(
|
||||||
message = event.message(resources).toString(),
|
snackbarData = BitwardenSnackbarData(message = event.message),
|
||||||
duration = SnackbarDuration.Short,
|
duration = SnackbarDuration.Short,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -199,7 +197,7 @@ fun GeneratorScreen(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
snackbarHost = {
|
snackbarHost = {
|
||||||
BitwardenSnackbarHost(hostState = snackbarHostState)
|
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
|
||||||
},
|
},
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
|
|
Loading…
Reference in a new issue