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

Add hierarchial api for child flow controllers in FlowController #12

Open
wants to merge 1 commit into
base: stable
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions Demo/Modules/ImagePicker/ImagePickerFlowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ImagePickerFlowController: FlowController {
})

alertCtrl.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [unowned self] _ in
self.removeFromSuperFlowController()
self.removeFromParent()
})

return alertCtrl
Expand All @@ -63,15 +63,15 @@ class ImagePickerFlowController: FlowController {
extension ImagePickerFlowController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true) {
self.removeFromSuperFlowController()
self.removeFromParent()
}
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let pickedImage = info[.originalImage] as? UIImage {
resultCompletion.reportResult(result: pickedImage)
picker.dismiss(animated: true) {
self.removeFromSuperFlowController()
self.removeFromParent()
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions Demo/Modules/Main/MainFlowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class MainFlowController: InitialFlowController {
extension MainFlowController: MainFlowDelegate {
func tutorialStartButtonPressed() {
let tutorialFlowCtrl = TutorialFlowController()
add(subFlowController: tutorialFlowCtrl)
addChild(tutorialFlowCtrl)
tutorialFlowCtrl.start(from: mainViewController!)
}

Expand All @@ -33,7 +33,7 @@ extension MainFlowController: MainFlowDelegate {
}

let imagePickerFlowCtrl = ImagePickerFlowController(resultCompletion: resultCompletion)
add(subFlowController: imagePickerFlowCtrl)
addChild(imagePickerFlowCtrl)
imagePickerFlowCtrl.start(from: mainViewController!)
}
}
2 changes: 1 addition & 1 deletion Demo/Modules/Tutorial/TutorialFlowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ extension TutorialFlowController: Page2FlowDelegate {
extension TutorialFlowController: Page3FlowDelegate {
func completeButtonPressed() {
navigationCtrl?.dismiss(animated: true) {
self.removeFromSuperFlowController()
self.removeFromParent()
}
}
}
79 changes: 67 additions & 12 deletions Frameworks/Imperio/FlowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,88 @@ import UIKit

/// A class to be subclassed by flow controllers.
open class FlowController: NSObject {
var subFlowController: FlowController?
weak var superFlowController: FlowController?
private var subFlowController: FlowController?

private(set) weak var parent: FlowController?
private(set) var children: [FlowController] = []

/// Starts the flow from a given view controller.
///
/// - Parameters:
/// - presentingViewController: The view controller to start the flow from.
open func start(from presentingViewController: UIViewController) { /* for overriding purposes only */ }

/// Override this to perform logic before the flow controller will change its parent.
open func willMove(toParent: FlowController?) { /* for overriding purposes only */ }

/// Override this to perform logic after the flow controller did change its parent.
open func didMove(toParent: FlowController?) { /* for overriding purposes only */ }

/// Adds a flow controller to the children of this flow controller
///
/// - Parameters:
/// - child: The flow controller to be added as child.
public func addChild(_ child: FlowController) {
precondition(child.parent == nil)

child.willMove(toParent: self)
child.parent = self
children.append(child)
child.didMove(toParent: self)
}

/// Moves the flow controller from its current parent to the new parent.
///
/// - Parameters:
/// - toParent: The parent the flow controller will be moved to.
public func move(toParent: FlowController) {
removeFromParent()
toParent.addChild(self)
}

/// Removes the flow controller from its parent.
public func removeFromParent() {
parent?.removeChildren(in: [self])
}

/// Remove all child flow controllers.
public func removeAllChildren() {
removeChildren(in: children)
}

/// Removes all child flow controllers in `childrenToRemove`.
///
/// - Parameters:
/// - childrenToRemove: The children which will be removed from the flow controller.
public func removeChildren(in childrenToRemove: [FlowController]) {
childrenToRemove.forEach(removeChild(_:))
}

/// Removes the given `child` from the flow controller.
///
/// - Parameters:
/// - child: The child which will be removed from the flow controller.
public func removeChild(_ child: FlowController) {
precondition(child.parent == self)

child.willMove(toParent: nil)
child.parent = nil
children.removeAll { $0 === child }
child.didMove(toParent: nil)
}

/// Adds a sub flow controller to the existing one.
///
/// - Parameters:
/// - subFlowController: The sub flow controller to be added.
@available(*, deprecated, message: "`add(subFlowController:)` is deprecated use `addChild(_:)` instead!")
public func add(subFlowController: FlowController) {
// Clean up
self.subFlowController?.removeFromSuperFlowController()
subFlowController.removeFromSuperFlowController()

// Store new
self.subFlowController = subFlowController
subFlowController.superFlowController = self
addChild(subFlowController)
}

/// Removes this flow controller from its super flow controller.
@available(*, deprecated, message: "`removeFromSuperFlowController` is deprecated use `removeFromParent` instead!")
public func removeFromSuperFlowController() {
subFlowController?.removeFromSuperFlowController()
superFlowController?.subFlowController = nil
superFlowController = nil
removeFromParent()
}
}
5 changes: 5 additions & 0 deletions Frameworks/Imperio/InitialFlowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ open class InitialFlowController: FlowController {
/// - Paramters:
/// - window: The window to present the flow from.
open func start(from window: UIWindow) { /* needs to be overridden */ }

@available(*, unavailable, message: "InitialFlowController can only be started from a UIWindow!")
override open func start(from presentingViewController: UIViewController) {
fatalError("InitialFlowController can only be started from a UIWindow!")
}
}
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class TutorialFlowController: FlowController {

### The `start(from:)` method

Each coordinator subclass needs to override at least the `start` method which opens the initial view controller of the screen flow. For example:
Each flow controller subclass needs to override at least the `start` method which opens the initial view controller of the screen flow. For example:

``` Swift
import Imperio
Expand Down Expand Up @@ -98,7 +98,7 @@ Now, whenever you might want to start your screen flow from within another flow
``` Swift
func tutorialStartButtonPressed() {
let tutorialFlowCtrl = TutorialFlowController()
add(subFlowController: tutorialFlowCtrl)
addChild(tutorialFlowCtrl)
tutorialFlowCtrl.start(from: someViewController!)
}
```
Expand All @@ -108,7 +108,7 @@ Please note that this works pretty much like adding a subview to a `UIView` with
``` Swift
func completeButtonPressed() {
navigationCtrl?.dismiss(animated: true) {
self.removeFromSuperFlowController()
self.removeFromParent()
}
}
```
Expand Down Expand Up @@ -289,7 +289,7 @@ func imagePickerStartButtonPressed() {
}

let imagePickerFlowCtrl = ImagePickerFlowController(resultCompletion: resultCompletion)
add(subFlowController: imagePickerFlowCtrl)
addChild(imagePickerFlowCtrl)
imagePickerFlowCtrl.start(from: mainViewController!)
}
```
Expand Down Expand Up @@ -417,7 +417,7 @@ class ImagePickerFlowController: FlowController {
})

alertCtrl.addAction(UIAlertAction(title: "Cancel", style: .cancel) { [unowned self] _ in
self.removeFromSuperFlowController()
self.removeFromParent()
})

return alertCtrl
Expand Down Expand Up @@ -451,15 +451,15 @@ class ImagePickerFlowController: FlowController {
extension ImagePickerFlowController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true) {
self.removeFromSuperFlowController()
self.removeFromParent()
}
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
resultCompletion.reportResult(result: pickedImage)
picker.dismiss(animated: true) {
self.removeFromSuperFlowController()
self.removeFromParent()
}
}
}
Expand Down