From 156f6a51eadb5e498ec5eb5c3dee71ebcec5ffcb Mon Sep 17 00:00:00 2001 From: Isaac Udy Date: Wed, 22 May 2024 01:32:45 +1200 Subject: [PATCH] Added `NavigationResultScope` as a receiver for all registerForNavigationResult calls, to allow for more advanced handling of results and inspection of the instruction and navigation key that was used to open the result request. --- CHANGELOG.md | 1 + .../controller/usecase/AddPendingResult.kt | 6 +- .../controller/usecase/CreateResultChannel.kt | 27 +++--- .../core/result/AdvancedResultExtensions.kt | 6 +- .../core/result/NavigationResultExtensions.kt | 87 ++++++++++--------- .../enro/core/result/NavigationResultScope.kt | 9 ++ .../core/result/flows/FlowResultChannel.kt | 13 +-- .../internal/LazyResultChannelProperty.kt | 30 ++++--- .../core/result/internal/PendingResult.kt | 6 +- .../core/result/internal/ResultChannelImpl.kt | 22 ++--- .../compose/ComposableNavigationResult.kt | 5 +- .../enro/test/extensions/ResultExtensions.kt | 14 +-- 12 files changed, 131 insertions(+), 95 deletions(-) create mode 100644 enro-core/src/main/java/dev/enro/core/result/NavigationResultScope.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 68c4c3df..13f7d7f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.5.0 * Added `update` to the public API for `NavigationFlow`, as this is required for some use cases where the flow needs to be updated after changes in external state which may affect the logic of the flow. This function was previously named `next`, and removed from the public API in 2.4.0. * Moved `NavigationContext.getViewModel` and `requireViewModel` extensions to the `dev.enro.viewmodel` package. +* Added `NavigationResultScope` as a receiver for all registerForNavigationResult calls, to allow for more advanced handling of results and inspection of the instruction and navigation key that was used to open the result request. ## 2.4.1 * Added `EnroBackConfiguration`, which can be set when creating a `NavigationController`. This controls how Enro handles back presses. diff --git a/enro-core/src/main/java/dev/enro/core/controller/usecase/AddPendingResult.kt b/enro-core/src/main/java/dev/enro/core/controller/usecase/AddPendingResult.kt index 5e01f3a9..334ea4c9 100644 --- a/enro-core/src/main/java/dev/enro/core/controller/usecase/AddPendingResult.kt +++ b/enro-core/src/main/java/dev/enro/core/controller/usecase/AddPendingResult.kt @@ -27,9 +27,10 @@ internal class AddPendingResult( ownerId = openInstruction.instructionId, resultId = openInstruction.instructionId ) + else -> return } - when(instruction) { + when (instruction) { NavigationInstruction.Close -> { // If this instruction is forwarding a result from another instruction, // we don't want this instruction to actually deliver the close result, as only @@ -38,13 +39,16 @@ internal class AddPendingResult( enroResult.addPendingResult( PendingResult.Closed( resultChannelId = resultId, + instruction = navigationContext.instruction, navigationKey = navigationKey, ) ) } + is NavigationInstruction.Close.WithResult -> enroResult.addPendingResult( PendingResult.Result( resultChannelId = resultId, + instruction = navigationContext.instruction, navigationKey = navigationKey, resultType = instruction.result::class, result = instruction.result, diff --git a/enro-core/src/main/java/dev/enro/core/controller/usecase/CreateResultChannel.kt b/enro-core/src/main/java/dev/enro/core/controller/usecase/CreateResultChannel.kt index c7c3fa5d..6ac29be1 100644 --- a/enro-core/src/main/java/dev/enro/core/controller/usecase/CreateResultChannel.kt +++ b/enro-core/src/main/java/dev/enro/core/controller/usecase/CreateResultChannel.kt @@ -4,6 +4,7 @@ import dev.enro.core.NavigationHandle import dev.enro.core.NavigationKey import dev.enro.core.controller.get import dev.enro.core.result.EnroResult +import dev.enro.core.result.NavigationResultScope import dev.enro.core.result.UnmanagedNavigationResultChannel import dev.enro.core.result.internal.ResultChannelImpl import kotlin.reflect.KClass @@ -17,9 +18,6 @@ internal class CreateResultChannel( @PublishedApi internal val navigationHandle: NavigationHandle, @PublishedApi internal val enroResult: EnroResult, ) { - - - /** * The resultId being set here to the JVM class name of the onResult lambda is a key part of * being able to make result channels work without providing an explicit id. The JVM will treat @@ -49,21 +47,22 @@ internal class CreateResultChannel( * fall back to explicit identification of the channels in the case that the Kotlin/JVM behaviour * changes in the future. */ - fun Any.createResultId() : String { + fun Any.createResultId(): String { return this::class.java.name } // It is important that these functions are inlined, so that the empty lambda can be used // as a part of the result id, which is helpful for providing uniqueness related to location in // the code + @Deprecated("Use the other overload of invoke, as key is provided through the NavigationResultScope and doesn't need to be passed as a parameter") inline operator fun > invoke( resultType: KClass, - crossinline onClosed: () -> Unit, - noinline onResult: (Result) -> Unit, + crossinline onClosed: NavigationResultScope.(Key) -> Unit, + noinline onResult: NavigationResultScope.(Key, Result) -> Unit, additionalResultId: String = "", ): UnmanagedNavigationResultChannel { - val internalOnClosed: (Key) -> Unit = { _ -> onClosed() } - val internalOnResult: (Key, Result) -> Unit = { _, result -> onResult(result) } + val internalOnClosed: NavigationResultScope.() -> Unit = { onClosed(key) } + val internalOnResult: NavigationResultScope.(Result) -> Unit = { result -> onResult(key, result) } val resultId = onResult.createResultId() + "@" + internalOnResult.createResultId().hashCode() return create( resultType = resultType, @@ -79,12 +78,12 @@ internal class CreateResultChannel( // the code inline operator fun > invoke( resultType: KClass, - crossinline onClosed: (Key) -> Unit, - noinline onResult: (Key, Result) -> Unit, + crossinline onClosed: NavigationResultScope.() -> Unit, + noinline onResult: NavigationResultScope.(Result) -> Unit, additionalResultId: String = "", ): UnmanagedNavigationResultChannel { - val internalOnClosed: (Key) -> Unit = { key -> onClosed(key) } - val internalOnResult: (Key, Result) -> Unit = { key, result -> onResult(key, result) } + val internalOnClosed: NavigationResultScope.() -> Unit = { onClosed(this) } + val internalOnResult: NavigationResultScope.(Result) -> Unit = { result -> onResult(this, result) } val resultId = onResult.createResultId() + "@" + internalOnResult.createResultId().hashCode() return create( resultType = resultType, @@ -99,8 +98,8 @@ internal class CreateResultChannel( internal fun > create( resultType: KClass, resultId: String, - onClosed: (Key) -> Unit, - onResult: (Key, Result) -> Unit, + onClosed: NavigationResultScope.() -> Unit, + onResult: NavigationResultScope.(Result) -> Unit, additionalResultId: String = "", ): UnmanagedNavigationResultChannel { return ResultChannelImpl( diff --git a/enro-core/src/main/java/dev/enro/core/result/AdvancedResultExtensions.kt b/enro-core/src/main/java/dev/enro/core/result/AdvancedResultExtensions.kt index 082c70b6..73236001 100644 --- a/enro-core/src/main/java/dev/enro/core/result/AdvancedResultExtensions.kt +++ b/enro-core/src/main/java/dev/enro/core/result/AdvancedResultExtensions.kt @@ -10,7 +10,7 @@ import dev.enro.core.result.internal.PendingResult @AdvancedEnroApi public object AdvancedResultExtensions { - public fun getForwardingInstructionId(instruction: NavigationInstruction.Open<*>) : String? { + public fun getForwardingInstructionId(instruction: NavigationInstruction.Open<*>): String? { return instruction.extras[FORWARDING_RESULT_FROM_EXTRA] as? String } @@ -18,7 +18,7 @@ public object AdvancedResultExtensions { originalInstruction: NavigationInstruction.Open<*>, direction: T, navigationKey: NavigationKey.WithResult<*>, - ) : NavigationInstruction.Open { + ): NavigationInstruction.Open { return NavigationInstruction.Open.OpenInternal( navigationDirection = direction, navigationKey = navigationKey, @@ -46,6 +46,7 @@ public object AdvancedResultExtensions { EnroResult.from(navigationController).addPendingResult( PendingResult.Result( resultChannelId = resultId, + instruction = instruction, navigationKey = keyForResult, resultType = result::class, result = result @@ -68,6 +69,7 @@ public object AdvancedResultExtensions { EnroResult.from(navigationController).addPendingResult( PendingResult.Closed( resultChannelId = resultId, + instruction = instruction, navigationKey = keyForResult, ) ) diff --git a/enro-core/src/main/java/dev/enro/core/result/NavigationResultExtensions.kt b/enro-core/src/main/java/dev/enro/core/result/NavigationResultExtensions.kt index f3ba59c6..1cf8385c 100644 --- a/enro-core/src/main/java/dev/enro/core/result/NavigationResultExtensions.kt +++ b/enro-core/src/main/java/dev/enro/core/result/NavigationResultExtensions.kt @@ -20,7 +20,7 @@ import dev.enro.core.closeWithResult as nonDeprecatedCloseWithResult message = "Please use closeWithResult from dev.enro.core", level = DeprecationLevel.WARNING, replaceWith = - ReplaceWith("closeWithResult(result)", "dev.enro.core.closeWithResult"), + ReplaceWith("closeWithResult(result)", "dev.enro.core.closeWithResult"), ) public fun TypedNavigationHandle>.closeWithResult(result: T) { nonDeprecatedCloseWithResult(result) @@ -53,8 +53,8 @@ public fun TypedNavigationHandle>.deli @Deprecated("It is no longer required to provide a navigationHandle") public inline fun ViewModel.registerForNavigationResult( navigationHandle: NavigationHandle, - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope>.() -> Unit = {}, + noinline onResult: NavigationResultScope>.(T) -> Unit ): ReadOnlyProperty>> = LazyResultChannelProperty( owner = navigationHandle, @@ -64,8 +64,8 @@ public inline fun ViewModel.registerForNavigationResult( ) public inline fun ViewModel.registerForNavigationResult( - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope>.() -> Unit = {}, + noinline onResult: NavigationResultScope>.(T) -> Unit ): ReadOnlyProperty>> = LazyResultChannelProperty( owner = getNavigationHandle(), @@ -74,9 +74,10 @@ public inline fun ViewModel.registerForNavigationResult( onResult = onResult, ) +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun ViewModel.registerForNavigationResultWithKey( - noinline onClosed: (NavigationKey.WithResult) -> Unit = {}, - noinline onResult: (NavigationKey.WithResult, T) -> Unit + noinline onClosed: NavigationResultScope>.(NavigationKey.WithResult) -> Unit = {}, + noinline onResult: NavigationResultScope>.(NavigationKey.WithResult, T) -> Unit ): ReadOnlyProperty>> = LazyResultChannelProperty( owner = getNavigationHandle(), @@ -87,8 +88,8 @@ public inline fun ViewModel.registerForNavigationResultWithKey public inline fun > ViewModel.registerForNavigationResult( key: KClass, - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope.() -> Unit = {}, + noinline onResult: NavigationResultScope.(T) -> Unit ): ReadOnlyProperty> = LazyResultChannelProperty( owner = getNavigationHandle(), @@ -97,10 +98,11 @@ public inline fun > ViewModel onResult = onResult ) +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun > ViewModel.registerForNavigationResultWithKey( key: KClass, - noinline onClosed: (Key) -> Unit = {}, - noinline onResult: (Key, T) -> Unit + noinline onClosed: NavigationResultScope.(Key) -> Unit = {}, + noinline onResult: NavigationResultScope.(Key, T) -> Unit ): ReadOnlyProperty> = LazyResultChannelProperty( owner = getNavigationHandle(), @@ -110,8 +112,8 @@ public inline fun > ViewModel ) public inline fun ComponentActivity.registerForNavigationResult( - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope>.() -> Unit = {}, + noinline onResult: NavigationResultScope>.(T) -> Unit ): ReadOnlyProperty>> = LazyResultChannelProperty( owner = this, @@ -120,9 +122,10 @@ public inline fun ComponentActivity.registerForNavigationResul onResult = onResult ) +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun ComponentActivity.registerForNavigationResultWithKey( - noinline onClosed: (NavigationKey.WithResult) -> Unit = {}, - noinline onResult: (NavigationKey.WithResult, T) -> Unit + noinline onClosed: NavigationResultScope>.(NavigationKey.WithResult) -> Unit = {}, + noinline onResult: NavigationResultScope>.(NavigationKey.WithResult, T) -> Unit ): ReadOnlyProperty>> = LazyResultChannelProperty( owner = this, @@ -131,10 +134,11 @@ public inline fun ComponentActivity.registerForNavigationResul onResult = onResult ) + public inline fun > ComponentActivity.registerForNavigationResult( key: KClass, - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope.() -> Unit = {}, + noinline onResult: NavigationResultScope.(T) -> Unit ): ReadOnlyProperty> = LazyResultChannelProperty( owner = this, @@ -143,10 +147,11 @@ public inline fun > Component onResult = onResult ) +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun > ComponentActivity.registerForNavigationResultWithKey( key: KClass, - noinline onClosed: (Key) -> Unit = {}, - noinline onResult: (Key, T) -> Unit + noinline onClosed: NavigationResultScope.(Key) -> Unit = {}, + noinline onResult: NavigationResultScope.(Key, T) -> Unit ): ReadOnlyProperty> = LazyResultChannelProperty( owner = this, @@ -156,8 +161,8 @@ public inline fun > Component ) public inline fun Fragment.registerForNavigationResult( - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope>.() -> Unit = {}, + noinline onResult: NavigationResultScope>.(T) -> Unit ): ReadOnlyProperty>> = LazyResultChannelProperty( owner = this, @@ -166,9 +171,10 @@ public inline fun Fragment.registerForNavigationResult( onResult = onResult ) +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun Fragment.registerForNavigationResultWithKey( - noinline onClosed: (NavigationKey.WithResult) -> Unit = {}, - noinline onResult: (NavigationKey.WithResult, T) -> Unit + noinline onClosed: NavigationResultScope>.(NavigationKey.WithResult) -> Unit = {}, + noinline onResult: NavigationResultScope>.(NavigationKey.WithResult, T) -> Unit ): ReadOnlyProperty>> = LazyResultChannelProperty( owner = this, @@ -179,8 +185,8 @@ public inline fun Fragment.registerForNavigationResultWithKey( public inline fun > Fragment.registerForNavigationResult( key: KClass, - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope.() -> Unit = {}, + noinline onResult: NavigationResultScope.(T) -> Unit ): ReadOnlyProperty> = LazyResultChannelProperty( owner = this, @@ -189,10 +195,11 @@ public inline fun > Fragment. onResult = onResult ) +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun > Fragment.registerForNavigationResultWithKey( key: KClass, - noinline onClosed: (Key) -> Unit = {}, - noinline onResult: (Key, T) -> Unit + noinline onClosed: NavigationResultScope.(Key) -> Unit = {}, + noinline onResult: NavigationResultScope.(Key, T) -> Unit ): ReadOnlyProperty> = LazyResultChannelProperty( owner = this, @@ -213,8 +220,8 @@ public inline fun > Fragment. */ public inline fun NavigationHandle.registerForNavigationResult( id: String, - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope>.() -> Unit = {}, + noinline onResult: NavigationResultScope>.(T) -> Unit ): UnmanagedNavigationResultChannel> { return createResultChannel( resultType = T::class, @@ -234,10 +241,11 @@ public inline fun NavigationHandle.registerForNavigationResult * @see managedByLifecycle * @see managedByView */ +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun NavigationHandle.registerForNavigationResultWithKey( id: String, - noinline onClosed: (NavigationKey.WithResult) -> Unit = {}, - noinline onResult: (NavigationKey.WithResult, T) -> Unit + noinline onClosed: NavigationResultScope>.(NavigationKey.WithResult) -> Unit = {}, + noinline onResult: NavigationResultScope>.(NavigationKey.WithResult, T) -> Unit ): UnmanagedNavigationResultChannel> { return createResultChannel( resultType = T::class, @@ -260,8 +268,8 @@ public inline fun NavigationHandle.registerForNavigationResult public inline fun > NavigationHandle.registerForNavigationResult( id: String, key: KClass, - noinline onClosed: () -> Unit = {}, - noinline onResult: (T) -> Unit + noinline onClosed: NavigationResultScope.() -> Unit = {}, + noinline onResult: NavigationResultScope.(T) -> Unit ): UnmanagedNavigationResultChannel { return createResultChannel( resultType = T::class, @@ -281,11 +289,12 @@ public inline fun > Navigatio * @see managedByLifecycle * @see managedByView */ +@Deprecated("Please use registerForNavigationResult, as the key is provided through the NavigationResultScope") public inline fun > NavigationHandle.registerForNavigationResultWithKey( id: String, key: KClass, - noinline onClosed: (Key) -> Unit = {}, - noinline onResult: (Key, T) -> Unit + noinline onClosed: NavigationResultScope.(Key) -> Unit = {}, + noinline onResult: NavigationResultScope.(Key, T) -> Unit ): UnmanagedNavigationResultChannel { return createResultChannel( resultType = T::class, @@ -301,7 +310,7 @@ public inline fun > Navigatio * The result channel will be attached when the ON_START event occurs, detached when the ON_STOP * event occurs, and destroyed when ON_DESTROY occurs. */ -public fun > UnmanagedNavigationResultChannel.managedByLifecycle( +public fun > UnmanagedNavigationResultChannel.managedByLifecycle( lifecycle: Lifecycle ): NavigationResultChannel { lifecycle.addObserver(LifecycleEventObserver { _, event -> @@ -319,7 +328,7 @@ public fun > UnmanagedNavigationResultCh * detached when the view is detached from a Window, and destroyed when the ViewTreeLifecycleOwner * lifecycle receives the ON_DESTROY event. */ -public fun > UnmanagedNavigationResultChannel.managedByView(view: View): NavigationResultChannel { +public fun > UnmanagedNavigationResultChannel.managedByView(view: View): NavigationResultChannel { var activeLifecycle: Lifecycle? = null val lifecycleObserver = LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_DESTROY) destroy() @@ -333,7 +342,7 @@ public fun > UnmanagedNavigationResultCh } } - view.addOnAttachStateChangeListener(object: View.OnAttachStateChangeListener { + view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { activeLifecycle?.removeObserver(lifecycleObserver) @@ -364,7 +373,7 @@ public fun > UnmanagedNavigationResultCh * destroyed every time the ViewHolder is re-bound to data through onBindViewHolder, which means the * result channel should be created each time the ViewHolder is bound. */ -public fun > UnmanagedNavigationResultChannel.managedByViewHolderItem( +public fun > UnmanagedNavigationResultChannel.managedByViewHolderItem( viewHolder: RecyclerView.ViewHolder ): NavigationResultChannel { if (viewHolder.itemView.isAttachedToWindow) { diff --git a/enro-core/src/main/java/dev/enro/core/result/NavigationResultScope.kt b/enro-core/src/main/java/dev/enro/core/result/NavigationResultScope.kt new file mode 100644 index 00000000..82cb3888 --- /dev/null +++ b/enro-core/src/main/java/dev/enro/core/result/NavigationResultScope.kt @@ -0,0 +1,9 @@ +package dev.enro.core.result + +import dev.enro.core.AnyOpenInstruction +import dev.enro.core.NavigationKey + +public class NavigationResultScope> internal constructor( + public val instruction: AnyOpenInstruction, + public val key: Key, +) \ No newline at end of file diff --git a/enro-core/src/main/java/dev/enro/core/result/flows/FlowResultChannel.kt b/enro-core/src/main/java/dev/enro/core/result/flows/FlowResultChannel.kt index 73198590..90a67dc0 100644 --- a/enro-core/src/main/java/dev/enro/core/result/flows/FlowResultChannel.kt +++ b/enro-core/src/main/java/dev/enro/core/result/flows/FlowResultChannel.kt @@ -12,8 +12,9 @@ import dev.enro.core.container.toBackstack import dev.enro.core.controller.usecase.extras import dev.enro.core.onActiveContainer import dev.enro.core.result.NavigationResultChannel +import dev.enro.core.result.NavigationResultScope import dev.enro.core.result.internal.ResultChannelImpl -import dev.enro.core.result.registerForNavigationResultWithKey +import dev.enro.core.result.registerForNavigationResult import dev.enro.extensions.getParcelableListCompat import dev.enro.viewmodel.getNavigationHandle import kotlin.properties.PropertyDelegateProvider @@ -21,8 +22,8 @@ import kotlin.properties.ReadOnlyProperty internal fun interface CreateResultChannel { operator fun invoke( - onClosed: (Any) -> Unit, - onResult: (NavigationKey.WithResult<*>, Any) -> Unit + onClosed: NavigationResultScope<*, *>.() -> Unit, + onResult: NavigationResultScope<*, *>.(Any) -> Unit ): NavigationResultChannel> } @@ -42,7 +43,7 @@ public class NavigationFlow internal constructor( @Suppress("UNCHECKED_CAST") private val resultChannel = registerForNavigationResult( - onClosed = { key -> + onClosed = { val step = key as? FlowStep ?: return@registerForNavigationResult resultManager.clear(step) steps = steps @@ -50,7 +51,7 @@ public class NavigationFlow internal constructor( .dropLast(1) .dropLastWhile { it.isTransient } }, - onResult = { key, result -> + onResult = { result -> val step = key as? FlowStep ?: return@registerForNavigationResult resultManager.set(step, result) update() @@ -200,7 +201,7 @@ public fun ViewModel.registerForFlowResult( navigation = navigationHandle, resultManager = resultManager, registerForNavigationResult = { onClosed, onResult -> - registerForNavigationResultWithKey( + registerForNavigationResult( onClosed = onClosed, onResult = onResult, ).getValue(thisRef, property) diff --git a/enro-core/src/main/java/dev/enro/core/result/internal/LazyResultChannelProperty.kt b/enro-core/src/main/java/dev/enro/core/result/internal/LazyResultChannelProperty.kt index 4f11df17..dc1dabe8 100644 --- a/enro-core/src/main/java/dev/enro/core/result/internal/LazyResultChannelProperty.kt +++ b/enro-core/src/main/java/dev/enro/core/result/internal/LazyResultChannelProperty.kt @@ -11,13 +11,14 @@ import dev.enro.core.NavigationKey import dev.enro.core.controller.usecase.createResultChannel import dev.enro.core.getNavigationHandle import dev.enro.core.result.NavigationResultChannel +import dev.enro.core.result.NavigationResultScope import dev.enro.core.result.managedByLifecycle import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KClass import kotlin.reflect.KProperty @PublishedApi -internal class LazyResultChannelProperty> private constructor ( +internal class LazyResultChannelProperty> private constructor( owner: Any, resultType: KClass, params: LambdaParams @@ -26,8 +27,8 @@ internal class LazyResultChannelProperty, - onClosed: (Key) -> Unit = {}, - onResult: (Key, Result) -> Unit + onClosed: NavigationResultScope.(Key) -> Unit = {}, + onResult: NavigationResultScope.(Key, Result) -> Unit ) : this( owner = owner, resultType = resultType, @@ -40,8 +41,8 @@ internal class LazyResultChannelProperty, - onClosed: () -> Unit = {}, - onResult: (Result) -> Unit + onClosed: NavigationResultScope.() -> Unit = {}, + onResult: NavigationResultScope.(Result) -> Unit ) : this( owner = owner, resultType = resultType, @@ -66,12 +67,13 @@ internal class LazyResultChannelProperty handle.value.createResultChannel( resultType = resultType, onClosed = params.onClosed, onResult = params.onResult, ) + is LambdaParams.WithoutKey -> handle.value.createResultChannel( resultType = resultType, onClosed = params.onClosed, @@ -91,15 +93,15 @@ internal class LazyResultChannelProperty> { - class WithKey>( - val onClosed: (Key) -> Unit, - val onResult: (Key, Result) -> Unit, + private sealed class LambdaParams> { + class WithKey>( + val onClosed: NavigationResultScope.(Key) -> Unit, + val onResult: NavigationResultScope.(Key, Result) -> Unit, ) : LambdaParams() - class WithoutKey>( - val onClosed: () -> Unit, - val onResult: (Result) -> Unit, - ): LambdaParams() + class WithoutKey>( + val onClosed: NavigationResultScope.() -> Unit, + val onResult: NavigationResultScope.(Result) -> Unit, + ) : LambdaParams() } } diff --git a/enro-core/src/main/java/dev/enro/core/result/internal/PendingResult.kt b/enro-core/src/main/java/dev/enro/core/result/internal/PendingResult.kt index ebf6c922..c2143e5b 100644 --- a/enro-core/src/main/java/dev/enro/core/result/internal/PendingResult.kt +++ b/enro-core/src/main/java/dev/enro/core/result/internal/PendingResult.kt @@ -1,19 +1,23 @@ package dev.enro.core.result.internal +import dev.enro.core.AnyOpenInstruction import dev.enro.core.NavigationKey import kotlin.reflect.KClass internal sealed class PendingResult { abstract val resultChannelId: ResultChannelId + abstract val instruction: AnyOpenInstruction abstract val navigationKey: NavigationKey.WithResult<*> class Closed( override val resultChannelId: ResultChannelId, + override val instruction: AnyOpenInstruction, override val navigationKey: NavigationKey.WithResult<*>, - ): PendingResult() + ) : PendingResult() data class Result( override val resultChannelId: ResultChannelId, + override val instruction: AnyOpenInstruction, override val navigationKey: NavigationKey.WithResult<*>, val resultType: KClass, val result: Any diff --git a/enro-core/src/main/java/dev/enro/core/result/internal/ResultChannelImpl.kt b/enro-core/src/main/java/dev/enro/core/result/internal/ResultChannelImpl.kt index f3e91e67..cf8046d8 100644 --- a/enro-core/src/main/java/dev/enro/core/result/internal/ResultChannelImpl.kt +++ b/enro-core/src/main/java/dev/enro/core/result/internal/ResultChannelImpl.kt @@ -8,23 +8,24 @@ import dev.enro.core.NavigationHandle import dev.enro.core.NavigationInstruction import dev.enro.core.NavigationKey import dev.enro.core.result.EnroResult +import dev.enro.core.result.NavigationResultScope import dev.enro.core.result.UnmanagedNavigationResultChannel import dev.enro.core.runWhenHandleActive private class ResultChannelProperties>( val navigationHandle: NavigationHandle, val resultType: Class, - val onClosed: (Key) -> Unit, - val onResult: (Key, Result) -> Unit, + val onClosed: NavigationResultScope.() -> Unit, + val onResult: NavigationResultScope.(Result) -> Unit, ) @PublishedApi -internal class ResultChannelImpl>( +internal class ResultChannelImpl>( private val enroResult: EnroResult, navigationHandle: NavigationHandle, resultType: Class, - onClosed: @DisallowComposableCalls (Key) -> Unit, - onResult: @DisallowComposableCalls (Key, Result) -> Unit, + onClosed: @DisallowComposableCalls NavigationResultScope.() -> Unit, + onResult: @DisallowComposableCalls NavigationResultScope.(Result) -> Unit, resultId: String, additionalResultId: String = "", ) : UnmanagedNavigationResultChannel { @@ -53,7 +54,7 @@ internal class ResultChannelImpl - if(event == Lifecycle.Event.ON_DESTROY) { + if (event == Lifecycle.Event.ON_DESTROY) { destroy() } }.apply { navigationHandle.lifecycle.addObserver(this) } @@ -88,14 +89,15 @@ internal class ResultChannelImpl { val key = pendingResult.navigationKey key as Key properties.navigationHandle.runWhenHandleActive { - properties.onClosed(key) + properties.onClosed(NavigationResultScope(pendingResult.instruction, key)) } } + is PendingResult.Result -> { val result = pendingResult.result val key = pendingResult.navigationKey @@ -104,7 +106,7 @@ internal class ResultChannelImpl registerForNavigationResult( id: String = rememberSaveable { UUID.randomUUID().toString() }, - noinline onClosed: @DisallowComposableCalls () -> Unit = {}, - noinline onResult: @DisallowComposableCalls (T) -> Unit + noinline onClosed: @DisallowComposableCalls NavigationResultScope>.() -> Unit = {}, + noinline onResult: @DisallowComposableCalls NavigationResultScope>.(T) -> Unit ): NavigationResultChannel> { val navigationHandle = navigationHandle() diff --git a/enro-test/src/main/java/dev/enro/test/extensions/ResultExtensions.kt b/enro-test/src/main/java/dev/enro/test/extensions/ResultExtensions.kt index fb7f1239..6194d5d0 100644 --- a/enro-test/src/main/java/dev/enro/test/extensions/ResultExtensions.kt +++ b/enro-test/src/main/java/dev/enro/test/extensions/ResultExtensions.kt @@ -1,4 +1,5 @@ @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") + package dev.enro.test.extensions import dev.enro.core.NavigationInstruction @@ -7,23 +8,24 @@ import dev.enro.core.result.EnroResult import dev.enro.core.result.internal.PendingResult import dev.enro.test.EnroTest -fun NavigationInstruction.Open<*>.sendResultForTest(type: Class, result: T) { +fun NavigationInstruction.Open<*>.sendResultForTest(type: Class, result: T) { val navigationController = EnroTest.getCurrentNavigationController() val resultId = internal.resultId!! val navigationKey = internal.resultKey ?: navigationKey val pendingResult = PendingResult.Result( - resultId, - navigationKey as NavigationKey.WithResult, - type.kotlin, - result + resultChannelId = resultId, + instruction = this, + navigationKey = navigationKey as NavigationKey.WithResult, + resultType = type.kotlin, + result = result ) EnroResult .from(navigationController) .addPendingResult(pendingResult) } -inline fun NavigationInstruction.Open<*>.sendResultForTest(result: T) { +inline fun NavigationInstruction.Open<*>.sendResultForTest(result: T) { sendResultForTest(T::class.java, result) }