Hello there! I’m trying to write helper function f...
# compose
y
Hello there! I’m trying to write helper function for
Flow<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!
y
I took inspiration from implementation of
Flow<T>.collectAsStateWithLifecycle(...): State<T>
My current version looks like this
Copy code
@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
Copy code
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