2017-01-22 16:22:05 +03:00
|
|
|
/**
|
|
|
|
* Tae Won Ha - http://taewon.de - @hataewon
|
|
|
|
* See LICENSE
|
|
|
|
*/
|
2017-01-17 21:47:59 +03:00
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import RxSwift
|
|
|
|
|
|
|
|
class StateContext {
|
|
|
|
|
2017-01-25 00:39:19 +03:00
|
|
|
let stateSource: Observable<AppState>
|
2017-01-17 21:47:59 +03:00
|
|
|
let actionEmitter = Emitter<Any>()
|
|
|
|
|
2017-02-06 20:57:50 +03:00
|
|
|
init(_ initialState: AppState) {
|
2017-02-20 20:04:45 +03:00
|
|
|
let baseServerUrl = URL(string: "http://localhost:\(NetUtils.openPort())")!
|
|
|
|
|
|
|
|
self.httpServerService = HttpServerService(port: baseServerUrl.port ?? 0)
|
|
|
|
self.appDelegateTransformer = AppDelegateTransformer(baseServerUrl: baseServerUrl)
|
|
|
|
self.previewTransformer = PreviewTransformer(baseServerUrl: baseServerUrl)
|
|
|
|
self.previewToolTransformer = PreviewToolTransformer(baseServerUrl: baseServerUrl)
|
2017-01-22 16:22:05 +03:00
|
|
|
|
2017-02-09 02:31:49 +03:00
|
|
|
self.appState = initialState
|
|
|
|
|
|
|
|
self.stateSource = self.stateSubject.asObservable()
|
2017-02-12 13:24:15 +03:00
|
|
|
let actionSource = self.actionEmitter.observable
|
2017-02-09 02:31:49 +03:00
|
|
|
|
2017-01-22 16:22:05 +03:00
|
|
|
Observable
|
|
|
|
.of(
|
|
|
|
actionSource
|
|
|
|
.mapOmittingNil { $0 as? AppDelegate.Action }
|
|
|
|
.map { StateActionPair(state: self.appState, action: $0, modified: false) }
|
|
|
|
.transform(by: self.appDelegateTransformer)
|
|
|
|
.filter { $0.modified }
|
|
|
|
.map { $0.state },
|
|
|
|
actionSource
|
|
|
|
.mapOmittingNil { $0 as? UuidAction<MainWindow.Action> }
|
|
|
|
.map { StateActionPair(state: self.appState, action: $0, modified: false) }
|
|
|
|
.transform(by: self.uiRootTransformer)
|
2017-02-20 21:33:22 +03:00
|
|
|
.transform(by: self.mainWindowOpenQuicklyTransformer)
|
|
|
|
.filter { $0.modified }
|
|
|
|
.map { $0.state },
|
|
|
|
actionSource
|
|
|
|
.mapOmittingNil { $0 as? FileMonitor.Action }
|
2017-02-23 21:22:11 +03:00
|
|
|
.map { StateActionPair(state: self.appState, action: $0, modified: false) }
|
2017-02-20 21:33:22 +03:00
|
|
|
.transform(by: self.fileMonitorTransformer)
|
|
|
|
.filter { $0.modified }
|
|
|
|
.map { $0.state },
|
|
|
|
actionSource
|
|
|
|
.mapOmittingNil { $0 as? OpenQuicklyWindow.Action }
|
2017-02-23 21:22:11 +03:00
|
|
|
.map { StateActionPair(state: self.appState, action: $0, modified: false) }
|
2017-02-20 21:33:22 +03:00
|
|
|
.transform(by: self.openQuicklyTransformer)
|
2017-01-22 16:22:05 +03:00
|
|
|
.filter { $0.modified }
|
|
|
|
.map { $0.state }
|
|
|
|
)
|
|
|
|
.merge()
|
2017-01-17 21:47:59 +03:00
|
|
|
.subscribe(onNext: { state in
|
2017-01-22 16:22:05 +03:00
|
|
|
self.appState = state
|
|
|
|
self.stateSubject.onNext(self.appState)
|
2017-01-17 21:47:59 +03:00
|
|
|
})
|
|
|
|
.addDisposableTo(self.disposeBag)
|
|
|
|
|
2017-02-12 13:24:15 +03:00
|
|
|
Observable
|
2017-02-24 02:24:30 +03:00
|
|
|
.of(
|
|
|
|
actionSource
|
|
|
|
.mapOmittingNil { $0 as? UuidAction<MainWindow.Action> }
|
|
|
|
.mapOmittingNil { action in
|
|
|
|
guard let mainWindowState = self.appState.mainWindows[action.uuid] else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return StateActionPair(state: UuidState(uuid: action.uuid, state: mainWindowState),
|
|
|
|
action: action.payload,
|
|
|
|
modified: false)
|
|
|
|
}
|
|
|
|
.transform(by: self.mainWindowTransformer)
|
2017-02-27 01:01:06 +03:00
|
|
|
.transform(by: self.previewTransformer.forMainWindow)
|
2017-02-24 02:24:30 +03:00
|
|
|
.filter { $0.modified }
|
2017-02-27 01:01:06 +03:00
|
|
|
.apply(to: self.previewService.forMainWindow)
|
2017-02-24 02:24:30 +03:00
|
|
|
.apply(to: self.httpServerService)
|
|
|
|
.map { $0.state },
|
|
|
|
actionSource
|
|
|
|
.mapOmittingNil { $0 as? UuidAction<PreviewTool.Action> }
|
|
|
|
.mapOmittingNil { action in
|
|
|
|
guard let mainWindowState = self.appState.mainWindows[action.uuid] else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return StateActionPair(state: UuidState(uuid: action.uuid, state: mainWindowState),
|
|
|
|
action: action.payload,
|
|
|
|
modified: false)
|
|
|
|
}
|
|
|
|
.transform(by: self.previewToolTransformer)
|
|
|
|
.filter { $0.modified }
|
|
|
|
.map { $0.state },
|
|
|
|
actionSource
|
2017-02-24 12:51:24 +03:00
|
|
|
.mapOmittingNil { $0 as? UuidAction<FileBrowser.Action> }
|
2017-02-24 02:24:30 +03:00
|
|
|
.mapOmittingNil { action in
|
|
|
|
guard let mainWindowState = self.appState.mainWindows[action.uuid] else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return StateActionPair(state: UuidState(uuid: action.uuid, state: mainWindowState),
|
|
|
|
action: action.payload,
|
|
|
|
modified: false)
|
|
|
|
}
|
2017-02-24 12:51:24 +03:00
|
|
|
.transform(by: self.fileBrowserTransformer)
|
2017-02-24 02:24:30 +03:00
|
|
|
.filter { $0.modified }
|
2017-02-26 16:23:23 +03:00
|
|
|
.map { $0.state },
|
|
|
|
actionSource
|
|
|
|
.mapOmittingNil { $0 as? UuidAction<OpenedFileList.Action> }
|
|
|
|
.mapOmittingNil { action in
|
|
|
|
guard let mainWindowState = self.appState.mainWindows[action.uuid] else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return StateActionPair(state: UuidState(uuid: action.uuid, state: mainWindowState),
|
|
|
|
action: action.payload,
|
|
|
|
modified: false)
|
|
|
|
}
|
|
|
|
.transform(by: self.openedFileListTransformer)
|
2017-02-27 01:01:06 +03:00
|
|
|
.transform(by: self.previewTransformer.forOpenedFileList)
|
2017-02-26 16:23:23 +03:00
|
|
|
.filter { $0.modified }
|
2017-02-27 01:01:06 +03:00
|
|
|
.apply(to: self.previewService.forOpenedFileList)
|
2017-02-24 02:24:30 +03:00
|
|
|
.map { $0.state }
|
|
|
|
)
|
2017-02-12 13:24:15 +03:00
|
|
|
.merge()
|
2017-02-11 20:32:22 +03:00
|
|
|
.subscribe(onNext: { state in
|
|
|
|
self.appState.mainWindows[state.uuid] = state.payload
|
|
|
|
self.stateSubject.onNext(self.appState)
|
|
|
|
})
|
|
|
|
.addDisposableTo(self.disposeBag)
|
|
|
|
|
2017-02-24 02:24:30 +03:00
|
|
|
|
2017-02-03 00:39:05 +03:00
|
|
|
#if DEBUG
|
2017-02-24 02:24:30 +03:00
|
|
|
// actionSource.debug().subscribe().addDisposableTo(self.disposeBag)
|
2017-02-11 20:32:22 +03:00
|
|
|
// stateSource.debug().subscribe().addDisposableTo(self.disposeBag)
|
2017-02-03 00:39:05 +03:00
|
|
|
#endif
|
2017-01-17 21:47:59 +03:00
|
|
|
}
|
|
|
|
|
2017-02-12 12:53:24 +03:00
|
|
|
deinit {
|
|
|
|
self.stateSubject.onCompleted()
|
|
|
|
}
|
|
|
|
|
2017-01-25 00:39:19 +03:00
|
|
|
fileprivate let stateSubject = PublishSubject<AppState>()
|
2017-01-22 16:22:05 +03:00
|
|
|
fileprivate let scheduler = SerialDispatchQueueScheduler(qos: .userInitiated)
|
2017-01-17 21:47:59 +03:00
|
|
|
fileprivate let disposeBag = DisposeBag()
|
|
|
|
|
2017-02-06 20:57:50 +03:00
|
|
|
fileprivate var appState: AppState
|
2017-01-17 21:47:59 +03:00
|
|
|
|
2017-02-06 20:57:50 +03:00
|
|
|
fileprivate let appDelegateTransformer: AppDelegateTransformer
|
2017-01-17 21:47:59 +03:00
|
|
|
fileprivate let uiRootTransformer = UiRootTransformer()
|
2017-02-19 20:00:41 +03:00
|
|
|
fileprivate let fileMonitorTransformer = FileMonitorTransformer()
|
2017-02-20 21:33:22 +03:00
|
|
|
|
2017-01-17 21:47:59 +03:00
|
|
|
fileprivate let mainWindowTransformer = MainWindowTransformer()
|
2017-02-20 21:33:22 +03:00
|
|
|
fileprivate let mainWindowOpenQuicklyTransformer = MainWindowToOpenQuicklyTransformer()
|
|
|
|
|
|
|
|
fileprivate let openQuicklyTransformer = OpenQuicklyTransformer()
|
|
|
|
|
2017-02-04 17:34:13 +03:00
|
|
|
fileprivate let previewTransformer: PreviewTransformer
|
2017-02-12 13:24:15 +03:00
|
|
|
fileprivate let previewToolTransformer: PreviewToolTransformer
|
2017-01-25 00:39:19 +03:00
|
|
|
|
2017-02-24 12:51:24 +03:00
|
|
|
fileprivate let fileBrowserTransformer = FileBrowserTransformer()
|
2017-02-24 02:24:30 +03:00
|
|
|
|
2017-02-26 16:23:23 +03:00
|
|
|
fileprivate let openedFileListTransformer = OpenedFileListTransformer()
|
|
|
|
|
2017-02-27 01:01:06 +03:00
|
|
|
fileprivate let previewService = PreviewService()
|
2017-01-25 00:39:19 +03:00
|
|
|
fileprivate let httpServerService: HttpServerService
|
2017-01-17 21:47:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
extension Observable {
|
|
|
|
|
2017-02-03 00:39:05 +03:00
|
|
|
fileprivate func transform<T:Transformer>(by transformer: T) -> Observable<Element> where T.Element == Element {
|
2017-01-25 00:39:19 +03:00
|
|
|
return transformer.transform(self)
|
2017-01-17 21:47:59 +03:00
|
|
|
}
|
|
|
|
|
2017-02-05 17:17:25 +03:00
|
|
|
fileprivate func apply<S:Service>(to service: S) -> Observable<Element> where S.Element == Element {
|
2017-02-03 00:39:05 +03:00
|
|
|
return self.do(onNext: service.apply)
|
2017-01-17 21:47:59 +03:00
|
|
|
}
|
|
|
|
}
|