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