Skip to content

Latest commit

 

History

History
146 lines (123 loc) · 4.43 KB

SAMPLES.md

File metadata and controls

146 lines (123 loc) · 4.43 KB

Here are some samples of how to use library's API.

DebounceStateIndentity.debounce()

Inside View, Presenter or ViewModel

val signInButtonState = DebounceStateIdentity()

fun onSignInButtonClick() =
    signInButtonState.debounce {
        yourCoroutineScope.launch {
            authApi.signIn() // suspending call
            navigateToMainScreen()
            releaseIn(600.milliseconds) // or release() if you want release debouncing immediately
        }
    }

Important

It is crucial to remember() DebounceStateIdentity() to preserve debouncing state across recomposition.

Tip

You should also remember() onClick action due to unstable lambdas or use method reference.

val coroutineScope = rememberCoroutineScope()
val buttonState = remember { DebounceStateIdentity() }

val onClick: () -> Unit = remember {
    {
        buttonState.debounce {
            coroutineScope.launch {
                animateUi() // suspending call
                release()
            }
        }
    }
}

Button(onClick = onClick) {
    Text("Animate UI")
}

debounced()

Basic:

val onClick = debounced(400.milliseconds) { println("Clicked!") }
onClick() // "Clicked!"
onClick() // debounced
delay(500.milliseconds) // timeout has passed
onClick() // "Clicked!"
onClick() // debounced

Advanced, general callback

val onClick = debounced(
    timeout = 400.milliseconds,
    action = { println("Clicked!") },
    onInvoke = { wasExecuted -> println("Action was executed: $wasExecuted") },
)
onClick() // "Clicked!", "Action was executed: true"
onClick() // debounced, "Action was executed: false"
delay(500.milliseconds) // timeout has passed
onClick() // "Clicked!", "Action was executed: true"
onClick() // debounced, "Action was executed: false"

Advanced, specific callbacks

val onClick = debounced(
    timeout = 400.milliseconds,
    action = { println("Clicked!") },
    onExecuted = { println("Action was executed") },
    onDebounced = { timeLeft -> println("Action was debounced, time left: $timeLeft") },
)
onClick() // "Clicked!", "Action was executed"
onClick() // debounced, "Action was debounced, time left: 399.86ms"
delay(500.milliseconds) // timeout has passed
onClick() // "Clicked!", "Action was executed"
delay(300.milliseconds) // timeout hasn't passed
onClick() // debounced, "Action was debounced, time left: 88.81ms"

Important

It is crucial to remember() debounced() action to preserve debouncing state across recomposition.

val onClick = remember {
    debounced(2.seconds) {
        navigator.navigateToNextScreen()
    }
}
Button(onClick = onClick) {
    Text("Go to next screen")
}

Observing debouncing state

There is no observable provided by the library out of the box. You can implement your own with the technology you're using, like Kotlin Coroutines or RxJava. Following simplified example uses Kotlin Coroutines and Flows.

val timeout = 1.seconds
// 1. create mutable Flow
val isReadyFlow = MutableStateFlow(true)
val action = debounced(
    timeout = timeout,
    onExecuted = {
        // 2. update isReadyFlow
        yourCoroutineScope.launch { isReadyFlow.updateOnExecuted(timeout) }
    },
    action = { println("Action executed!") },
)

// 3. subscribe to value updates
yourCoroutineScope.launch {
    isReadyFlow.collect { isReady ->
        println("isReady is $isReady")
    }
}

// 4. action is ready to be used
action()

/*
 * Once action was executed, we update our Flow with false,
 * meaning that successive calls will be debounced.
 * After timeout used to create a debounced action has passed,
 * we update the Flow with true, meaning that successive call will be executed.
 */
private suspend fun MutableStateFlow<Boolean>.updateOnExecuted(timeout: Duration) {
    value = false
    delay(timeout)
    value = true
}