Created
December 19, 2024 16:36
-
-
Save DevPicon/e42b17ab45f07011a80d3dd2666d9899 to your computer and use it in GitHub Desktop.
[Android] Custom Snackbar Demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data class CustomMode(val mode: Mode, val name: String, val minValue: Int, val maxValue: Int) | |
enum class Mode { | |
ONE, TWO, THREE, UNDEFINED | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun CustomSnackbarDemo( | |
modifier: Modifier = Modifier, | |
) { | |
val viewModel: CustomSnackbarViewModel = viewModel() | |
val state by viewModel.customSnackbarState.collectAsState() | |
val snackbarHostState = remember { SnackbarHostState() } | |
var retryCount by remember { mutableIntStateOf(0) } | |
val scope = rememberCoroutineScope() | |
var currentMode by remember { mutableStateOf(CustomMode(Mode.UNDEFINED, "", 0, 0)) } | |
when (state) { | |
is CustomSnackbarState.Offline -> { | |
Button( | |
onClick = { | |
viewModel.turnOn() | |
} | |
) { | |
Text("turn On") | |
} | |
} | |
is CustomSnackbarState.Online -> { | |
val onlineState = state as CustomSnackbarState.Online | |
if (onlineState.hasModeChangeFailed) { | |
LaunchedEffect(retryCount) { | |
snackbarHostState.currentSnackbarData?.dismiss() | |
snackbarHostState.showSnackbar( | |
message = "Mode change failed", | |
actionLabel = "Retry", | |
duration = SnackbarDuration.Long | |
) | |
} | |
Column( | |
horizontalAlignment = Alignment.CenterHorizontally, | |
verticalArrangement = Arrangement.Center | |
) { | |
Box( | |
Modifier.fillMaxSize(), | |
contentAlignment = Alignment.Center | |
) { | |
SnackbarHost( | |
hostState = snackbarHostState | |
) { snackbarData -> | |
CustomSnackbar( | |
title = "Mode change failed", | |
message = snackbarData.visuals.message, | |
showAction = retryCount < 3, | |
actionLabel = snackbarData.visuals.actionLabel ?: "Try again", | |
onAction = { | |
retryCount++ | |
viewModel.executeEvent(currentMode) | |
} | |
) | |
} | |
} | |
} | |
} else { | |
Column( | |
horizontalAlignment = Alignment.CenterHorizontally, | |
verticalArrangement = Arrangement.Center | |
) { | |
// Button to trigger Snackbar | |
Button( | |
onClick = { | |
val successMode = CustomMode(Mode.TWO, "Success", 1, 1) | |
currentMode = successMode | |
viewModel.executeEvent(currentMode) | |
} | |
) { | |
Text("Send Success") | |
} | |
// Button to trigger Snackbar | |
Button( | |
onClick = { | |
val failureMode = CustomMode(Mode.THREE, "Failure", 2, 2) | |
currentMode = failureMode | |
viewModel.executeEvent(currentMode) | |
} | |
) { | |
Text("Send Failure") | |
} | |
} | |
} | |
} | |
} | |
} | |
@Composable | |
fun CustomSnackbar( | |
title: String, | |
message: String, | |
showAction: Boolean, | |
actionLabel: String, | |
onAction: () -> Unit | |
) { | |
Surface( | |
color = Color.White, | |
shape = MaterialTheme.shapes.medium, | |
shadowElevation = 2.dp, | |
) { | |
Row( | |
Modifier | |
.padding(16.dp) | |
.fillMaxWidth(), | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
Row(Modifier.fillMaxWidth()) { | |
Column(Modifier.weight(1f)) { | |
Text( | |
text = title, | |
fontSize = 16.sp, | |
fontWeight = FontWeight.Bold, | |
color = Color.Black | |
) | |
Spacer(modifier = Modifier.height(4.dp)) | |
Text( | |
text = message, | |
fontSize = 14.sp, | |
color = Color.Gray | |
) | |
} | |
if (showAction) { | |
TextButton(onClick = onAction) { | |
Text( | |
text = actionLabel, | |
fontSize = 14.sp, | |
fontWeight = FontWeight.Bold, | |
textDecoration = TextDecoration.Underline, | |
color = Color.Black | |
) | |
} | |
} | |
} | |
} | |
} | |
} | |
@Preview | |
@Composable | |
private fun CustomSnackbarDemoPreview() { | |
CustomSnackbarDemo() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CustomSnackbarViewModel : ViewModel() { | |
private var _customSnackbarState = | |
MutableStateFlow<CustomSnackbarState>(CustomSnackbarState.Offline) | |
val customSnackbarState = _customSnackbarState | |
fun executeEvent(selectedMode: CustomMode) { | |
when (selectedMode.mode) { | |
Mode.ONE -> _customSnackbarState.value = CustomSnackbarState.Offline | |
Mode.THREE -> _customSnackbarState.update { state -> | |
if (state is CustomSnackbarState.Online) { | |
state.copy(hasModeChangeFailed = true) | |
} else { | |
CustomSnackbarState.Online(hasModeChangeFailed = true) | |
} | |
} | |
Mode.TWO, | |
Mode.UNDEFINED -> _customSnackbarState.update { state -> | |
CustomSnackbarState.Online() | |
} | |
} | |
} | |
fun turnOn() { | |
_customSnackbarState.update { | |
CustomSnackbarState.Online() | |
} | |
} | |
} | |
sealed class CustomSnackbarState { | |
data object Offline : CustomSnackbarState() | |
data class Online(val hasModeChangeFailed: Boolean = false) : CustomSnackbarState() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment