Created
January 30, 2019 17:23
-
-
Save KaQuMiQ/6dc310aec563ac58f9e6d53aed4b66f5 to your computer and use it in GitHub Desktop.
ReduxExperiment.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
public final class ModuleController<State, Update, Message, Task> { | |
private var state: State | |
private var reducer: (inout State, Message) -> ([Update], [Task]) | |
private var worker: (ModuleController, Task) -> Void | |
private var presenter: (Update) -> Void | |
public init(state: State, | |
reducer: @escaping (inout State, Message) -> ([Update], [Task]), | |
worker: @escaping (ModuleController, Task) -> Void, | |
presenter: @escaping (Update) -> Void) { | |
self.state = state | |
self.reducer = reducer | |
self.worker = worker | |
self.presenter = presenter | |
} | |
public func handle(_ message: Message) { | |
let (updates, tasks) = reducer(&state, message) | |
updates.forEach(presenter) | |
tasks.forEach { worker(self, $0) } | |
} | |
} | |
public enum Dashboard { | |
public typealias Controller = ModuleController<State, Update, Message, Task> | |
public typealias Item = String | |
public struct State { | |
public var title: String | |
public var items: [Item] | |
} | |
public enum Message { | |
case load | |
case showDetail(Item) | |
case handleButton | |
case present(UIViewController) | |
} | |
public enum Update { | |
case title(String) | |
case items([Item]) | |
case present(UIViewController) | |
} | |
public enum Task { | |
case navigate | |
case storeItem(Item) | |
} | |
public final class ViewController: UIViewController { | |
var buttonTapAction: (()->Void)? = nil | |
func set(title: String) {} | |
func setListDataSource(_ dataSource: [String]) {} | |
public override func loadView() { | |
super.loadView() | |
view.backgroundColor = .white | |
let button = UIButton.init(frame: CGRect.init(x: 50, y: 50, width: 200, height: 80)) | |
button.setTitle("BUTTON", for: .normal) | |
button.setTitleColor(.blue, for: .normal) | |
button.addTarget(self, action: #selector(buttonTap), for: .touchUpInside) | |
view.addSubview(button) | |
} | |
@objc | |
func buttonTap() { | |
buttonTapAction?() | |
} | |
} | |
static func reducer(state: inout State, message: Message) -> ([Update], [Task]) { | |
switch message { | |
case .load: | |
return ([], []) | |
case let .showDetail(item): | |
state.items.append(item) | |
return ([.items(state.items)], []) | |
case .handleButton: | |
return ([], [.navigate]) | |
case let .present(vc): | |
return ([.present(vc)], []) | |
} | |
} | |
static func buildController(_ context: Void = (), state: State = State(title: "Title", items: [])) -> (UIViewController, Controller) { | |
let viewController: ViewController = .init() | |
let controller: Controller | |
= .init(state: state, | |
reducer: reducer, | |
worker: { (controller, task) in | |
switch task { | |
case .navigate: | |
let (vc, detail) = Detail.buildController(controller, state: "TEST") | |
controller.handle(.present(vc)) | |
case let .storeItem(item): | |
break | |
} | |
}, | |
presenter: { update in | |
switch update { | |
case let .title(string): | |
viewController.set(title: string) | |
case let .items(list): | |
viewController.setListDataSource(list) | |
case let .present(vc): | |
viewController.present(vc, animated: true, completion: nil) | |
} | |
}) | |
viewController.buttonTapAction = { [weak controller] in controller?.handle(.handleButton) ; print("TAP") } | |
return (viewController, controller) | |
} | |
} | |
public enum Detail { | |
public typealias Controller = ModuleController<State, Update, Message, Task> | |
public typealias State = String | |
public enum Message { | |
case back | |
case delete(String) | |
} | |
public typealias Update = String | |
public enum Task { | |
case navigateBack | |
case delete(String) | |
} | |
public final class ViewController: UIViewController { | |
func set(label: String) {} | |
} | |
static func reducer(state: inout State, message: Message) -> ([Update], [Task]) { | |
switch message { | |
case .back: | |
return ([], [.navigateBack]) | |
case let .delete(item): | |
return ([], [.delete(item), .navigateBack]) | |
} | |
} | |
static func buildController<Parent>(_ context: Parent, state: State) -> (UIViewController, Controller) { | |
let viewController: ViewController = .init() | |
let controller: Controller | |
= .init(state: "state", | |
reducer: reducer, | |
worker: { (_, task) in | |
switch task { | |
case .navigateBack: | |
break | |
case .delete: | |
break | |
} | |
}, | |
presenter: { update in | |
viewController.set(label: update) | |
}) | |
return (viewController, controller) | |
} | |
} | |
public final class DashboardViewController: UIViewController { | |
func set(title: String) {} | |
func setListDataSource(_ dataSource: [String]) {} | |
} | |
extension UIViewController { | |
func push(viewController: UIViewController) {} | |
func present(viewController: UIViewController) {} | |
} | |
let (vc, dashboard) = Dashboard.buildController() | |
import PlaygroundSupport | |
PlaygroundPage.current.liveView = vc |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment