Pablo
05/18/2021, 3:38 PMfun <T> debounce(
delayMillis: Long = 300L,
scope: CoroutineScope,
action: (T) -> Unit
): (T) -> Unit {
var debounceJob: Job? = null
return { param: T ->
if (debounceJob == null) {
debounceJob = scope.launch {
action(param)
delay(delayMillis)
debounceJob = null
}
}
}
}
Where I can do
fun setDebounceListener(view: Button, onClickListener: View.OnClickListener) {
val clickWithDebounce: (view: View) -> Unit =
debounce(scope = MainScope()) {
onClickListener.onClick(it)
}
view.setOnClickListener(clickWithDebounce)
}
Does it make sense to use debounce here? It's just to avoid double click on a Buttonlouiscad
05/18/2021, 4:20 PMlouiscad
05/18/2021, 4:23 PMawaitOneClick() in the flow { … } builder.Pablo
05/19/2021, 7:35 AMPablo
05/19/2021, 7:35 AMlouiscad
05/19/2021, 7:36 AMPablo
05/19/2021, 7:40 AMlouiscad
05/19/2021, 7:40 AMxxxLatest operators if called from a flow operatorPablo
05/19/2021, 7:40 AMPablo
05/19/2021, 7:41 AMlouiscad
05/19/2021, 7:42 AMawaitOneClick() again until your app wants to allow clicks againlouiscad
05/19/2021, 7:42 AMlouiscad
05/19/2021, 7:44 AMsuspend handleStuff() {
while (true) {
btn.awaitOneClick()
doStuff()
}
}louiscad
05/19/2021, 7:44 AMPablo
05/19/2021, 7:44 AMlouiscad
05/19/2021, 7:44 AMdoStuff() is a suspending function)Pablo
05/19/2021, 7:44 AMfun View.clicks(): Flow<Unit> = callbackFlow {
setOnClickListener {
offer(Unit)
}
awaitClose { setOnClickListener(null) }
}louiscad
05/19/2021, 7:45 AMPablo
05/19/2021, 7:45 AMbutton.clicks().debounce(1000).onEach { println("clicked") }.launchIn(GlobalScope)louiscad
05/19/2021, 7:46 AMFlow is the following:
fun View.clicks(): Flow<Unit> = flow {
while (true) {
awaitOneClick()
emit(Unit)
}
}louiscad
05/19/2021, 7:47 AMemit is suspending (which is when the lambda of collect is executing)Pablo
05/19/2021, 7:48 AMPablo
05/19/2021, 7:48 AMlouiscad
05/19/2021, 7:49 AMPablo
05/19/2021, 7:49 AMlouiscad
05/19/2021, 7:49 AMawaitOneClick()Pablo
05/19/2021, 7:49 AMPablo
05/19/2021, 7:49 AMlouiscad
05/19/2021, 7:50 AMlouiscad
05/19/2021, 7:50 AMPablo
05/19/2021, 7:50 AMPablo
05/19/2021, 7:51 AMlouiscad
05/19/2021, 7:51 AMPablo
05/19/2021, 7:54 AMPablo
05/19/2021, 7:54 AMPablo
05/19/2021, 7:55 AMlouiscad
05/19/2021, 7:56 AMPablo
05/19/2021, 7:58 AMlouiscad
05/19/2021, 7:59 AMlouiscad
05/19/2021, 8:00 AMPablo
05/19/2021, 8:01 AMPablo
05/19/2021, 8:01 AMPablo
05/19/2021, 8:01 AMlouiscad
05/19/2021, 8:01 AMlouiscad
05/19/2021, 8:02 AMlouiscad
05/19/2021, 8:02 AMPablo
05/19/2021, 8:02 AMPablo
05/19/2021, 8:07 AMPablo
05/19/2021, 8:07 AMPablo
05/19/2021, 8:10 AMscope.launch {
singleClick().onEach {
itemClicked.invoke(position)
}.launchIn(this)
}Pablo
05/19/2021, 8:26 AMlouiscad
05/19/2021, 8:28 AMcollect instead, yup. Also, having a flow that actually gives only one value ever is weird, name-wise, and use-wise, just using awaitOneClick() would make more sense here.Pablo
05/19/2021, 8:30 AMPablo
05/19/2021, 8:30 AMPablo
05/19/2021, 8:44 AMlouiscad
05/19/2021, 8:46 AMPablo
05/19/2021, 8:47 AMfun View.clicks(): Flow<Unit> = flow {
while (true) {
awaitOneClick()
emit(Unit)
}
}Pablo
05/19/2021, 8:47 AMlouiscad
05/19/2021, 8:47 AMPablo
05/19/2021, 8:47 AMPablo
05/19/2021, 8:49 AMlouiscad
05/19/2021, 8:50 AMlouiscad
05/19/2021, 8:50 AMlouiscad
05/19/2021, 8:50 AMPablo
05/19/2021, 8:52 AMPablo
05/19/2021, 8:52 AMPablo
05/19/2021, 8:53 AMlouiscad
05/19/2021, 8:56 AMdelay(timeMillis = 700) or alike after doing it before calling awaitOneClick() againPablo
05/19/2021, 8:57 AMlouiscad
05/19/2021, 8:58 AMPablo
05/19/2021, 8:58 AMPablo
05/19/2021, 9:00 AMPablo
05/19/2021, 9:00 AMlouiscad
05/19/2021, 9:00 AMView that takes a CoroutineScopePablo
05/19/2021, 9:01 AMlouiscad
05/19/2021, 9:01 AMlouiscad
05/19/2021, 9:02 AMawaitOneClick(). suspendCancellable is an implementation detail of awaitOneClickPablo
05/19/2021, 9:03 AMsuspend fun View.awaitOneClick(
disableAfterClick: Boolean = true,
hideAfterClick: Boolean = false,
onClick: (View) -> Unit,
) = try {
if (disableAfterClick) isEnabled = true
if (hideAfterClick) isVisible = true
suspendCancellableCoroutine<Unit> { continuation ->
setOnClickListener {
onClick.invoke(it)
continuation.resume(Unit)
}
}
} finally {
setOnClickListener(null)
if (disableAfterClick) isEnabled = false
if (hideAfterClick) isVisible = false
}louiscad
05/19/2021, 9:03 AMPablo
05/19/2021, 9:04 AMawaitOneClick { //do something }louiscad
05/19/2021, 9:04 AMlouiscad
05/19/2021, 9:05 AMawaitOneClick() (kidding about the TM, but you can find a clearer name to the function that'd use awaitOneClick() )Pablo
05/19/2021, 9:06 AMscope.launch{
while(true){
delay(700)
awaitOnClick{
onClick.invoke(position)
}
}louiscad
05/19/2021, 9:09 AMawaitOneClick()?
Just put if after calling awaitOneClick().louiscad
05/19/2021, 9:09 AMdelay should be after that code, not before.louiscad
05/19/2021, 9:09 AMlouiscad
05/19/2021, 9:10 AMPablo
05/19/2021, 9:10 AMPablo
05/19/2021, 9:11 AMYou see the code you want to pass in the non existing lambda ofI add it in your code when I said "I have this from now"?awaitOneClick()
louiscad
05/19/2021, 9:13 AMlouiscad
05/19/2021, 9:13 AMlouiscad
05/19/2021, 9:13 AMlouiscad
05/19/2021, 9:13 AMlouiscad
05/19/2021, 9:14 AMlaunchLoop is launch on a scope + while (isActive)Pablo
05/19/2021, 9:21 AMfun View.handleSingleClick(scope: CoroutineScope, block: () -> Unit) {
scope.launch{
while(true){
awaitOneClick()
block()
delay(700)
}
}
}louiscad
05/19/2021, 9:26 AMPablo
05/19/2021, 9:26 AMlouiscad
05/19/2021, 9:27 AMlouiscad
05/19/2021, 9:28 AM