diff --git a/Workflow/Workflow.swift b/Workflow/Workflow.swift index 06e09a9e1..ebb289171 100644 --- a/Workflow/Workflow.swift +++ b/Workflow/Workflow.swift @@ -123,8 +123,8 @@ public class Workflow: LinkedList { flowRepresentable.workflow = self let shouldLoad = flowRepresentable.erasedShouldLoad(with: args) defer { + let position = node.position if (shouldLoad) { - let position = node.position instances.replace(atIndex: position, withItem: flowRepresentable) firstLoadedInstance = instances.first?.traverse(position) if let firstLoadedInstance = firstLoadedInstance { @@ -133,13 +133,14 @@ public class Workflow: LinkedList { onFinish: onFinish) } } else if (!shouldLoad && metadata.staysInViewStack(args) == .hiddenInitially) { - rootView = flowRepresentable - self.presenter?.launch(view: flowRepresentable, - from: from, - withLaunchStyle: metadata.presentationType, metadata: metadata, - animated: false, - completion: nil) - + var reference:((Any?) -> Void)? + self.handleCallbackWhenHiddenInitially(viewToPresent: &rootView, + hold: &reference, + instance: flowRepresentable, + instancePosition: position, + from: from, + metadata: metadata, + onFinish: onFinish) } } @@ -188,7 +189,7 @@ public class Workflow: LinkedList { instance.proceedInWorkflow = $0.value?.proceedInWorkflow instance.workflow = self - let hold = instance.proceedInWorkflow + var hold = instance.proceedInWorkflow defer { instance.proceedInWorkflow = hold self.replaceInstance(atIndex: index, withInstance: instance) @@ -198,11 +199,13 @@ public class Workflow: LinkedList { let shouldLoad = instance.erasedShouldLoad(with: argsToPass) == true if (!shouldLoad && metadata.staysInViewStack(argsToPass) == .hiddenInitially) { - viewToPresent = instance - self.presenter?.launch(view: instance, - from: self.instances.first?.traverse(node.position)?.value, - withLaunchStyle: metadata.presentationType, metadata: metadata, animated: false, completion: nil) - + self.handleCallbackWhenHiddenInitially(viewToPresent: &viewToPresent, + hold: &hold, + instance: instance, + instancePosition: index, + from: self.instances.first?.traverse(node.position)?.value, + metadata: metadata, + onFinish: onFinish) } return shouldLoad @@ -230,6 +233,19 @@ public class Workflow: LinkedList { } } } + + private func handleCallbackWhenHiddenInitially(viewToPresent:inout Any?, hold:inout ((Any?) -> Void)?, instance:AnyFlowRepresentable, instancePosition:Int, from:Any?, metadata: FlowRepresentableMetaData, onFinish:((Any?) -> Void)?) { + viewToPresent = instance + self.replaceInstance(atIndex: instancePosition, withInstance: instance) + if let instanceNode = self.instances.first?.traverse(instancePosition) { + self.setupCallbacks(for: instanceNode, onFinish: onFinish) + hold = instanceNode.value?.proceedInWorkflow + } + self.presenter?.launch(view: instance, + from: from, + withLaunchStyle: metadata.presentationType, metadata: metadata, animated: false, completion: nil) + + } } public class FlowRepresentableMetaData { diff --git a/WorkflowTests/UIKitPresenter/UIKitPresenterTests.swift b/WorkflowTests/UIKitPresenter/UIKitPresenterTests.swift index 868c7fd64..40b536788 100644 --- a/WorkflowTests/UIKitPresenter/UIKitPresenterTests.swift +++ b/WorkflowTests/UIKitPresenter/UIKitPresenterTests.swift @@ -574,6 +574,34 @@ class UIKitPresenterTests: XCTestCase { XCTAssert(UIApplication.topViewController() is FR2) } + func testNavWorkflowWhichSkipsAScreen_ButKeepsItInTheViewStack_BacksUp_ThenGoesForwardAgain() { + class FR1: TestViewController { } + class FR2: UIWorkflowItem, FlowRepresentable { + static func instance() -> AnyFlowRepresentable { FR2() } + func shouldLoad() -> Bool { false } + } + class FR3: TestViewController { } + + let nav = UINavigationController() + loadView(controller: nav) + + nav.launchInto(Workflow() + .thenPresent(FR1.self) + .thenPresent(FR2.self, staysInViewStack: .hiddenInitially) + .thenPresent(FR3.self), withLaunchStyle: .navigationStack) + waitUntil(UIApplication.topViewController() is FR1) + XCTAssert(UIApplication.topViewController() is FR1) + (UIApplication.topViewController() as? FR1)?.proceedInWorkflow() + waitUntil(UIApplication.topViewController() is FR3) + XCTAssert(UIApplication.topViewController() is FR3) + (UIApplication.topViewController()?.navigationController)?.popViewController(animated: false) + waitUntil(UIApplication.topViewController() is FR2) + XCTAssert(UIApplication.topViewController() is FR2) + (UIApplication.topViewController() as? FR2)?.proceedInWorkflow() + waitUntil(UIApplication.topViewController() is FR3) + XCTAssert(UIApplication.topViewController() is FR3) + } + func testNavWorkflowWhichSkipsFirstScreen_ButKeepsItInTheViewStack() { class FR1: TestViewController { override func shouldLoad(with args: Any?) -> Bool { @@ -600,6 +628,35 @@ class UIKitPresenterTests: XCTestCase { XCTAssert(UIApplication.topViewController() is FR1) } + func testNavWorkflowWhichSkipsFirstScreen_ButKeepsItInTheViewStack_BacksUp_ThenGoesForwardAgain() { + class FR1: TestViewController { + override func shouldLoad(with args: Any?) -> Bool { + _ = super.shouldLoad(with: args) + return false + } + } + class FR2: UIWorkflowItem, FlowRepresentable { + static func instance() -> AnyFlowRepresentable { FR2() } + } + class FR3: TestViewController { } + + let nav = UINavigationController() + loadView(controller: nav) + + nav.launchInto(Workflow() + .thenPresent(FR1.self, staysInViewStack: .hiddenInitially) + .thenPresent(FR2.self) + .thenPresent(FR3.self), withLaunchStyle: .navigationStack) + waitUntil(UIApplication.topViewController() is FR2) + XCTAssert(UIApplication.topViewController() is FR2) + (UIApplication.topViewController()?.navigationController)?.popViewController(animated: false) + waitUntil(UIApplication.topViewController() is FR1) + XCTAssert(UIApplication.topViewController() is FR1) + (UIApplication.topViewController() as? FR1)?.proceedInWorkflow() + waitUntil(UIApplication.topViewController() is FR2) + XCTAssert(UIApplication.topViewController() is FR2) + } + func testNavWorkflowWhichDoesNotSkipAScreen_ButRemovesItFromTheViewStack() { class FR1: TestViewController { } class FR2: UIWorkflowItem, FlowRepresentable {