From 6acef4279c4f361c1508d39f76b1c9edf99cda6c Mon Sep 17 00:00:00 2001 From: hoonha choi Date: Fri, 23 Jul 2021 04:04:12 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=E1=84=83=E1=85=A6=E1=86=AF?= =?UTF-8?q?=E1=84=85=E1=85=B5=E1=84=80=E1=85=A6=E1=84=8B=E1=85=B5=E1=84=90?= =?UTF-8?q?=E1=85=B3=20=E1=84=91=E1=85=A2=E1=84=90=E1=85=A5=E1=86=AB=20?= =?UTF-8?q?=E1=84=8C=E1=85=A6=E1=84=80=E1=85=A5,=20=E1=84=8F=E1=85=B3?= =?UTF-8?q?=E1=86=AF=E1=84=85=E1=85=A9=E1=84=8C=E1=85=A5=20=E1=84=92?= =?UTF-8?q?=E1=85=A2=E1=86=AB=E1=84=83=E1=85=B3=E1=86=AF=E1=84=85=E1=85=A5?= =?UTF-8?q?=20=E1=84=87=E1=85=A7=E1=86=AB=E1=84=80=E1=85=A7=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ghojeong/issue-tracker/#198 --- .../Coordinator/AppCoordinator.swift | 12 ++++-------- .../Login/LoginViewController.swift | 8 ++------ .../Login/LoginViewCoordinator.swift | 18 +++++------------- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift b/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift index 9c220f52b..0506519ab 100644 --- a/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift +++ b/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift @@ -17,7 +17,7 @@ final class AppCoordinator: Coordinator { var tabBarCoordinatorFactory: ((UINavigationController) -> TabBarCoordinator) } - private let loginCoordinator: LoginViewCoordinator + private var loginCoordinator: LoginViewCoordinator private let tabBarCoordinator: TabBarCoordinator init(navigation: UINavigationController = UINavigationController(), @@ -37,7 +37,9 @@ final class AppCoordinator: Coordinator { } private func showLoginFlow() { - loginCoordinator.delegate = self + loginCoordinator.authenticated = { + self.showTabBarFlow() + } loginCoordinator.loadInitalView() } @@ -52,9 +54,3 @@ final class AppCoordinator: Coordinator { return toggle } } - -extension AppCoordinator: LoginViewCoordinatorDelegate { - func completeLogin() { - showTabBarFlow() - } -} diff --git a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift index d998e71f9..6ef15888c 100644 --- a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift +++ b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift @@ -8,14 +8,10 @@ import UIKit import AuthenticationServices -protocol LoginViewControllerDelegate: AnyObject { - func didFinishLogin() -} - final class LoginViewController: UIViewController, StoryBoarded { var githubLoginHandler: ((ASWebAuthenticationPresentationContextProviding) -> Void)? - weak var delegate: LoginViewControllerDelegate? + var authorizeCompleteHandler: (() -> Void)? override func viewDidLoad() {} @@ -32,7 +28,7 @@ final class LoginViewController: UIViewController, StoryBoarded { func authorizeCompltion() { DispatchQueue.main.async { [weak self] in - self?.delegate?.didFinishLogin() + self?.authorizeCompleteHandler?() self?.dismiss(animated: true, completion: nil) } } diff --git a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift index e088dab73..b5ac5aa2c 100644 --- a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift +++ b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift @@ -11,15 +11,11 @@ protocol LoginViewCoordinatorDependencies { func makeLoginViewController() -> LoginViewController } -protocol LoginViewCoordinatorDelegate: AnyObject { - func completeLogin() -} - -final class LoginViewCoordinator: Coordinator { +struct LoginViewCoordinator: Coordinator { var navigation: UINavigationController + var authenticated: (() -> Void)? private let loginViewControllerFactory: () -> LoginViewController - weak var delegate: LoginViewCoordinatorDelegate? init(navigation: UINavigationController, dependency: LoginViewCoordinatorDependencies) { @@ -29,13 +25,9 @@ final class LoginViewCoordinator: Coordinator { func loadInitalView() { let loginViewController = loginViewControllerFactory() - loginViewController.delegate = self + loginViewController.authorizeCompleteHandler = { + self.authenticated?() + } navigation.setViewControllers([loginViewController], animated: true) } } - -extension LoginViewCoordinator: LoginViewControllerDelegate { - func didFinishLogin() { - delegate?.completeLogin() - } -} From e16c65899be5d4f5d031c62d5472e03c6debfd6e Mon Sep 17 00:00:00 2001 From: hoonha choi Date: Fri, 23 Jul 2021 17:36:33 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=E1=84=90=E1=85=A9=E1=84=8F?= =?UTF-8?q?=E1=85=B3=E1=86=AB=20=E1=84=8B=E1=85=B2=E1=84=86=E1=85=AE=20?= =?UTF-8?q?=E1=84=80=E1=85=AE=E1=84=87=E1=85=AE=E1=86=AB=20=E1=84=92?= =?UTF-8?q?=E1=85=A1=E1=86=B7=E1=84=89=E1=85=AE=E1=84=80=E1=85=A1=20?= =?UTF-8?q?=E1=84=8B=E1=85=A1=E1=84=82=E1=85=B5=E1=86=AB=20=E1=84=87?= =?UTF-8?q?=E1=85=A7=E1=86=AB=E1=84=89=E1=85=AE=E1=84=85=E1=85=A9=20?= =?UTF-8?q?=E1=84=80=E1=85=A1=E1=84=8C=E1=85=B5=E1=84=83=E1=85=A9=E1=84=85?= =?UTF-8?q?=E1=85=A9=E1=86=A8=20=E1=84=87=E1=85=A7=E1=86=AB=E1=84=80?= =?UTF-8?q?=E1=85=A7=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ghojeong/issue-tracker/#198 --- .../issue-tracker/Coordinator/AppCoordinator.swift | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift b/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift index 0506519ab..9e1ec06a1 100644 --- a/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift +++ b/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift @@ -19,6 +19,9 @@ final class AppCoordinator: Coordinator { private var loginCoordinator: LoginViewCoordinator private let tabBarCoordinator: TabBarCoordinator + private var tokenState: Bool { + KeychainSwift().get("token")?.isEmpty ?? true + } init(navigation: UINavigationController = UINavigationController(), dependency: Dependency) { @@ -29,7 +32,7 @@ final class AppCoordinator: Coordinator { } func loadInitalView() { - if isEmptyToken() { + if tokenState { showLoginFlow() } else { showTabBarFlow() @@ -46,11 +49,4 @@ final class AppCoordinator: Coordinator { private func showTabBarFlow() { tabBarCoordinator.loadInitalView() } - - private func isEmptyToken() -> Bool { - guard let toggle = KeychainSwift().get("token")?.isEmpty else { - return true - } - return toggle - } } From ef20e5e40d4821942d1f51c4e4a0ed01ca5bfb2b Mon Sep 17 00:00:00 2001 From: hoonha choi Date: Mon, 26 Jul 2021 20:35:45 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20AppStore,=20TokenAction=20=E1=84=8E?= =?UTF-8?q?=E1=85=AE=E1=84=80=E1=85=A1,=20=E1=84=89=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=90=E1=85=A2=E1=84=8B=E1=85=A6=20=E1=84=84=E1=85=A1?= =?UTF-8?q?=E1=84=85=E1=85=A1=20=E1=84=92=E1=85=AA=E1=84=86=E1=85=A7?= =?UTF-8?q?=E1=86=AB=20=E1=84=92=E1=85=B3=E1=84=85=E1=85=B3=E1=86=B7=20?= =?UTF-8?q?=E1=84=87=E1=85=A1=E1=84=81=E1=85=B1=E1=84=83=E1=85=A9=E1=84=85?= =?UTF-8?q?=E1=85=A9=E1=86=A8=20=E1=84=87=E1=85=A7=E1=86=AB=E1=84=80?= =?UTF-8?q?=E1=85=A7=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ghojeong/issue-tracker/#198 --- .../issue-tracker.xcodeproj/project.pbxproj | 8 +++ .../AppCycle/SceneDelegate.swift | 4 +- .../Coordinator/AppCoordinator.swift | 31 ++++++++---- .../issue-tracker/Coordinator/AppStore.swift | 50 +++++++++++++++++++ .../Coordinator/TokenAction.swift | 15 ++++++ .../Login/LoginViewController.swift | 4 +- .../Login/LoginViewCoordinator.swift | 6 +-- 7 files changed, 102 insertions(+), 16 deletions(-) create mode 100644 mobile/issue-tracker/issue-tracker/Coordinator/AppStore.swift create mode 100644 mobile/issue-tracker/issue-tracker/Coordinator/TokenAction.swift diff --git a/mobile/issue-tracker/issue-tracker.xcodeproj/project.pbxproj b/mobile/issue-tracker/issue-tracker.xcodeproj/project.pbxproj index 19f8960f4..d6f6da0f7 100644 --- a/mobile/issue-tracker/issue-tracker.xcodeproj/project.pbxproj +++ b/mobile/issue-tracker/issue-tracker.xcodeproj/project.pbxproj @@ -33,6 +33,8 @@ BF7B7CD72696AFE400278518 /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7B7CD62696AFE400278518 /* UIColor+Extension.swift */; }; BF7DE027267A418D0019B519 /* LoginViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF0A6C15266F5F8F000F3BC5 /* LoginViewController.storyboard */; }; BF87CBC12686FC40002F81FD /* URLRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8C7FBE2682242B005ABB38 /* URLRouter.swift */; }; + BF8AC85326AE7BE500D90C4C /* TokenAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8AC85226AE7BE500D90C4C /* TokenAction.swift */; }; + BF8AC85526AE7CAD00D90C4C /* AppStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8AC85426AE7CAD00D90C4C /* AppStore.swift */; }; BF8C7F052678905C005ABB38 /* ClientId.plist in Resources */ = {isa = PBXBuildFile; fileRef = BF8C7F042678905C005ABB38 /* ClientId.plist */; }; BF8C7F3A267A5E7D005ABB38 /* UIStoryBoard+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFB399CD2671BB59002C6D80 /* UIStoryBoard+Extension.swift */; }; BF8C7F4D267A6131005ABB38 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = BF8C7F4C267A6131005ABB38 /* KeychainSwift */; }; @@ -124,6 +126,8 @@ BF50FE65267FC3FC0084F73F /* UIAlertController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Extension.swift"; sourceTree = ""; }; BF50FE67268022950084F73F /* ASWebAuthPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASWebAuthPublisher.swift; sourceTree = ""; }; BF7B7CD62696AFE400278518 /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; + BF8AC85226AE7BE500D90C4C /* TokenAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenAction.swift; sourceTree = ""; }; + BF8AC85426AE7CAD00D90C4C /* AppStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStore.swift; sourceTree = ""; }; BF8C7F042678905C005ABB38 /* ClientId.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = ClientId.plist; sourceTree = ""; }; BF8C7F8A267B2C06005ABB38 /* LoginUITests2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginUITests2.swift; sourceTree = ""; }; BF8C7FBE2682242B005ABB38 /* URLRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLRouter.swift; sourceTree = ""; }; @@ -352,6 +356,8 @@ isa = PBXGroup; children = ( BF9D0942269E204E009B6AA0 /* AppCoordinator.swift */, + BF8AC85426AE7CAD00D90C4C /* AppStore.swift */, + BF8AC85226AE7BE500D90C4C /* TokenAction.swift */, ); path = Coordinator; sourceTree = ""; @@ -592,6 +598,7 @@ BFB399CB2671B387002C6D80 /* Endpoint.swift in Sources */, BFA153E6269EE79000341A6D /* LoginViewCoordinator.swift in Sources */, BF9D08F9269CC905009B6AA0 /* UITabBarItem+Extension.swift in Sources */, + BF8AC85326AE7BE500D90C4C /* TokenAction.swift in Sources */, BFD75CFF26949C4E004695E9 /* LabelCell.swift in Sources */, BF251D252695A6AE00834E33 /* IssueLabel.swift in Sources */, BF0A6C12266F5F40000F3BC5 /* LoginViewModel.swift in Sources */, @@ -622,6 +629,7 @@ BF0E36A22695AE0B00835E49 /* IssueListCollectionDataSource.swift in Sources */, BF50FE66267FC3FC0084F73F /* UIAlertController+Extension.swift in Sources */, BFA153FB269F401900341A6D /* TabBarCoordinator.swift in Sources */, + BF8AC85526AE7CAD00D90C4C /* AppStore.swift in Sources */, BFB399CE2671BB59002C6D80 /* UIStoryBoard+Extension.swift in Sources */, BF0A6BD8266F4EE5000F3BC5 /* SceneDelegate.swift in Sources */, BFD2198E268EC02800FEF16C /* Issues.swift in Sources */, diff --git a/mobile/issue-tracker/issue-tracker/AppCycle/SceneDelegate.swift b/mobile/issue-tracker/issue-tracker/AppCycle/SceneDelegate.swift index 39d4f361a..05551ed92 100644 --- a/mobile/issue-tracker/issue-tracker/AppCycle/SceneDelegate.swift +++ b/mobile/issue-tracker/issue-tracker/AppCycle/SceneDelegate.swift @@ -26,10 +26,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window?.rootViewController = navigationController window?.makeKeyAndVisible() + let appStore = AppStore(state: .init()) appCoordinator = AppCoordinator(navigation: navigationController, dependency: .init(loginCoordinatorFactory: appDependency.makeLoginCoordinator, tabBarCoordinatorFactory: appDependency.makeTabBarCoordinator)) - + appCoordinator?.dispatch = appStore.dispatch(_:) + appStore.updateState = appCoordinator?.update(with:) appCoordinator?.loadInitalView() } } diff --git a/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift b/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift index 9e1ec06a1..621659f37 100644 --- a/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift +++ b/mobile/issue-tracker/issue-tracker/Coordinator/AppCoordinator.swift @@ -6,7 +6,6 @@ // import UIKit -import KeychainSwift final class AppCoordinator: Coordinator { @@ -17,11 +16,14 @@ final class AppCoordinator: Coordinator { var tabBarCoordinatorFactory: ((UINavigationController) -> TabBarCoordinator) } + struct TokenState { + var token: TokenAction = .initial + } + private var loginCoordinator: LoginViewCoordinator private let tabBarCoordinator: TabBarCoordinator - private var tokenState: Bool { - KeychainSwift().get("token")?.isEmpty ?? true - } + + var dispatch: ((TokenAction) -> Void)? init(navigation: UINavigationController = UINavigationController(), dependency: Dependency) { @@ -32,17 +34,22 @@ final class AppCoordinator: Coordinator { } func loadInitalView() { - if tokenState { + dispatch?(.initial) + } + + func update(with state: TokenState) { + switch state.token { + case .empty: showLoginFlow() - } else { + case .existent, .completed: showTabBarFlow() + case .initial: + break } } private func showLoginFlow() { - loginCoordinator.authenticated = { - self.showTabBarFlow() - } + loginCoordinator.authenticated = dispatch loginCoordinator.loadInitalView() } @@ -50,3 +57,9 @@ final class AppCoordinator: Coordinator { tabBarCoordinator.loadInitalView() } } + +extension AppCoordinator.TokenState { + init(state: AppStore.State) { + token = state.token + } +} diff --git a/mobile/issue-tracker/issue-tracker/Coordinator/AppStore.swift b/mobile/issue-tracker/issue-tracker/Coordinator/AppStore.swift new file mode 100644 index 000000000..60a87c52d --- /dev/null +++ b/mobile/issue-tracker/issue-tracker/Coordinator/AppStore.swift @@ -0,0 +1,50 @@ +// +// AppStore.swift +// issue-tracker +// +// Created by HOONHA CHOI on 2021/07/26. +// + +import Foundation +import Combine +import KeychainSwift + +final class AppStore { + + struct State { + var token: TokenAction = .initial + } + + struct Reducer { + func reduce(action: TokenAction, state: inout State) { + switch action { + case .initial: + state.token = (KeychainSwift().get("token")?.isEmpty ?? true) ? .empty : .existent + case .empty: + state.token = .empty + case .completed, .existent: + state.token = .existent + } + } + } + + private var reducer: Reducer { + return Reducer() + } + + @Published private(set) var state: State + private var cancellable: AnyCancellable? + + var updateState: ((AppCoordinator.TokenState) -> Void)? + + init(state: State) { + self.state = state + cancellable = $state.sink(receiveValue: { [weak self] state in + self?.updateState?(AppCoordinator.TokenState(token: state.token)) + }) + } + + func dispatch(_ action: TokenAction) { + reducer.reduce(action: action, state: &state) + } +} diff --git a/mobile/issue-tracker/issue-tracker/Coordinator/TokenAction.swift b/mobile/issue-tracker/issue-tracker/Coordinator/TokenAction.swift new file mode 100644 index 000000000..20cd486d9 --- /dev/null +++ b/mobile/issue-tracker/issue-tracker/Coordinator/TokenAction.swift @@ -0,0 +1,15 @@ +// +// AppAction.swift +// issue-tracker +// +// Created by HOONHA CHOI on 2021/07/26. +// + +import Foundation + +enum TokenAction { + case initial + case empty + case existent + case completed +} diff --git a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift index 6ef15888c..094e1d6e3 100644 --- a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift +++ b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewController.swift @@ -11,7 +11,7 @@ import AuthenticationServices final class LoginViewController: UIViewController, StoryBoarded { var githubLoginHandler: ((ASWebAuthenticationPresentationContextProviding) -> Void)? - var authorizeCompleteHandler: (() -> Void)? + var authorizeCompleteHandler: ((TokenAction) -> Void)? override func viewDidLoad() {} @@ -28,7 +28,7 @@ final class LoginViewController: UIViewController, StoryBoarded { func authorizeCompltion() { DispatchQueue.main.async { [weak self] in - self?.authorizeCompleteHandler?() + self?.authorizeCompleteHandler?(.completed) self?.dismiss(animated: true, completion: nil) } } diff --git a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift index b5ac5aa2c..05355aee3 100644 --- a/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift +++ b/mobile/issue-tracker/issue-tracker/PresentationLayer/Login/LoginViewCoordinator.swift @@ -13,7 +13,7 @@ protocol LoginViewCoordinatorDependencies { struct LoginViewCoordinator: Coordinator { var navigation: UINavigationController - var authenticated: (() -> Void)? + var authenticated: ((TokenAction) -> Void)? private let loginViewControllerFactory: () -> LoginViewController @@ -25,9 +25,7 @@ struct LoginViewCoordinator: Coordinator { func loadInitalView() { let loginViewController = loginViewControllerFactory() - loginViewController.authorizeCompleteHandler = { - self.authenticated?() - } + loginViewController.authorizeCompleteHandler = authenticated navigation.setViewControllers([loginViewController], animated: true) } }