lce icon indicating copy to clipboard operation
lce copied to clipboard

Add support for folding into composables

Open warting opened this issue 3 years ago • 2 comments

Whould it make sence for this library to be able to fold types to composables? Maybe an extension that supports composable?

I have done something like this to convert the types into something that can be representable to the user:

@Composable
inline fun <C> UCT<C>.Compose(
    crossinline onLoading: @Composable () -> Unit,
    crossinline onError: @Composable (Throwable) -> Unit,
    crossinline onContent: @Composable (C) -> Unit
) {
    return ComposeTypes(
        onLoading = { onLoading() },
        onContent = { onContent(it.value) },
        onError = { onError(it.value) }
    )
}

@Composable
inline fun <C> UCT<C>.ComposeTypes(
    crossinline onLoading: @Composable (Type.Loading.UnitType) -> Unit,
    crossinline onContent: @Composable (Type.Content<C>) -> Unit,
    crossinline onError: @Composable (Type.Error.ThrowableType) -> Unit
) {
    return when (val type = asLceType()) {
        is Type.Loading.UnitType -> onLoading(type)
        is Type.Content -> onContent(type)
        is Type.Error.ThrowableType -> onError(type)
        else -> throw IllegalStateException("this should not happen: $type")
    }
}

and then the usages could be something like this:

    val uiState by remember {
        mutableStateOf(UCT.content("hello earth!"))
    }
    uiState.Compose(
        onError = {
            Text(text = it.message ?: "")
            ErrorView(stringResource(id = R.string.error))
        },
        onLoading = {
            LoadingView(stringResource(id = R.string.loading))
        },
        onContent = {
            Text(text = it)
        }
    )

warting avatar Apr 01 '22 11:04 warting

Hey, thanks for submitting an issue. This makes sense to me, I think we should have lce-compose module for such utilities.

Looking at what I see in our codebase, there seems to be some nuance around animations. We aren't using fold because of the way animation container also needs to know when to animate out which depends on nullability of the model. I wonder if there is a public API that would be simple yet flexible or maybe we need to have two options.

@Composable
inline fun <Content> UCT<Content>.Render(
    crossinline onLoading: @Composable () -> Unit,
    crossinline onError: @Composable (Throwable) -> Unit,
    crossinline onContent: @Composable (C) -> Unit
) {
    AnimateContentIn(loadingOrNull()) { onLoading() }
    AnimateContentIn(errorOrNull()) { onError(it) }
    AnimateContentIn(contentOrNull()) { onContent(it) }
}

@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun <T> AnimateContentIn(model: T?, content: @Composable (T) -> Unit) {
    AnimatedVisibility(visible = model != null, enter = fadeIn(), exit = fadeOut()) {
        model?.let { content(it) }
    }
}

Laimiux avatar Apr 01 '22 17:04 Laimiux

Any movement on this?

mveroukis avatar Mar 18 '23 15:03 mveroukis