https://kotlinlang.org logo
#compose
Title
# compose
b

Bearings of Platinum

02/28/2024, 12:44 AM
Hi, I currently have something like this:
Copy code
var isFetching by rememberSaveable { mutableStateOf(false) }
// some networking code that sets it to true whenever a network request starts,
// and back to false once the network request completes or fails
AnimatedContent(isFetching, ...) { ... }
It works fine but since the network requests usually complete before the
AnimatedContent
composable even has a single frame to show content, is there a way to force it to show the content as if
isFetching
were true for a bit longer, like 100ms?
a

Alex Vanyo

02/28/2024, 1:16 AM
I would see if you can introduce an additional layer of state that you have control over that precisely indicates the minimum duration behavior that you want to achieve, so maybe something along the lines of this:
Copy code
var isFetching by rememberSaveable { mutableStateOf(false) }

val shouldDisplayLoading by produceState(isFetching) {
    @OptIn(FlowPreview::class)
    snapshotFlow { isFetching }
        .debounce(100)
        .collect { value = it }
}

AnimatedContent(shouldDisplayLoading, ...) { ... }
This keeps the source of truth of each layer distinct and clear:
isFetching
still represents precisely if the request is happening.
AnimatedContent
still does its normal thing, based on the value of a
Boolean
state.
shouldDisplayLoading
is a new piece of state introduced to represent precisely whether or not you want to show the content. And then
shouldDisplayLoading
can be derived from
isFetching
using the debouncing logic of your choice.
👍 2
m

myanmarking

02/28/2024, 9:25 AM
i would solve it in viewModel layer. You can create a wrapper suspend function that makes sure it won't return before some delay. For example, 500ms. If the network request is longer, it does nothing. Otherwise, it delays the remaining time
s

Stylianos Gakis

02/28/2024, 10:17 AM
In general I despise things looking like they take longer than they actually do, but I had to do it once and it was done the way JCRQ is saying here https://github.com/HedvigInsurance/android/blob/0196026a2740612d16d8f4d64283ad856d[…]einsurance/step/terminationreview/TerminationReviewViewModel.kt The important bit being that you do not want it to still delay for no reason if there was in fact a failure. And that you do not want to add 3 seconds on top of what your real action was already doing. Just to take the maximum between 3 seconds and how much the real action takes. Something easy to miss if you do the delay and the request sequentially instead of at the same time.
👍 1
m

myanmarking

02/28/2024, 12:13 PM
It depends. In case of failure you could still delay. Take an example as a screen that needs some expensive queries to load. It can be fast or not. If you show a circularprogressbar, it can appear and imediatly disappear which looks terrible. Insteal, delaying for small ms actually improved ui imo
s

Stylianos Gakis

02/28/2024, 12:30 PM
You can have a minimum time for the failure too, for sure. In our case we did in fact want to fail immediately as the UI could handle it in this particular case. The failure should absolutely not take 3 seconds though 😂 I already had this argument about 3 being way too much so I am re-living those moments all over again in this discussion 😅
m

myanmarking

02/28/2024, 12:41 PM
Not 3s xd. 300ms is enough for loader to appear and disappear without feelinh weird
👌 1
4 Views