Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added enabled changed listeners to BackDispatcher #146

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions back-handler/api/android/back-handler.api
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ public final class com/arkivanov/essenty/backhandler/BackCallbackKt {
}

public abstract interface class com/arkivanov/essenty/backhandler/BackDispatcher : com/arkivanov/essenty/backhandler/BackHandler {
public abstract fun addEnabledChangedListener (Lkotlin/jvm/functions/Function1;)V
public abstract fun back ()Z
public abstract fun isEnabled ()Z
public abstract fun removeEnabledChangedListener (Lkotlin/jvm/functions/Function1;)V
public abstract fun startPredictiveBack (Lcom/arkivanov/essenty/backhandler/BackEvent;)Lcom/arkivanov/essenty/backhandler/BackDispatcher$PredictiveBackDispatcher;
}

Expand Down
2 changes: 2 additions & 0 deletions back-handler/api/jvm/back-handler.api
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ public final class com/arkivanov/essenty/backhandler/BackCallbackKt {
}

public abstract interface class com/arkivanov/essenty/backhandler/BackDispatcher : com/arkivanov/essenty/backhandler/BackHandler {
public abstract fun addEnabledChangedListener (Lkotlin/jvm/functions/Function1;)V
public abstract fun back ()Z
public abstract fun isEnabled ()Z
public abstract fun removeEnabledChangedListener (Lkotlin/jvm/functions/Function1;)V
public abstract fun startPredictiveBack (Lcom/arkivanov/essenty/backhandler/BackEvent;)Lcom/arkivanov/essenty/backhandler/BackDispatcher$PredictiveBackDispatcher;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import androidx.lifecycle.LifecycleOwner
* Creates a new instance of [BackHandler] and attaches it to the provided AndroidX [OnBackPressedDispatcher].
*/
fun BackHandler(onBackPressedDispatcher: OnBackPressedDispatcher): BackHandler =
AndroidBackHandler(
addCallback = onBackPressedDispatcher::addCallback,
)
AndroidBackHandler().also {
onBackPressedDispatcher.addCallback(it.onBackPressedCallback)
}

/**
* Creates a new instance of [BackHandler] and attaches it to the provided AndroidX [OnBackPressedDispatcher]
Expand All @@ -22,9 +22,9 @@ fun BackHandler(
onBackPressedDispatcher: OnBackPressedDispatcher,
lifecycleOwner: LifecycleOwner,
): BackHandler =
AndroidBackHandler(
addCallback = { callback -> onBackPressedDispatcher.addCallback(lifecycleOwner, callback) },
)
AndroidBackHandler().also {
onBackPressedDispatcher.addCallback(lifecycleOwner, it.onBackPressedCallback)
}

/**
* Creates a new instance of [BackHandler] and attaches it to the AndroidX [OnBackPressedDispatcher].
Expand All @@ -33,54 +33,34 @@ fun OnBackPressedDispatcherOwner.backHandler(): BackHandler =
BackHandler(onBackPressedDispatcher = onBackPressedDispatcher)

private class AndroidBackHandler(
addCallback: (OnBackPressedCallback) -> Unit,
) : BackHandler {
private val dispatcher: BackDispatcher = BackDispatcher()
) : BackHandler by dispatcher {

private var set = emptySet<BackCallback>()
val onBackPressedCallback: OnBackPressedCallback =
object : OnBackPressedCallback(enabled = dispatcher.isEnabled) {
private var predictiveBackDispatcher: BackDispatcher.PredictiveBackDispatcher? = null

private val delegateCallback =
object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
set.findMostImportant()?.onBack()
dispatcher.back()
predictiveBackDispatcher = null
}

override fun handleOnBackStarted(backEvent: BackEventCompat) {
set.findMostImportant()?.onBackStarted(backEvent.toEssentyBackEvent())
predictiveBackDispatcher = dispatcher.startPredictiveBack(backEvent.toEssentyBackEvent())
}

override fun handleOnBackProgressed(backEvent: BackEventCompat) {
set.findMostImportant()?.onBackProgressed(backEvent.toEssentyBackEvent())
predictiveBackDispatcher?.progress(backEvent.toEssentyBackEvent())
}

override fun handleOnBackCancelled() {
set.findMostImportant()?.onBackCancelled()
predictiveBackDispatcher?.cancel()
predictiveBackDispatcher = null
}
}

private val enabledChangedListener: (Boolean) -> Unit = { onEnabledChanged() }

init {
addCallback(delegateCallback)
}

override fun register(callback: BackCallback) {
check(callback !in set) { "Callback is already registered" }

this.set += callback
callback.addEnabledChangedListener(enabledChangedListener)
onEnabledChanged()
}

override fun unregister(callback: BackCallback) {
check(callback in set) { "Callback is not registered" }

callback.removeEnabledChangedListener(enabledChangedListener)
this.set -= callback
onEnabledChanged()
}

private fun onEnabledChanged() {
delegateCallback.isEnabled = set.any(BackCallback::isEnabled)
dispatcher.addEnabledChangedListener { onBackPressedCallback.isEnabled = it }
}

private fun BackEventCompat.toEssentyBackEvent(): BackEvent =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ interface BackDispatcher : BackHandler {
*/
val isEnabled: Boolean

fun addEnabledChangedListener(listener: (isEnabled: Boolean) -> Unit)

fun removeEnabledChangedListener(listener: (isEnabled: Boolean) -> Unit)

/**
* Iterates through all registered callbacks in reverse order and triggers the first one enabled.
*
Expand Down Expand Up @@ -51,4 +55,5 @@ interface BackDispatcher : BackHandler {
* Creates and returns a default implementation of [BackDispatcher].
*/
@JsName("backDispatcher")
fun BackDispatcher(): BackDispatcher = DefaultBackDispatcher()
fun BackDispatcher(): BackDispatcher =
DefaultBackDispatcher()
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,40 @@ internal class DefaultBackDispatcher : BackDispatcher {

private var set = emptySet<BackCallback>()
override val isEnabled: Boolean get() = set.any(BackCallback::isEnabled)
private var enabledChangedListeners = emptySet<(Boolean) -> Unit>()
private var hasEnabledCallback: Boolean = false
private val onCallbackEnabledChanged: (Boolean) -> Unit = { onCallbackEnabledChanged() }

private fun onCallbackEnabledChanged() {
val hasEnabledCallback = isEnabled
if (this.hasEnabledCallback != hasEnabledCallback) {
this.hasEnabledCallback = hasEnabledCallback
enabledChangedListeners.forEach { it.invoke(hasEnabledCallback) }
}
}

override fun register(callback: BackCallback) {
check(callback !in set) { "Callback is already registered" }

this.set += callback
callback.addEnabledChangedListener(onCallbackEnabledChanged)
onCallbackEnabledChanged()
}

override fun unregister(callback: BackCallback) {
check(callback in set) { "Callback is not registered" }

this.set -= callback
callback.removeEnabledChangedListener(onCallbackEnabledChanged)
onCallbackEnabledChanged()
}

override fun addEnabledChangedListener(listener: (isEnabled: Boolean) -> Unit) {
enabledChangedListeners += listener
}

override fun removeEnabledChangedListener(listener: (isEnabled: Boolean) -> Unit) {
enabledChangedListeners -= listener
}

override fun back(): Boolean = set.call()
Expand Down
Loading
Loading