Skip to content

Commit

Permalink
Added NavigationResultScope<Result, Key> as a receiver for all regi…
Browse files Browse the repository at this point in the history
…sterForNavigationResult 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.
  • Loading branch information
isaac-udy committed May 21, 2024
1 parent 55be4e4 commit 156f6a5
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 95 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<Result, Key>` 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 <Result : Any, Key : NavigationKey.WithResult<Result>> invoke(
resultType: KClass<Result>,
crossinline onClosed: () -> Unit,
noinline onResult: (Result) -> Unit,
crossinline onClosed: NavigationResultScope<Result, Key>.(Key) -> Unit,
noinline onResult: NavigationResultScope<Result, Key>.(Key, Result) -> Unit,
additionalResultId: String = "",
): UnmanagedNavigationResultChannel<Result, Key> {
val internalOnClosed: (Key) -> Unit = { _ -> onClosed() }
val internalOnResult: (Key, Result) -> Unit = { _, result -> onResult(result) }
val internalOnClosed: NavigationResultScope<Result, Key>.() -> Unit = { onClosed(key) }
val internalOnResult: NavigationResultScope<Result, Key>.(Result) -> Unit = { result -> onResult(key, result) }
val resultId = onResult.createResultId() + "@" + internalOnResult.createResultId().hashCode()
return create(
resultType = resultType,
Expand All @@ -79,12 +78,12 @@ internal class CreateResultChannel(
// the code
inline operator fun <Result : Any, Key : NavigationKey.WithResult<Result>> invoke(
resultType: KClass<Result>,
crossinline onClosed: (Key) -> Unit,
noinline onResult: (Key, Result) -> Unit,
crossinline onClosed: NavigationResultScope<Result, Key>.() -> Unit,
noinline onResult: NavigationResultScope<Result, Key>.(Result) -> Unit,
additionalResultId: String = "",
): UnmanagedNavigationResultChannel<Result, Key> {
val internalOnClosed: (Key) -> Unit = { key -> onClosed(key) }
val internalOnResult: (Key, Result) -> Unit = { key, result -> onResult(key, result) }
val internalOnClosed: NavigationResultScope<Result, Key>.() -> Unit = { onClosed(this) }
val internalOnResult: NavigationResultScope<Result, Key>.(Result) -> Unit = { result -> onResult(this, result) }
val resultId = onResult.createResultId() + "@" + internalOnResult.createResultId().hashCode()
return create(
resultType = resultType,
Expand All @@ -99,8 +98,8 @@ internal class CreateResultChannel(
internal fun <Result : Any, Key : NavigationKey.WithResult<Result>> create(
resultType: KClass<Result>,
resultId: String,
onClosed: (Key) -> Unit,
onResult: (Key, Result) -> Unit,
onClosed: NavigationResultScope<Result, Key>.() -> Unit,
onResult: NavigationResultScope<Result, Key>.(Result) -> Unit,
additionalResultId: String = "",
): UnmanagedNavigationResultChannel<Result, Key> {
return ResultChannelImpl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ 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
}

public fun <T : NavigationDirection> getInstructionToForwardResult(
originalInstruction: NavigationInstruction.Open<*>,
direction: T,
navigationKey: NavigationKey.WithResult<*>,
) : NavigationInstruction.Open<T> {
): NavigationInstruction.Open<T> {
return NavigationInstruction.Open.OpenInternal(
navigationDirection = direction,
navigationKey = navigationKey,
Expand Down Expand Up @@ -46,6 +46,7 @@ public object AdvancedResultExtensions {
EnroResult.from(navigationController).addPendingResult(
PendingResult.Result(
resultChannelId = resultId,
instruction = instruction,
navigationKey = keyForResult,
resultType = result::class,
result = result
Expand All @@ -68,6 +69,7 @@ public object AdvancedResultExtensions {
EnroResult.from(navigationController).addPendingResult(
PendingResult.Closed(
resultChannelId = resultId,
instruction = instruction,
navigationKey = keyForResult,
)
)
Expand Down
Loading

0 comments on commit 156f6a5

Please sign in to comment.