-
Notifications
You must be signed in to change notification settings - Fork 1
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
[Core] RxFlow로 코디네이터의 기본적인 구조를 설계했어요. #208
base: feature/myeongsoo/add_rxFlow
Are you sure you want to change the base?
Changes from all commits
0c8f80f
175df81
dee81f1
79ac05a
5cab06b
491d28a
7b73851
b1e29dd
d0b555b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// AppFlow.swift | ||
// Tooda | ||
// | ||
// Created by Lyine on 2022/03/26. | ||
// | ||
|
||
import UIKit | ||
import RxFlow | ||
import RxSwift | ||
import RxCocoa | ||
|
||
// Flow는 AnyObject를 준수하므로 class로 선언해주어야 합니다! | ||
final class AppFlow: Flow { | ||
var root: Presentable { | ||
return self.rootWindow | ||
} | ||
|
||
struct Dependency { | ||
let appInject: AppInjectRegister & AppInjectResolve | ||
} | ||
|
||
private let rootWindow: UIWindow | ||
private let dependency: Dependency | ||
|
||
init( | ||
with window: UIWindow, | ||
dependency: Dependency | ||
) { | ||
self.rootWindow = window | ||
self.dependency = dependency | ||
} | ||
|
||
deinit { | ||
print("\(type(of: self)): \(#function))") | ||
} | ||
|
||
func navigate(to step: Step) -> FlowContributors { | ||
guard let step = step.asToodaStep else { return .none } | ||
|
||
switch step { | ||
case .loginIsRequired: | ||
return coordinateToLogin() | ||
|
||
case .loginIsCompleted, .homeIsRequired: | ||
return coordinateToHome() | ||
|
||
default: | ||
return .none | ||
} | ||
} | ||
|
||
private func coordinateToLogin() -> FlowContributors { | ||
let loginFlow = LoginFlow(with: .init(appInject: self.dependency.appInject)) | ||
|
||
Flows.use(loginFlow, when: .created) { [unowned self] root in | ||
self.rootWindow.rootViewController = root | ||
} | ||
|
||
let nextStep = OneStepper(withSingleStep: ToodaStep.loginIsRequired) | ||
|
||
return .one( | ||
flowContributor: .contribute( | ||
withNextPresentable: loginFlow, | ||
withNextStepper: nextStep | ||
) | ||
) | ||
} | ||
|
||
// TODO: HomeFlow를 연결할 예정이에요. | ||
private func coordinateToHome() -> FlowContributors { | ||
return .none | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// | ||
// LoginFlow.swift | ||
// Tooda | ||
// | ||
// Created by Lyine on 2022/03/26. | ||
// | ||
|
||
import UIKit | ||
import RxFlow | ||
|
||
final class LoginFlow: Flow { | ||
|
||
var root: Presentable { | ||
return self.rootViewController | ||
} | ||
|
||
private let rootViewController: UINavigationController = .init() | ||
|
||
struct Dependency { | ||
let appInject: AppInjectRegister & AppInjectResolve | ||
} | ||
|
||
private let dependency: Dependency | ||
|
||
|
||
init(with dependency: Dependency) { | ||
self.dependency = dependency | ||
} | ||
|
||
deinit { | ||
print("\(type(of: self)): \(#function)") | ||
} | ||
|
||
func navigate(to step: Step) -> FlowContributors { | ||
guard let step = step.asToodaStep else { return .none } | ||
|
||
switch step { | ||
case .loginIsRequired: | ||
return coordinateToLogin() | ||
case .loginIsCompleted: | ||
return .end(forwardToParentFlowWithStep: ToodaStep.homeIsRequired) | ||
default: | ||
return .none | ||
} | ||
|
||
} | ||
} | ||
|
||
// MARK: - Extensions | ||
|
||
extension LoginFlow { | ||
private func coordinateToLogin() -> FlowContributors { | ||
let reactor = LoginReactor( | ||
dependency: .init( | ||
service: self.dependency.appInject.resolve(NetworkingProtocol.self), | ||
coordinator: self.dependency.appInject.resolve(AppCoordinatorType.self), | ||
localPersistanceManager: self.dependency.appInject.resolve(LocalPersistanceManagerType.self), | ||
socialLoginService: self.dependency.appInject.resolve(SocialLoginServiceType.self), | ||
snackBarEventBus: SnackBarEventBus.event.asObservable() | ||
) | ||
) | ||
|
||
let viewController = LoginViewController(reactor: reactor) | ||
|
||
self.rootViewController.pushViewController(viewController, animated: true) | ||
|
||
return .one(flowContributor: .contribute(withNextPresentable: viewController, | ||
withNextStepper: reactor)) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// | ||
// AppStepper.swift | ||
// Tooda | ||
// | ||
// Created by Lyine on 2022/03/26. | ||
// | ||
|
||
import Foundation | ||
import RxFlow | ||
import RxSwift | ||
import RxRelay | ||
|
||
struct AppStepper: Stepper { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. struct로 한 이유가 어떤거에요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 샘플로 찾아본 예제에서 struct로 설계했어서 크게 고려하지 않았었습니다. |
||
let steps: PublishRelay<Step> = .init() | ||
|
||
struct Dependency { | ||
let persistenceManager: LocalPersistanceManagerType | ||
} | ||
|
||
private let dependency: Dependency | ||
private let disposeBag: DisposeBag = .init() | ||
|
||
init(dependency: Dependency) { | ||
self.dependency = dependency | ||
} | ||
|
||
func readyToEmitSteps() { | ||
let token: AppToken? = self.dependency.persistenceManager.objectValue(forKey: .appToken) | ||
|
||
Observable.just(token) | ||
.map { $0 != nil } | ||
.map { $0 ? ToodaStep.loginIsCompleted : ToodaStep.loginIsRequired } | ||
.bind(to: steps) | ||
.disposed(by: self.disposeBag) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// | ||
// Step+asSample.swift | ||
// Tooda | ||
// | ||
// Created by Lyine on 2022/03/26. | ||
// | ||
|
||
import Foundation | ||
|
||
import RxFlow | ||
|
||
extension Step { | ||
var asToodaStep: ToodaStep? { | ||
return self as? ToodaStep | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// | ||
// ToodaStep.swift | ||
// Tooda | ||
// | ||
// Created by Lyine on 2022/03/26. | ||
// | ||
|
||
import Foundation | ||
import RxFlow | ||
|
||
enum ToodaStep: Step { | ||
// Global | ||
case alert(message: String) | ||
case dismiss | ||
|
||
// Login | ||
case loginIsRequired | ||
case loginIsCompleted | ||
|
||
// Home | ||
case homeIsRequired | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
공유주신대로 dependency를 가져야 되는 군요ㅠ ㅎㅎ 다른 대안이 저도 떠오르지 않아서 이렇게 구성해야 할듯요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네네 Flow에서 ViewController를 보내는 형태가 되어서 생성시점에 의존성을 넘겨주려면 Flow가 프로퍼티로 들고있어야겠더라구요..