diff --git a/Sources/StoryFlow/Flow/Helpers/Transition.swift b/Sources/StoryFlow/Flow/Helpers/Transition.swift index 0be69e9..baed251 100644 --- a/Sources/StoryFlow/Flow/Helpers/Transition.swift +++ b/Sources/StoryFlow/Flow/Helpers/Transition.swift @@ -10,15 +10,31 @@ public struct Transition<To: UIViewController> { extension Transition { public static func custom(_: To.Type, transition: @escaping (UIViewController, To) -> ()) -> Transition { - return Transition(go: transition) + return Transition { from, to in + from.afterDismissingCompleted { + transition(from, to) + } + } } public static func show(_: To.Type) -> Transition { - return Transition { $0.show($1, sender: nil) } + return Transition { from, to in + if from.navigationController != nil { + from.show(to, sender: nil) + } else { + from.afterDismissingCompleted { + from.show(to, sender: nil) + } + } + } } public static func present(_: To.Type, animated: Bool = true) -> Transition { - return Transition { $0.present($1, animated: animated) } + return Transition { from, to in + from.afterDismissingCompleted { + from.present(to, animated: animated) + } + } } } @@ -30,6 +46,8 @@ extension Transition where To == UIViewController { let parentInTab = $1.parentInTabBarController let isWrongTab = parentInTab != $1.tabBarController?.selectedViewController let isPresenting = $1.presentedViewController != nil + && $1.presentedViewController?.isBeingPresented == false + && $1.presentedViewController?.isBeingDismissed == false // 1. Navigation pop if let nav = $1.navigationController { @@ -55,4 +73,12 @@ private extension UIViewController { var parentInTabBarController: UIViewController? { self.parent == self.tabBarController ? self : self.parent?.parentInTabBarController } + + func afterDismissingCompleted(_ transition: @escaping () -> ()) { + if presentedViewController?.isBeingDismissed == true { + dismiss(animated: true, completion: transition) + } else { + transition() + } + } } diff --git a/Sources/StoryFlow/Flow/ImplicitFlow/ImplicitFlow.swift b/Sources/StoryFlow/Flow/ImplicitFlow/ImplicitFlow.swift index 997aa16..a3059b0 100644 --- a/Sources/StoryFlow/Flow/ImplicitFlow/ImplicitFlow.swift +++ b/Sources/StoryFlow/Flow/ImplicitFlow/ImplicitFlow.swift @@ -53,7 +53,7 @@ extension Flow { if let to = Flow<Any>.destination(for: output) { let transition = TransitionInfo(from: from, producedType: output.type, receivedType: type, to: to, isUnwind: false) if CustomTransition.attempt(transition) == false { - from.show(to, sender: nil) + Transition.show(UIViewController.self).go(from, to) } return } diff --git a/StoryFlowTests/ImplicitFlowTests.swift b/StoryFlowTests/ImplicitFlowTests.swift index 19efabb..50887f2 100644 --- a/StoryFlowTests/ImplicitFlowTests.swift +++ b/StoryFlowTests/ImplicitFlowTests.swift @@ -163,6 +163,33 @@ class ImplicitFlowTests: XCTestCase { XCTAssert(currentVc is To) } + // MARK: Present + + func testProduce_whenDismissingPresented_itPresentsAfterDismiss() { + + // Arrange + class T {} + + class From: UIViewController, OutputProducing { typealias OutputType = T } + class To: UIViewController, InputRequiring { typealias InputType = T } + + let from = From().visible() + from.present(UIViewController(), animated: true, completion: nil) + XCTAssert(currentVc.didAppear()) + + from.dismiss(animated: true, completion: nil) + + let output = T() + + // Act + from.produce(output) + XCTAssert(currentVc.didDismiss()) + + // Assert + XCTAssert(currentVc is To) + + } + // MARK: Unwind func testProduce_itUnwindsToUpdateHandlingVcAndPassesOutput() { @@ -242,6 +269,7 @@ class ImplicitFlowTests: XCTestCase { let from = From() container.show(from, sender: nil) + XCTAssert(currentVc.didAppear()) let output = T() @@ -330,6 +358,68 @@ class ImplicitFlowTests: XCTestCase { XCTAssert(to.update === output) } + func testProduce_whenParentIsPresentingDuringUnwind_itUnwindsWihtoutInteruptingPresentation() { + + // Arrange + class T {} + + class From: UIViewController, OutputProducing { typealias OutputType = T } + class To: UIViewController, UpdateHandling { + func handle(update: T) { + self.update = update + self.present(UIViewController(), animated: true, completion: nil) + } + var update: T! + } + + let to = To().visible() + let from = From() + + to.addChild(from) + + let output = T() + + // Act + from.produce(output) + XCTAssert(currentVc.didAppear()) + + // Assert + XCTAssert(currentVc == to.presentedViewController!) + XCTAssert(to.update === output) + } + + func testProduce_whenPresentingDuringUnwind_itUnwindsWihtoutInteruptingPresentation() { + + // Arrange + class T {} + + class From: UIViewController, OutputProducing { typealias OutputType = T } + class To: UIViewController, UpdateHandling { + func handle(update: T) { + self.update = update + self.present(UIViewController(), animated: true, completion: nil) + } + var update: T! + } + + let to = To() + let from = From() + UINavigationController(rootViewController: to).visible() + + to.show(from, sender: nil) + XCTAssert(currentVc.didAppear()) + + let output = T() + + // Act + from.produce(output) + XCTAssert(currentVc.didAppear()) + + // Assert + XCTAssert(currentVc == to.presentedViewController!) + XCTAssert(to.update === output) + } + func testProduce_whenSelfCanHandleUpdate_itUnwindsToPreviousVc() { // Arrange @@ -443,6 +533,7 @@ class ImplicitFlowTests: XCTestCase { let from = From() currentVc.show(from, sender: nil) + XCTAssert(currentVc.didAppear()) // TabBar // - Navigation