yuriy.stetsyk
04/25/2023, 7:02 PMFlow<T>.collectAsSnackBarStateWithLifecycle(...): State<AppSnackBarData?>
AppSnackBarData
is my custom SnackBar description. It will be shown until produced state emits null
The goal is to produce state that emits null
after short period of time, to dismiss snack bar.
Details it thread
Would appreciate any tips/improvements, thanks!yuriy.stetsyk
04/25/2023, 7:06 PMFlow<T>.collectAsStateWithLifecycle(...): State<T>
My current version looks like this
@Composable
fun <T> Flow<T>.collectAsSnackBarStateWithLifecycle(
snackbarDuration: SnackbarDuration = SnackbarDuration.Short,
accessibilityManager: AccessibilityManager? = LocalAccessibilityManager.current,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
context: CoroutineContext = EmptyCoroutineContext,
mapToSnackbarData: (T) -> AppSnackbarData?,
): State<AppSnackbarData?> = collectAsSnackBarStateWithLifecycle(
snackbarDuration = snackbarDuration,
accessibilityManager = accessibilityManager,
lifecycle = lifecycleOwner.lifecycle,
minActiveState = minActiveState,
context = context,
mapToSnackbarData = mapToSnackbarData,
)
@Composable
fun <T> Flow<T>.collectAsSnackBarStateWithLifecycle(
snackbarDuration: SnackbarDuration,
accessibilityManager: AccessibilityManager?,
lifecycle: Lifecycle,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
context: CoroutineContext = EmptyCoroutineContext,
mapToSnackbarData: (T) -> AppSnackbarData?,
): State<AppSnackbarData?> {
return produceState<AppSnackbarData?>(
null,
this,
snackbarDuration,
accessibilityManager,
lifecycle,
minActiveState,
context,
mapToSnackbarData,
) {
suspend fun transformAndEmit(t: T) {
val data = mapToSnackbarData(t)
this@produceState.value = data
if (data != null && data.style !is AppSnackbarStyle.Progress) {
delay(snackbarDuration.toMillis(accessibilityManager))
this@produceState.value = null
}
}
lifecycle.repeatOnLifecycle(minActiveState) {
if (context == EmptyCoroutineContext) {
this@collectAsSnackBarStateWithLifecycle.collectLatest { // Using collectLatest to cancel delay in transformAndEmit
transformAndEmit(it)
}
} else withContext(context) {
this@collectAsSnackBarStateWithLifecycle.collectLatest {
transformAndEmit(it)
}
}
}
}
}
Main usage would look as follows
val snackBarData by alerts.collectAsSnackBarStateWithLifecycle { alert -> alert.asSnackBarData() }
Though it behaves as expected in my tests, but I have a few concerns
1. mapToSnackbarData
lambda, should it be remembered before passing it to collectAsSnackBarStateWithLifecycle
, as it is one of the keys for produceState
2. Usage of collectLatest
, I think it it safe to use it, but not sure