-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
182 changed files
with
21,034 additions
and
15 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// | ||
// Aurum.swift | ||
// AmberPlayground | ||
// | ||
// Created by Nikita Arkhipov on 22.01.2020. | ||
// Copyright © 2020 Anvics. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
public class Aurum{ | ||
public static var shouldLogActions = true | ||
|
||
static func toggled(action: Any){ | ||
if !shouldLogActions { return } | ||
print("-----------------------------") | ||
print("\(type(of: action)).\(action)") | ||
} | ||
|
||
public static func setInitial(controller: UIViewController, window: UIWindow){ | ||
window.rootViewController = controller | ||
window.makeKeyAndVisible() | ||
} | ||
|
||
public static func setInitial(controller: AurumLink, window: UIWindow!){ | ||
setInitial(controller: controller.instantiate(), window: window) | ||
} | ||
|
||
public static func setInitial<Module: AurumModuleConfigurator>(module: Module.Type, data: Module.RequiredData, window: UIWindow!){ | ||
setInitial(controller: Module().create(data: data).controller, window: window) | ||
} | ||
|
||
public static func setInitial<Module: AurumModuleConfigurator>(module: Module.Type, window: UIWindow!) where Module.RequiredData == Void{ | ||
setInitial(controller: Module().create().controller, window: window) | ||
} | ||
|
||
|
||
// private static var simulatedActions: [SimulatedActionType] = [] | ||
// | ||
// public static func setInitial(){ | ||
// | ||
// } | ||
// | ||
// public static func simulate(actions: [SimulatedActionType]){ | ||
// simulatedActions = actions | ||
// } | ||
// | ||
// static func moduleInitialized<Module: AurumModule>(module: Module){ | ||
// simulatedActions = simulatedActions.filter { $0.isProcessed(module: module) } | ||
// } | ||
} |
Empty file.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// | ||
// AurumActor.swift | ||
// AmberPlayground | ||
// | ||
// Created by Nikita Arkhipov on 22.01.2020. | ||
// Copyright © 2020 Anvics. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
public struct AurumLink{ | ||
let storyboard: String | ||
let id: String | ||
|
||
func instantiate() -> UIViewController{ | ||
return UIStoryboard(name: storyboard, bundle: nil).instantiateViewController(withIdentifier: id) | ||
} | ||
} | ||
|
||
public enum AurumRouteType{ | ||
var isEmbedding: Bool{ | ||
switch self { | ||
case .embed(_), .embedFullscreen, .cleanEmbed(_), .cleanEmbedFullscreen: return true | ||
default: return false | ||
} | ||
} | ||
|
||
var isCleanEmbedding: Bool{ | ||
switch self { | ||
case .cleanEmbed(_), .cleanEmbedFullscreen: return true | ||
default: return false | ||
} | ||
} | ||
|
||
case present, push, show, baseReplace, replace(UIView.AnimationOptions), embed(UIView), embedFullscreen, cleanEmbed(UIView), cleanEmbedFullscreen | ||
} | ||
|
||
public enum AurumRouteCloseType{ | ||
case close, dismiss, pop, popToRoot, unembed | ||
} | ||
|
||
public class AurumModuleData<A: AurumAction>{ | ||
let controller: UIViewController | ||
let inputActionListener: (A) -> Void | ||
|
||
init(controller: UIViewController, inputActionListener: @escaping (A) -> Void) { | ||
self.controller = controller | ||
self.inputActionListener = inputActionListener | ||
} | ||
} | ||
|
||
public class AurumActor<Action: AurumAction, InputAction: AurumAction, OutputAction: AurumAction> { | ||
|
||
typealias Reducer = (Action) -> Void | ||
typealias InputReducer = (InputAction) -> Void | ||
typealias OutputReducer = (OutputAction) -> Void | ||
|
||
private weak var rootController: UIViewController? | ||
private weak var controller: UIViewController? | ||
|
||
private let reducer: Reducer | ||
private let inputReducer: InputReducer | ||
private let outputReducer: OutputReducer | ||
|
||
init(rootController: UIViewController?, controller: UIViewController?, reducer: @escaping Reducer, inputReducer: @escaping InputReducer, outputReducer: @escaping OutputReducer) { | ||
self.rootController = rootController ?? controller | ||
self.controller = controller | ||
self.reducer = reducer | ||
self.inputReducer = inputReducer | ||
self.outputReducer = outputReducer | ||
} | ||
|
||
func act(_ action: Action){ | ||
reducer(action) | ||
} | ||
|
||
func output(_ action: OutputAction){ | ||
outputReducer(action) | ||
} | ||
|
||
func route(to toController: UIViewController, type: AurumRouteType = .show, animated: Bool = true){ | ||
switch type { | ||
case .present: rootController?.present(toController, animated: animated, completion: nil) | ||
case .push: rootController?.navigationController?.push(toController, animated: animated) | ||
case .show: rootController?.show(toController, animated: animated) | ||
case .baseReplace: rootController?.replaceWith(toController, animation: .transitionFlipFromLeft) | ||
case .replace(let animation): rootController?.replaceWith(toController, animation: animation) | ||
case .embedFullscreen, .cleanEmbedFullscreen: | ||
if type.isCleanEmbedding { controller?.view.unembedAll() } | ||
if let vc = controller { toController.embedIn(view: vc.view, container: vc) } | ||
case .embed(let view), .cleanEmbed(let view): | ||
if type.isCleanEmbedding { view.unembedAll() } | ||
if let vc = controller { toController.embedIn(view: view, container: vc) } | ||
} | ||
} | ||
|
||
func route(link: AurumLink, type: AurumRouteType = .show, animated: Bool = true){ | ||
route(to: link.instantiate(), type: type, animated: animated) | ||
} | ||
|
||
@discardableResult func route<Module: AurumModuleConfigurator>(module: Module.Type, data: Module.RequiredData, type: AurumRouteType = .show, animated: Bool = true, outputListener: ((Module.OutputAction) -> Void)? = nil) -> AurumModuleData<Module.InputAction>{ | ||
let config = Module() | ||
let data = config.create(data: data, rootController: type.isEmbedding ? rootController : nil, outputListener: outputListener) | ||
route(to: data.controller, type: type, animated: animated) | ||
return data | ||
} | ||
|
||
@discardableResult func route<Module: AurumModuleConfigurator>(module: Module.Type, type: AurumRouteType = .show, animated: Bool = true, outputListener: ((Module.OutputAction) -> Void)? = nil) -> AurumModuleData<Module.InputAction> where Module.RequiredData == Void{ | ||
return route(module: module, data: (), type: type, animated: animated, outputListener: outputListener) | ||
} | ||
|
||
func close(type: AurumRouteCloseType = .close, animated: Bool = true){ | ||
switch type { | ||
case .close: controller?.close(animated: animated) | ||
case .dismiss: controller?.dismiss(animated: animated) | ||
case .pop: controller?.pop(animated: animated) | ||
case .popToRoot: controller?.popToRoot(animated: animated) | ||
case .unembed: controller?.unembed() | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// | ||
// AurumController.swift | ||
// AmberPlayground | ||
// | ||
// Created by Nikita Arkhipov on 22.01.2020. | ||
// Copyright © 2020 Anvics. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
public protocol AurumStoreSetupable { | ||
func set<S, A>(store: AurumStore<S, A>) | ||
} | ||
|
||
public protocol AurumController: class, AurumStoreSetupable { | ||
associatedtype State: AurumState | ||
associatedtype Action: AurumAction | ||
var store: AurumStore<State, Action>! { get set } | ||
} | ||
|
||
extension AurumController{ | ||
func set<S, A>(store: AurumStore<S, A>){ | ||
guard let s = store as? AurumStore<State, Action> else { fatalError("\(type(of: self)) failed to set store: expected <\(State.self), \(Action.self)> got <\(S.self), \(A.self)>") } | ||
self.store = s | ||
} | ||
} | ||
|
||
private var UIView_Associated_Embeded: UInt8 = 0 | ||
extension UIView{ | ||
var embedded: [UIViewController]{ | ||
get { | ||
return objc_getAssociatedObject(self, &UIView_Associated_Embeded) as? [UIViewController] ?? [] | ||
} | ||
set { | ||
objc_setAssociatedObject(self, &UIView_Associated_Embeded, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) | ||
} | ||
} | ||
|
||
func unembedAll(){ | ||
embedded.forEach { $0.unembed(shouldModifyEmbedArray: false) } | ||
embedded = [] | ||
} | ||
} | ||
|
||
extension UIViewController{ | ||
public func push(_ viewController: UIViewController, animated: Bool){ | ||
navigationController?.pushViewController(viewController, animated: animated) | ||
} | ||
|
||
public func embedIn(view: UIView, container: UIViewController){ | ||
self.view.frame = view.bounds | ||
container.addChild(self) | ||
view.addSubview(self.view) | ||
view.embedded.append(self) | ||
didMove(toParent: container) | ||
} | ||
|
||
public func show(_ viewController: UIViewController, animated: Bool){ | ||
if navigationController != nil { push(viewController, animated: true) } | ||
else { present(viewController, animated: true, completion: nil) } | ||
} | ||
|
||
public func close(animated: Bool){ | ||
if let nav = navigationController{ nav.popViewController(animated: animated) } | ||
else if parent != nil { unembed() } | ||
else{ dismiss(animated: animated, completion: nil) } | ||
} | ||
|
||
public func dismiss(animated: Bool) { | ||
dismiss(animated: animated, completion: nil) | ||
} | ||
|
||
public func pop(animated: Bool){ | ||
navigationController?.popViewController(animated: animated) | ||
} | ||
|
||
public func popToRoot(animated: Bool){ | ||
navigationController?.popToRootViewController(animated: animated) | ||
} | ||
|
||
public func unembed(shouldModifyEmbedArray: Bool = true){ | ||
removeFromParent() | ||
if let index = view.superview?.embedded.firstIndex(of: self), shouldModifyEmbedArray{ | ||
view.superview?.embedded.remove(at: index) | ||
} | ||
view.removeFromSuperview() | ||
didMove(toParent: nil) | ||
} | ||
|
||
public func replaceWith(_ vc: UIViewController, animation: UIView.AnimationOptions){ | ||
guard let currentVC = UIApplication.shared.keyWindow?.rootViewController else { fatalError() } | ||
UIView.transition(from: currentVC.view, to: vc.view, duration: 0.4, options: animation) { _ in | ||
UIApplication.shared.keyWindow?.rootViewController = vc | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// | ||
// AurumMiddleware.swift | ||
// AmberPlayground | ||
// | ||
// Created by Nikita Arkhipov on 22.01.2020. | ||
// Copyright © 2020 Anvics. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
public typealias EmptyClosure = () -> Void | ||
|
||
public protocol AurumMiddleware { | ||
func preprocess() | ||
|
||
func process(complete: EmptyClosure) | ||
|
||
func postprocess() | ||
} | ||
|
||
extension AurumMiddleware{ | ||
func preprocess(){} | ||
|
||
func process(complete: EmptyClosure){ complete() } | ||
|
||
func postprocess(){} | ||
} | ||
|
||
public protocol AurumMiddlwareProvider { | ||
associatedtype State: AurumState | ||
associatedtype Action: AurumAction | ||
associatedtype InputAction: AurumAction | ||
associatedtype OutputAction: AurumAction | ||
|
||
func provide(forAction action: Action, state: State) -> [AurumMiddleware] | ||
|
||
func provide(forInputAction action: InputAction, state: State) -> [AurumMiddleware] | ||
func provide(forOutputAction action: OutputAction, state: State) -> [AurumMiddleware] | ||
} | ||
|
||
extension AurumMiddlwareProvider{ | ||
func provide(forInputAction action: InputAction, state: State) -> [AurumMiddleware] { return [] } | ||
func provide(forOutputAction action: OutputAction, state: State) -> [AurumMiddleware] { return [] } | ||
|
||
func wrapped() -> AurumMiddlewareProviderWrapper<State, Action, InputAction, OutputAction>{ | ||
return AurumMiddlewareProviderWrapper(provider: self) | ||
} | ||
} | ||
|
||
public class AurumMiddlewareProviderWrapper<State: AurumState, Action: AurumAction, InputAction: AurumAction, OutputAction: AurumAction>{ | ||
|
||
typealias MiddlewareProvider = (Action, State) -> [AurumMiddleware] | ||
typealias InputMiddlewareProvider = (InputAction, State) -> [AurumMiddleware] | ||
typealias OutputMiddlewareProvider = (OutputAction, State) -> [AurumMiddleware] | ||
|
||
let middleware: MiddlewareProvider | ||
let inputMiddleware: InputMiddlewareProvider | ||
let outputMiddleware: OutputMiddlewareProvider | ||
|
||
init<Provider: AurumMiddlwareProvider>(provider: Provider) where Provider.State == State, Provider.Action == Action, Provider.InputAction == InputAction, Provider.OutputAction == OutputAction{ | ||
middleware = provider.provide | ||
inputMiddleware = provider.provide | ||
outputMiddleware = provider.provide | ||
} | ||
} |
Oops, something went wrong.