From bbbbb96aaac0cfe1491e448b8e3021e5869d04c0 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 13:59:51 +0900 Subject: [PATCH 01/26] =?UTF-8?q?[feat]=20accent=20color=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets.xcassets/AccentColor.colorset/Contents.json | 9 +++++++++ .../UseCases/Settings/DefaultSettingsUseCase.swift | 8 ++++++++ .../UseCases/Settings/Protocols/SettingsUseCase.swift | 8 ++++++++ .../Settings/ViewModel/SettingsViewModel.swift | 8 ++++++++ 4 files changed, 33 insertions(+) create mode 100644 DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift create mode 100644 DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift create mode 100644 DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift diff --git a/DailyQuest/DailyQuest/Assets.xcassets/AccentColor.colorset/Contents.json b/DailyQuest/DailyQuest/Assets.xcassets/AccentColor.colorset/Contents.json index eb87897..641de21 100644 --- a/DailyQuest/DailyQuest/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/DailyQuest/DailyQuest/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,6 +1,15 @@ { "colors" : [ { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.490", + "green" : "0.871", + "red" : "1.000" + } + }, "idiom" : "universal" } ], diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift new file mode 100644 index 0000000..4b63820 --- /dev/null +++ b/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift @@ -0,0 +1,8 @@ +// +// DefaultSettingsUseCase.swift +// DailyQuest +// +// Created by jinwoong Kim on 2022/12/06. +// + +import Foundation diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift new file mode 100644 index 0000000..957416a --- /dev/null +++ b/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift @@ -0,0 +1,8 @@ +// +// SettingsUseCase.swift +// DailyQuest +// +// Created by jinwoong Kim on 2022/12/06. +// + +import Foundation diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift new file mode 100644 index 0000000..5416d4f --- /dev/null +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift @@ -0,0 +1,8 @@ +// +// SettingsViewModel.swift +// DailyQuest +// +// Created by jinwoong Kim on 2022/12/06. +// + +import Foundation From 582baef7ffcd3d11799132093ce41c0cd724f670 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:00:05 +0900 Subject: [PATCH 02/26] =?UTF-8?q?[feat]=20SettingsUseCase=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UseCases/Settings/Protocols/SettingsUseCase.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift index 957416a..2f4d42d 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/SettingsUseCase.swift @@ -6,3 +6,10 @@ // import Foundation + +import RxSwift + +protocol SettingsUseCase { + func isLoggedIn() -> Observable + func signOut() -> Observable +} From 7216d081cbc20385aea0dfd7fe994fe772836416 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:00:18 +0900 Subject: [PATCH 03/26] =?UTF-8?q?[feat]=20SettingsUseCase=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EC=B2=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Settings/DefaultSettingsUseCase.swift | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift index 4b63820..89ef700 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultSettingsUseCase.swift @@ -6,3 +6,35 @@ // import Foundation + +import RxSwift + +final class DefaultSettingsUseCase { + private let userRepository: UserRepository + private let authRepository: AuthRepository + + init(userRepository: UserRepository, authRepository: AuthRepository) { + self.userRepository = userRepository + self.authRepository = authRepository + } +} + +extension DefaultSettingsUseCase: SettingsUseCase { + func isLoggedIn() -> Observable { + return userRepository + .isLoggedIn() + .map { id in + guard let _ = id else { return false } + return true + } + .asObservable() + } + + func signOut() -> Observable { + return authRepository + .signOut() + .map { _ in true } + .catchAndReturn(false) + .asObservable() + } +} From 7e8e9d634085edc880d54258a0600f65025bd45b Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:00:40 +0900 Subject: [PATCH 04/26] =?UTF-8?q?[refactor]=20UserRepository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EC=B2=B4=EC=9D=98=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=98=B5=EC=85=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DailyQuest/Data/Repositories/DefaultUserRepository.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift index 71994d1..a5797de 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift @@ -13,7 +13,7 @@ final class DefaultUserRepository { private let persistentStorage: UserInfoStorage private let networkService: NetworkService - init(persistentStorage: UserInfoStorage, networkService: NetworkService) { + init(persistentStorage: UserInfoStorage, networkService: NetworkService = FirebaseService.shared) { self.persistentStorage = persistentStorage self.networkService = networkService } From e09a846156e9a2b0be27d49263570820006cbb58 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:01:00 +0900 Subject: [PATCH 05/26] =?UTF-8?q?[refactor]=20NavigateField=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Settings/View/NavigateField/NavigateCell.swift | 2 +- .../Settings/View/NavigateField/NavigateField.swift | 8 ++++++++ .../View/NavigateField/NavigateItemViewModel.swift | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateCell.swift b/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateCell.swift index edb9c14..320ec1c 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateCell.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateCell.swift @@ -54,6 +54,6 @@ final class NavigateCell: UITableViewCell { func setup(with viewModel: NavigateItemViewModel) { icon.image = UIImage(systemName: viewModel.imageName) - title.text = viewModel.title + title.text = viewModel.viewType.rawValue } } diff --git a/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateField.swift b/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateField.swift index 060b4f6..079f7d4 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateField.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateField.swift @@ -13,6 +13,14 @@ final class NavigateField { init(viewModel: NavigateItemViewModel) { self.viewModel = viewModel } + + func toggle(with status: Bool) { + if status { + viewModel.viewType = .logout + } else { + viewModel.viewType = .login + } + } } extension NavigateField: CommonField { diff --git a/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateItemViewModel.swift b/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateItemViewModel.swift index 6b0ea71..15ef952 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateItemViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/View/NavigateField/NavigateItemViewModel.swift @@ -10,5 +10,5 @@ import Foundation struct NavigateItemViewModel { let title: String let imageName: String - let viewType: ViewType + var viewType: ViewType } From a026f63efa502cdeba01858ece54e5e58097d27f Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:02:19 +0900 Subject: [PATCH 06/26] =?UTF-8?q?[feat]=20ViewType=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로그인상태, 로그아웃 상태를 가르킵니다. --- .../DailyQuest/Presentation/Settings/View/CommonField.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/View/CommonField.swift b/DailyQuest/DailyQuest/Presentation/Settings/View/CommonField.swift index a8b2125..064a554 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/View/CommonField.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/View/CommonField.swift @@ -7,8 +7,9 @@ import UIKit -enum ViewType { - case login +enum ViewType: String { + case login = "로그인" + case logout = "로그아웃" } protocol CommonField { From b82b243259db06315ce1c02e9c3200339a7a61f9 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:02:50 +0900 Subject: [PATCH 07/26] =?UTF-8?q?[feat]=20SettingsViewModel=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModel/SettingsViewModel.swift | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift index 5416d4f..ee76fb4 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SettingsViewModel.swift @@ -6,3 +6,48 @@ // import Foundation + +import RxSwift + +final class SettingsViewModel { + private(set) var fields: [CommonField] + private var navigateField: NavigateField + + private let settingsUseCase: SettingsUseCase + private var disposableBag = DisposeBag() + + init(settingsUseCase: SettingsUseCase) { + self.settingsUseCase = settingsUseCase + + let toggleField = ToggleField(viewModel: .init(title: "둘러보기 허용", imageName: "person.crop.circle.badge.checkmark")) + let plainField = PlainField(viewModel: .init(title: "앱 버전", info: "0.0.1", imageName: "exclamationmark.transmission")) + self.navigateField = NavigateField(viewModel: .init(title: "로그인", imageName: "person.circle.fill", viewType: .login)) + + self.fields = [ + toggleField, + plainField, + navigateField + ] + + print(self.fields.count) + } + + struct Input {} + + struct Output { + let loginStatusDidChange: Observable + } + + func transform() -> Output { + let loginStatusDidChange = settingsUseCase + .isLoggedIn() + .do(onNext: navigateField.toggle(with:)) + .map { _ in Void() } + + return Output(loginStatusDidChange: loginStatusDidChange) + } + + func signOut() -> Observable { + return settingsUseCase.signOut() + } +} From 3ca4583cfeeb0ede067fa187b6ae17862d14c64b Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:03:14 +0900 Subject: [PATCH 08/26] =?UTF-8?q?[refactor]=20SettingsViewController?= =?UTF-8?q?=EB=A5=BC=20=ED=95=B4=EB=8B=B9=20viewmodel=EA=B3=BC=20=ED=95=A8?= =?UTF-8?q?=EA=BB=98=20=EB=8F=99=EC=9E=91=ED=95=98=EA=B2=8C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SettingsViewController.swift | 63 +++++++++++++------ 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift index 1cb18c8..c556eea 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift @@ -11,49 +11,74 @@ import RxSwift import RxCocoa final class SettingsViewController: UITableViewController { - enum Event { - case showLoginFlow - } + private var viewModel: SettingsViewModel! + private var disposableBag = DisposeBag() var itemDidClick = PublishSubject() - private let fields: [CommonField] = [ - ToggleField(viewModel: .init(title: "둘러보기 허용", imageName: "person.crop.circle.badge.checkmark")), - PlainField(viewModel: .init(title: "some", info: "some...?", imageName: "pencil")), - NavigateField(viewModel: .init(title: "로그인", imageName: "person.circle.fill", viewType: .login)), - PlainField(viewModel: .init(title: "앱 버전", info: "0.0.1", imageName: "exclamationmark.transmission")) - ] - // MARK: - Life Cycle + static func create(with viewModel: SettingsViewModel) -> SettingsViewController { + let vc = SettingsViewController() + vc.viewModel = viewModel + + return vc + } + override func viewDidLoad() { super.viewDidLoad() tableView.separatorStyle = .singleLine register() + + bind() + } + + private func bind() { + let output = viewModel.transform() + + output + .loginStatusDidChange + .subscribe(onNext: { [weak self] in self?.reloadData() }) + .disposed(by: disposableBag) + } + + private func reloadData() { + tableView.reloadData() + } + + private func register() { + viewModel.fields.forEach { field in + field.register(for: self.tableView) + } + } +} + +extension SettingsViewController { + enum Event { + case showLoginFlow } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return fields.count + return viewModel.fields.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let field = fields[indexPath.row] + let field = viewModel.fields[indexPath.row] return field.dequeue(for: tableView, at: indexPath) } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let field = fields[indexPath.row] + let field = viewModel.fields[indexPath.row] guard let type = field.didSelect() else { return } switch type { case .login: itemDidClick.onNext(.showLoginFlow) - } - } - - private func register() { - fields.forEach { field in - field.register(for: self.tableView) + case .logout: + viewModel + .signOut() + .subscribe() + .disposed(by: disposableBag) } } } From bb48aa4cf0f5469cba40e7eb47c2ba508968a333 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:03:23 +0900 Subject: [PATCH 09/26] =?UTF-8?q?[feat]=20DI=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SettingsSceneDIContainer.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift b/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift index a61a0e6..5e049a0 100644 --- a/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift +++ b/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift @@ -9,26 +9,45 @@ import UIKit final class SettingsSceneDIContainer { + lazy var userInfoStorage: UserInfoStorage = RealmUserInfoStorage() + // MARK: - Repositories func makeAuthRepository() -> AuthRepository { return DefaultAuthRepository() } + func makeUserRepository() -> UserRepository { + return DefaultUserRepository(persistentStorage: userInfoStorage) + } + // MARK: - Use Cases func makeAuthUseCase() -> AuthUseCase { return DefaultAuthUseCase(authRepository: makeAuthRepository()) } + func makeSettingsUseCase() -> SettingsUseCase { + return DefaultSettingsUseCase(userRepository: makeUserRepository(), + authRepository: makeAuthRepository()) + } + // MARK: - View Models func makeLoginViewModel() -> LoginViewModel { return LoginViewModel(authUseCase: makeAuthUseCase()) } + func makeSettingsViewModel() -> SettingsViewModel { + return SettingsViewModel(settingsUseCase: makeSettingsUseCase()) + } + // MARK: - View Controller func makeLoginViewController() -> LoginViewController { return LoginViewController.create(with: makeLoginViewModel()) } + func makeSettingsViewController() -> SettingsViewController { + return SettingsViewController.create(with: makeSettingsViewModel()) + } + // MARK: - Flow func makeSettingsCoordinator(navigationController: UINavigationController, settingsSceneDIContainer: SettingsSceneDIContainer) -> SettingsCoordinator { From 5d5b136636815d32aeed60b6f1dc67d440102dd2 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:03:36 +0900 Subject: [PATCH 10/26] =?UTF-8?q?[feat]=20SettingsViewController=EB=A5=BC?= =?UTF-8?q?=20DIContainer=EB=A5=BC=20=ED=86=B5=ED=95=B4=EC=84=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Settings/Flow/SettingsCoordinator.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift b/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift index 6775f3d..c07f992 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift @@ -28,10 +28,10 @@ final class DefaultSettingsCoordinator: SettingsCoordinator { } func start() { - let settingsController = SettingsViewController() - navigationController.pushViewController(settingsController, animated: false) + let settingsViewController = settingsSceneDIContainer.makeSettingsViewController() + navigationController.pushViewController(settingsViewController, animated: false) - settingsController + settingsViewController .itemDidClick .bind(onNext: { [weak self] event in switch event { From cf1cd4b9553d2c75dd0ff9443194e3ff0716ddcd Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:03:56 +0900 Subject: [PATCH 11/26] =?UTF-8?q?[refactor]=20LoginViewController=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=8C=A8=EC=8A=A4=EC=9B=8C=EB=93=9C=20=EA=B0=80?= =?UTF-8?q?=EB=A6=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DailyQuest/DailyQuest.xcodeproj/project.pbxproj | 16 ++++++++++++++-- .../ViewController/LoginViewController.swift | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj index 11eeac0..0222301 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj +++ b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj @@ -46,6 +46,9 @@ 34283103292E2D9B00AE811B /* ToggleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34283102292E2D9B00AE811B /* ToggleCell.swift */; }; 34283105292E2E3F00AE811B /* ToggleField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34283104292E2E3F00AE811B /* ToggleField.swift */; }; 3429084F29383D73001812B1 /* UserRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3429084E29383D73001812B1 /* UserRepository.swift */; }; + 34404D92293EF75F0007E661 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34404D91293EF75F0007E661 /* SettingsViewModel.swift */; }; + 34404D94293EF9850007E661 /* SettingsUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34404D93293EF9850007E661 /* SettingsUseCase.swift */; }; + 34404D96293EF9E50007E661 /* DefaultSettingsUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34404D95293EF9E50007E661 /* DefaultSettingsUseCase.swift */; }; 3449AD5B2922164B00B87619 /* Quest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3449AD5A2922164B00B87619 /* Quest.swift */; }; 3449AD5D2922197000B87619 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3449AD5C2922197000B87619 /* User.swift */; }; 3449AD6029222B3900B87619 /* UserInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3449AD5F29222B3900B87619 /* UserInfoCell.swift */; }; @@ -105,9 +108,9 @@ 34EE0C662935FD7D002BEC23 /* BrowseItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3499552629235D1E007AB99E /* BrowseItemViewModel.swift */; }; 34EE6EB72924C674005AF583 /* QuestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB62924C674005AF583 /* QuestView.swift */; }; 34EE6EB92924CAA1005AF583 /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; + 34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; }; 34FCD369293DEED600E0DC8A /* FriendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD368293DEED600E0DC8A /* FriendViewController.swift */; }; 34FCD36B293DF2F600E0DC8A /* FriendStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */; }; - 34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; }; 34FEFB992935EA6D00954A40 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 34FEFB982935EA6D00954A40 /* Kingfisher */; }; 34FF6C5A292B86F8002AFD4D /* SnapKit-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */; }; 34FF6C5D292B8B27002AFD4D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C5C292B8B27002AFD4D /* RxCocoa */; }; @@ -253,6 +256,9 @@ 34283102292E2D9B00AE811B /* ToggleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleCell.swift; sourceTree = ""; }; 34283104292E2E3F00AE811B /* ToggleField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleField.swift; sourceTree = ""; }; 3429084E29383D73001812B1 /* UserRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRepository.swift; sourceTree = ""; }; + 34404D91293EF75F0007E661 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; + 34404D93293EF9850007E661 /* SettingsUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsUseCase.swift; sourceTree = ""; }; + 34404D95293EF9E50007E661 /* DefaultSettingsUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSettingsUseCase.swift; sourceTree = ""; }; 3449AD5A2922164B00B87619 /* Quest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Quest.swift; sourceTree = ""; }; 3449AD5C2922197000B87619 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 3449AD5F29222B3900B87619 /* UserInfoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoCell.swift; sourceTree = ""; }; @@ -307,9 +313,9 @@ 34EE0C632935FD6B002BEC23 /* BrowseViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseViewModelTests.swift; sourceTree = ""; }; 34EE6EB62924C674005AF583 /* QuestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestView.swift; sourceTree = ""; }; 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestViewModel.swift; sourceTree = ""; }; + 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = ""; }; 34FCD368293DEED600E0DC8A /* FriendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendViewController.swift; sourceTree = ""; }; 34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendStatusView.swift; sourceTree = ""; }; - 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = ""; }; 9B1CFB3E292B585700CCE97A /* QuestDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QuestDTO+Mapping.swift"; sourceTree = ""; }; 9BD8CCF22935BC0D00E6EA2F /* DefaultBrowseRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBrowseRepository.swift; sourceTree = ""; }; 9BD8CCF42935C38300E6EA2F /* UserDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDTO+Mapping.swift"; sourceTree = ""; }; @@ -426,6 +432,7 @@ isa = PBXGroup; children = ( 34113BE72934917500AB4919 /* LoginViewModel.swift */, + 34404D91293EF75F0007E661 /* SettingsViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -500,6 +507,7 @@ children = ( 3417B1422935DA2E00900454 /* Protocols */, 340A724A29348C2200B26AA6 /* DefaultAuthUseCase.swift */, + 34404D95293EF9E50007E661 /* DefaultSettingsUseCase.swift */, ); path = Settings; sourceTree = ""; @@ -516,6 +524,7 @@ isa = PBXGroup; children = ( 340A724829348B1B00B26AA6 /* AuthUseCase.swift */, + 34404D93293EF9850007E661 /* SettingsUseCase.swift */, ); path = Protocols; sourceTree = ""; @@ -1231,6 +1240,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 34404D94293EF9850007E661 /* SettingsUseCase.swift in Sources */, A5A8C8362936EC7E00988C88 /* SubQuestEntity.swift in Sources */, 34EC71D1292DF27E004813CB /* Date+.swift in Sources */, 34D8360129359C8A001DE9DF /* BrowseRepository.swift in Sources */, @@ -1251,6 +1261,7 @@ A5A8C8382936ED0F00988C88 /* SubQuestEntity+Mapping.swift in Sources */, 34874AA229250C43000570DF /* UIButton+.swift in Sources */, A50F9A3F292679BC005C00FE /* NetworkConfigure.swift in Sources */, + 34404D92293EF75F0007E661 /* SettingsViewModel.swift in Sources */, 34A529E7292481E1001BAD34 /* BrowseCoordinator.swift in Sources */, B5115453292CD07100FDBD22 /* CalendarViewModel.swift in Sources */, 34A529D329247903001BAD34 /* TabCoordinator.swift in Sources */, @@ -1302,6 +1313,7 @@ A50DE906292B53D900E1FD60 /* DefaultQuestsRepository.swift in Sources */, 34ACC32D291DE9C000741371 /* AppDelegate.swift in Sources */, A5AC96D929223648003B7637 /* RealmStorage.swift in Sources */, + 34404D96293EF9E50007E661 /* DefaultSettingsUseCase.swift in Sources */, 3417B1442935DA4A00900454 /* BrowseUseCase.swift in Sources */, A51189C329226E66008A9D33 /* QuestEntity+Mapping.swift in Sources */, A51F01D3292340360031ECA2 /* BrowseQuestsStorage.swift in Sources */, diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift index 0924658..8507bf2 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift @@ -33,6 +33,7 @@ final class LoginViewController: UIViewController { private lazy var passwordField: TextFieldForm = { let passwordField = TextFieldForm() passwordField.placeholder = "password" + passwordField.isSecureTextEntry = true return passwordField }() From df8f8aaf8a66fead5f2e3439c14c4613956ce719 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Tue, 6 Dec 2022 14:17:27 +0900 Subject: [PATCH 12/26] =?UTF-8?q?[feat]=20Logout=20AlertView=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SettingsViewController.swift | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift index c556eea..ff11c38 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SettingsViewController.swift @@ -54,10 +54,34 @@ final class SettingsViewController: UITableViewController { } extension SettingsViewController { - enum Event { - case showLoginFlow + func showAlert(preferredStyle: UIAlertController.Style = .alert, + completion: (() -> Void)? = nil) + { + let title = "로그아웃" + let message = "로그아웃 하시겠습니까?" + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let okAction = UIAlertAction(title: "Ok", style: .default) { [weak self] _ in + self?.signOut() + } + + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) + + alert.addAction(okAction) + alert.addAction(cancelAction) + + self.present(alert, animated: true, completion: completion) } + private func signOut() { + viewModel + .signOut() + .subscribe() + .disposed(by: disposableBag) + } +} + +extension SettingsViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return viewModel.fields.count } @@ -75,10 +99,13 @@ extension SettingsViewController { case .login: itemDidClick.onNext(.showLoginFlow) case .logout: - viewModel - .signOut() - .subscribe() - .disposed(by: disposableBag) + showAlert() } } } + +extension SettingsViewController { + enum Event { + case showLoginFlow + } +} From d325df00af35cdf898f7a940f41bd5827870bec0 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 19:09:16 +0900 Subject: [PATCH 13/26] [style] add discardableResult --- .../Data/PersistentStorages/RealmStorage/RealmStorage.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/DailyQuest/DailyQuest/Data/PersistentStorages/RealmStorage/RealmStorage.swift b/DailyQuest/DailyQuest/Data/PersistentStorages/RealmStorage/RealmStorage.swift index b80ce8a..9b0d0ad 100644 --- a/DailyQuest/DailyQuest/Data/PersistentStorages/RealmStorage/RealmStorage.swift +++ b/DailyQuest/DailyQuest/Data/PersistentStorages/RealmStorage/RealmStorage.swift @@ -77,6 +77,7 @@ final class RealmStorage { return entity } + @discardableResult func deleteAllEntity(type: O.Type) throws -> [O] { guard let persistentContainer = persistentContainer else { print(#function) From 822404782770754abf7b4717f88c838f2e80e885 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 19:11:21 +0900 Subject: [PATCH 14/26] [fix] disposable management --- DailyQuest/DailyQuest.xcodeproj/project.pbxproj | 10 ++-------- .../Data/Repositories/DefaultBrowseRepository.swift | 7 ++----- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj index 11eeac0..4f5e230 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj +++ b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj @@ -105,9 +105,9 @@ 34EE0C662935FD7D002BEC23 /* BrowseItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3499552629235D1E007AB99E /* BrowseItemViewModel.swift */; }; 34EE6EB72924C674005AF583 /* QuestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB62924C674005AF583 /* QuestView.swift */; }; 34EE6EB92924CAA1005AF583 /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; + 34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; }; 34FCD369293DEED600E0DC8A /* FriendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD368293DEED600E0DC8A /* FriendViewController.swift */; }; 34FCD36B293DF2F600E0DC8A /* FriendStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */; }; - 34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; }; 34FEFB992935EA6D00954A40 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 34FEFB982935EA6D00954A40 /* Kingfisher */; }; 34FF6C5A292B86F8002AFD4D /* SnapKit-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */; }; 34FF6C5D292B8B27002AFD4D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C5C292B8B27002AFD4D /* RxCocoa */; }; @@ -149,7 +149,6 @@ A5AC96E629223F06003B7637 /* QuestsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5AC96E529223F06003B7637 /* QuestsStorage.swift */; }; A5AC96E829223F27003B7637 /* RealmQuestsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5AC96E729223F27003B7637 /* RealmQuestsStorage.swift */; }; A5D3C813293DB1BE00F43B76 /* DataConfigure.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D3C812293DB1BE00F43B76 /* DataConfigure.swift */; }; - A5D3C820293DD52B00F43B76 /* RepositoryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D3C81F293DD52B00F43B76 /* RepositoryManager.swift */; }; A5D3C823293DDDAD00F43B76 /* ProtectedUserRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D3C822293DDDAD00F43B76 /* ProtectedUserRepository.swift */; }; A5D3C828293DDEBE00F43B76 /* QuestsRepositoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D3C827293DDEBE00F43B76 /* QuestsRepositoryTests.swift */; }; A5D3C829293DDF8A00F43B76 /* DataConfigure.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D3C812293DB1BE00F43B76 /* DataConfigure.swift */; }; @@ -157,7 +156,6 @@ A5D3C82B293DDF9000F43B76 /* QuestDTO+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B1CFB3E292B585700CCE97A /* QuestDTO+Mapping.swift */; }; A5D3C82C293DDF9200F43B76 /* DTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE910292B74C500E1FD60 /* DTO.swift */; }; A5D3C82D293DDF9400F43B76 /* BrowseQuestDTO+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CCF62935D7BB00E6EA2F /* BrowseQuestDTO+Mapping.swift */; }; - A5D3C82F293DDF9800F43B76 /* RepositoryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D3C81F293DD52B00F43B76 /* RepositoryManager.swift */; }; A5D3C830293DDF9B00F43B76 /* DefaultQuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */; }; A5D3C831293DDF9D00F43B76 /* DefaultAuthRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A517A84529349D91005CB1E8 /* DefaultAuthRepository.swift */; }; A5D3C832293DDFA000F43B76 /* DefaultUserRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A511228F29384FAF00384B4B /* DefaultUserRepository.swift */; }; @@ -307,9 +305,9 @@ 34EE0C632935FD6B002BEC23 /* BrowseViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseViewModelTests.swift; sourceTree = ""; }; 34EE6EB62924C674005AF583 /* QuestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestView.swift; sourceTree = ""; }; 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestViewModel.swift; sourceTree = ""; }; + 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = ""; }; 34FCD368293DEED600E0DC8A /* FriendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendViewController.swift; sourceTree = ""; }; 34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendStatusView.swift; sourceTree = ""; }; - 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = ""; }; 9B1CFB3E292B585700CCE97A /* QuestDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QuestDTO+Mapping.swift"; sourceTree = ""; }; 9BD8CCF22935BC0D00E6EA2F /* DefaultBrowseRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBrowseRepository.swift; sourceTree = ""; }; 9BD8CCF42935C38300E6EA2F /* UserDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDTO+Mapping.swift"; sourceTree = ""; }; @@ -343,7 +341,6 @@ A5AC96E529223F06003B7637 /* QuestsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestsStorage.swift; sourceTree = ""; }; A5AC96E729223F27003B7637 /* RealmQuestsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealmQuestsStorage.swift; sourceTree = ""; }; A5D3C812293DB1BE00F43B76 /* DataConfigure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataConfigure.swift; sourceTree = ""; }; - A5D3C81F293DD52B00F43B76 /* RepositoryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepositoryManager.swift; sourceTree = ""; }; A5D3C822293DDDAD00F43B76 /* ProtectedUserRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtectedUserRepository.swift; sourceTree = ""; }; A5D3C827293DDEBE00F43B76 /* QuestsRepositoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestsRepositoryTests.swift; sourceTree = ""; }; B50078D529222F3F0070AFC4 /* CircleCheckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleCheckView.swift; sourceTree = ""; }; @@ -1013,7 +1010,6 @@ A5AC96D42922356E003B7637 /* Repositories */ = { isa = PBXGroup; children = ( - A5D3C81F293DD52B00F43B76 /* RepositoryManager.swift */, A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */, A517A84529349D91005CB1E8 /* DefaultAuthRepository.swift */, A511228F29384FAF00384B4B /* DefaultUserRepository.swift */, @@ -1279,7 +1275,6 @@ A51F01C82923392F0031ECA2 /* UserInfoStorage.swift in Sources */, 34A529E429248178001BAD34 /* SettingsSceneDIContainer.swift in Sources */, 340A7246293455CE00B26AA6 /* AuthRepository.swift in Sources */, - A5D3C820293DD52B00F43B76 /* RepositoryManager.swift in Sources */, 345687FA2937815900CA51E3 /* QuantityView.swift in Sources */, 342830AA292E12C700AE811B /* SettingsViewController.swift in Sources */, 34A529E029247F1F001BAD34 /* HomeViewController.swift in Sources */, @@ -1342,7 +1337,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A5D3C82F293DDF9800F43B76 /* RepositoryManager.swift in Sources */, A5D3C83C293DDFC400F43B76 /* SubQuestEntity+Mapping.swift in Sources */, A5D3C83D293DDFCC00F43B76 /* QuestEntity.swift in Sources */, A5656452292BB89A0033E763 /* QuestsStorage.swift in Sources */, diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift index 9d79af9..af5f375 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift @@ -12,15 +12,12 @@ final class DefaultBrowseRepository { private let persistentStorage: BrowseQuestsStorage private let networkService: NetworkService - - private let disposeBag: DisposeBag + private let disposeBag: DisposeBag = DisposeBag() init(persistentStorage: BrowseQuestsStorage, - networkService: NetworkService = FirebaseService.shared, - repositoryManager: RepositoryManager = RepositoryManager.shared) { + networkService: NetworkService = FirebaseService.shared) { self.persistentStorage = persistentStorage self.networkService = networkService - self.disposeBag = repositoryManager.disposeBag } } From 329079906225aaf1b18678f89242e969b0c1e636 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 19:48:37 +0900 Subject: [PATCH 15/26] [fix] Firebase Error ignore --- .../DefaultQuestsRepository.swift | 108 ++++++++++-------- 1 file changed, 60 insertions(+), 48 deletions(-) diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultQuestsRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultQuestsRepository.swift index ecfb85b..6b82bf5 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultQuestsRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultQuestsRepository.swift @@ -9,10 +9,10 @@ import RxSwift import Foundation final class DefaultQuestsRepository { - + private let persistentStorage: QuestsStorage private let networkService: NetworkService - + init(persistentStorage: QuestsStorage, networkService: NetworkService = FirebaseService.shared) { self.persistentStorage = persistentStorage self.networkService = networkService @@ -22,74 +22,86 @@ final class DefaultQuestsRepository { extension DefaultQuestsRepository: QuestsRepository { func save(with quest: [Quest]) -> Single<[Quest]> { return persistentStorage.saveQuests(with: quest) - .flatMap { quests in - return Observable.from(quests) - .withUnretained(self) - .concatMap { (owner, quest) in - return owner.networkService.create(userCase: .currentUser, - access: .quests, - dto: quest.toDTO()) - .map { $0.toDomain() } - .catchAndReturn(quest) - } - .toArray() + .flatMap (saveNetworkService(quests:)) + .do{ event in + print("save", event) } } - + func fetch(by date: Date) -> Observable<[Quest]> { return persistentStorage.fetchQuests(by: date) - .catch { _ in - self.networkService.read(type: QuestDTO.self, userCase: .currentUser, access: .quests, filter: .today(date)) - .map { $0.toDomain() } - .toArray() - .asObservable() - } + .catch { [weak self] _ in + guard let self = self else { return Observable.just([]) } + return self.fetchNetworkService(date: date) + } + .catchAndReturn([]) } - + func update(with quest: Quest) -> Single { return persistentStorage.updateQuest(with: quest) .flatMap(updateNetworkService(quest:)) } - + func delete(with questId: UUID) -> Single { return persistentStorage.deleteQuest(with: questId) - .flatMap { quest in - self.networkService.delete(userCase: .currentUser, access: .quests, dto: quest.toDTO()) - } - .map { $0.toDomain() } - .asObservable() - .asSingle() + .flatMap(deleteNetworkService(quest:)) } - + func deleteAll(with groupId: UUID) -> Single<[Quest]> { return persistentStorage.deleteQuestGroup(with: groupId) - .flatMap { quests in - return Observable.from(quests) - .concatMap { quest in - self.networkService.delete(userCase: .currentUser, - access: .quests, - dto: quest.toDTO()) - } - .map { $0.toDomain() } - .toArray() - } + .flatMap(deleteAllNetworkService(quests:)) } - - func fetch(by uuid: String, date: Date) -> Observable<[Quest]> { // 받을 날짜까지 받아와야함 - return self.networkService.read(type: QuestDTO.self, - userCase: .anotherUser(uuid), - access: .quests, - filter: .today(date)) - .map { $0.toDomain() } - .toArray() - .asObservable() + + func fetch(by uuid: String, date: Date) -> Observable<[Quest]> { + return networkService.read(type: QuestDTO.self, + userCase: .anotherUser(uuid), + access: .quests, + filter: .today(date)) + .map { $0.toDomain() } + .toArray() + .asObservable() } } private extension DefaultQuestsRepository { + func saveNetworkService(quests: [Quest]) -> Single<[Quest]> { + return Observable.from(quests) + .withUnretained(self) + .concatMap { (owner, quest) in + return owner.networkService.create(userCase: .currentUser, + access: .quests, + dto: quest.toDTO()) + .map { $0.toDomain() } + .catchAndReturn(quest) + } + .toArray() + } + + func fetchNetworkService(date: Date) -> Observable<[Quest]> { + return networkService.read(type: QuestDTO.self, userCase: .currentUser, access: .quests, filter: .today(date)) + .map { $0.toDomain() } + .toArray() + .asObservable() + .catchAndReturn([]) + } + func updateNetworkService(quest: Quest) -> Single { return networkService.update(userCase: .currentUser, access: .quests, dto: quest.toDTO()) .map { $0.toDomain() } .catchAndReturn(quest) } + + func deleteNetworkService(quest: Quest) -> Single { + self.networkService.delete(userCase: .currentUser, access: .quests, dto: quest.toDTO()) + .map { $0.toDomain() } + .catchAndReturn(quest) + } + + func deleteAllNetworkService(quests: [Quest]) -> Single<[Quest]> { + Observable.from(quests) + .concatMap(deleteNetworkService(quest:)) + .toArray() + .catchAndReturn(quests) + } + } From e94c99a53ee9e5a4d62e6fd2a63652e0f33d744c Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 19:58:44 +0900 Subject: [PATCH 16/26] [fix] UserRepository Firebase Error ignore --- .../DefaultBrowseRepository.swift | 2 +- .../Repositories/DefaultUserRepository.swift | 39 ++++++++++++------- .../DailyQuest/Domain/Entities/User.swift | 20 ++++++++++ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift index af5f375..414192e 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift @@ -27,7 +27,7 @@ extension DefaultBrowseRepository: BrowseRepository { /// Firebase 우선, 실패시 persistentStorage, persistentStorage도 실패시 Error반환 /// - Returns: Observable<[BrowseQuest]> func fetch() -> Observable<[BrowseQuest]> { - return self.networkService.getAllowUsers(limit: 10) + return networkService.getAllowUsers(limit: 10) .map { $0.toDomain() } .flatMap { user in self.networkService diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift index 71994d1..28e4797 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift @@ -21,32 +21,28 @@ final class DefaultUserRepository { extension DefaultUserRepository: UserRepository { func isLoggedIn() -> BehaviorRelay { - return self.networkService.uid + return networkService.uid } func readUser() -> Observable { return self.persistentStorage.fetchUserInfo() - .catch { _ in - return self.networkService.read(type: UserDTO.self, userCase: .currentUser, access: .userInfo, filter: nil) - .map { $0.toDomain() } + .catch { [weak self] _ in + guard let self = self else { return Observable.just(User()) } + return self.fetchUserNetworkService() } } func updateUser(by user: User) -> Observable { - return self.persistentStorage.updateUserInfo(user: user) + return persistentStorage.updateUserInfo(user: user) .asObservable() - .concatMap { _ in - return self.networkService.update(userCase: .currentUser, access: .userInfo, dto: user.toDTO()) - .map { $0.toDomain() } - .asObservable() - } + .flatMap(updateUserNetworkService(user:)) } func fetchUser(by uuid: String) -> Observable { - return self.networkService.read(type: UserDTO.self, - userCase: .anotherUser(uuid), - access: .userInfo, - filter: nil) + return networkService.read(type: UserDTO.self, + userCase: .anotherUser(uuid), + access: .userInfo, + filter: nil) .map { $0.toDomain() } } } @@ -62,3 +58,18 @@ extension DefaultUserRepository: ProtectedUserRepository { } } } + +private extension DefaultUserRepository { + func fetchUserNetworkService() -> Observable { + networkService.read(type: UserDTO.self, userCase: .currentUser, access: .userInfo, filter: nil) + .map { $0.toDomain() } + } + + func updateUserNetworkService(user: User) -> Observable { + networkService.update(userCase: .currentUser, access: .userInfo, dto: user.toDTO()) + .map { $0.toDomain() } + .asObservable() + .catchAndReturn(user) + } +} + diff --git a/DailyQuest/DailyQuest/Domain/Entities/User.swift b/DailyQuest/DailyQuest/Domain/Entities/User.swift index 68763cf..ebf0dd8 100644 --- a/DailyQuest/DailyQuest/Domain/Entities/User.swift +++ b/DailyQuest/DailyQuest/Domain/Entities/User.swift @@ -14,4 +14,24 @@ struct User { let backgroundImageURL: String let description: String let allow: Bool + + init(){ + self.uuid = "" + self.nickName = "" + self.profileURL = "" + self.backgroundImageURL = "" + self.description = "" + self.allow = false + } + + init(uuid: String, nickName: String, profileURL: String, backgroundImageURL: String, description: String, allow: Bool) { + self.uuid = uuid + self.nickName = nickName + self.profileURL = profileURL + self.backgroundImageURL = backgroundImageURL + self.description = description + self.allow = allow + } + + } From a4903307d387b990e08f6aee46e8e86a0e1f10b6 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 20:18:01 +0900 Subject: [PATCH 17/26] [fix] BrowseRepository --- .../DefaultBrowseRepository.swift | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift index 414192e..7d2568a 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultBrowseRepository.swift @@ -27,38 +27,41 @@ extension DefaultBrowseRepository: BrowseRepository { /// Firebase 우선, 실패시 persistentStorage, persistentStorage도 실패시 Error반환 /// - Returns: Observable<[BrowseQuest]> func fetch() -> Observable<[BrowseQuest]> { - return networkService.getAllowUsers(limit: 10) + return self.networkService.getAllowUsers(limit: 10) .map { $0.toDomain() } - .flatMap { user in - self.networkService - .read(type: QuestDTO.self, userCase: .anotherUser(user.uuid), access: .quests, filter: .today(Date())) - .map { $0.toDomain() } - .toArray() - .asObservable() - .map { questList in - return BrowseQuest(user: user, quests: questList) - } - } - + .flatMap(fetchBrowseQuestNetworkService(user:)) .filter { !$0.quests.isEmpty } .toArray() .asObservable() - .do(afterNext: { browseQuests in + .do(afterNext: { [weak self] browseQuests in + guard let self = self else { return } self.persistentStorage.deleteBrowseQuests() .asObservable() .concatMap { _ in Observable.from(browseQuests) - .flatMap { browseQuest in - self.persistentStorage.saveBrowseQuest(browseQuest: browseQuest) - .asObservable() - } + .flatMap (self.saveBrowseQuestPersistentStorage(browseQuest:)) } - .subscribe(onError: { error in - print(error) - }).disposed(by: self.disposeBag) + .subscribe() + .disposed(by: self.disposeBag) }) .catch { error in return self.persistentStorage.fetchBrowseQuests() } } } + +private extension DefaultBrowseRepository { + func fetchBrowseQuestNetworkService(user: User) -> Observable { + networkService + .read(type: QuestDTO.self, userCase: .anotherUser(user.uuid), access: .quests, filter: .today(Date())) + .map { $0.toDomain() } + .toArray() + .asObservable() + .map { return BrowseQuest(user: user, quests: $0) } + } + + func saveBrowseQuestPersistentStorage(browseQuest: BrowseQuest) -> Observable { + persistentStorage.saveBrowseQuest(browseQuest: browseQuest) + .asObservable() + } +} From defca3a3ab04ce9b35409037512573c484d6c1d7 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 21:08:05 +0900 Subject: [PATCH 18/26] [feat] add SignUp Logic --- .../DailyQuest.xcodeproj/project.pbxproj | 12 +- .../Network/DataMapping/UserDTO+Mapping.swift | 9 ++ .../Repositories/DefaultAuthRepository.swift | 4 + .../Repositories/AuthRepository.swift | 8 ++ .../Settings/DefaultAuthUseCase.swift | 21 +++- .../Settings/Protocols/AuthUseCase.swift | 1 + .../FirebaseService/FirebaseService.swift | 90 ++++++++++----- .../Infrastructure/NetworkService.swift | 5 +- .../ViewController/SignUpViewController.swift | 106 ++++++++++++++++++ .../Settings/ViewModel/SignUpViewModel.swift | 47 ++++++++ 10 files changed, 264 insertions(+), 39 deletions(-) create mode 100644 DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift create mode 100644 DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift diff --git a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj index 11eeac0..b1be6c0 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj +++ b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj @@ -105,9 +105,9 @@ 34EE0C662935FD7D002BEC23 /* BrowseItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3499552629235D1E007AB99E /* BrowseItemViewModel.swift */; }; 34EE6EB72924C674005AF583 /* QuestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB62924C674005AF583 /* QuestView.swift */; }; 34EE6EB92924CAA1005AF583 /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; + 34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; }; 34FCD369293DEED600E0DC8A /* FriendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD368293DEED600E0DC8A /* FriendViewController.swift */; }; 34FCD36B293DF2F600E0DC8A /* FriendStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */; }; - 34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; }; 34FEFB992935EA6D00954A40 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 34FEFB982935EA6D00954A40 /* Kingfisher */; }; 34FF6C5A292B86F8002AFD4D /* SnapKit-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */; }; 34FF6C5D292B8B27002AFD4D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C5C292B8B27002AFD4D /* RxCocoa */; }; @@ -121,6 +121,8 @@ 9BD8CCFB2937407100E6EA2F /* FollowingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CCFA2937407100E6EA2F /* FollowingCell.swift */; }; 9BD8CD00293829DD00E6EA2F /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CCFF293829DD00E6EA2F /* FollowingView.swift */; }; 9BD8CD022938418500E6EA2F /* LastFollowingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */; }; + A5003AB4293F5FEC00082A9C /* SignUpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */; }; + A5003AB6293F601E00082A9C /* SignUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003AB5293F601E00082A9C /* SignUpViewController.swift */; }; A50DE906292B53D900E1FD60 /* DefaultQuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */; }; A50DE90B292B73B900E1FD60 /* FirebaseDatabaseSwift in Frameworks */ = {isa = PBXBuildFile; productRef = A50DE90A292B73B900E1FD60 /* FirebaseDatabaseSwift */; }; A50DE911292B74C500E1FD60 /* DTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE910292B74C500E1FD60 /* DTO.swift */; }; @@ -307,9 +309,9 @@ 34EE0C632935FD6B002BEC23 /* BrowseViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseViewModelTests.swift; sourceTree = ""; }; 34EE6EB62924C674005AF583 /* QuestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestView.swift; sourceTree = ""; }; 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestViewModel.swift; sourceTree = ""; }; + 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = ""; }; 34FCD368293DEED600E0DC8A /* FriendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendViewController.swift; sourceTree = ""; }; 34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendStatusView.swift; sourceTree = ""; }; - 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = ""; }; 9B1CFB3E292B585700CCE97A /* QuestDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QuestDTO+Mapping.swift"; sourceTree = ""; }; 9BD8CCF22935BC0D00E6EA2F /* DefaultBrowseRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBrowseRepository.swift; sourceTree = ""; }; 9BD8CCF42935C38300E6EA2F /* UserDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDTO+Mapping.swift"; sourceTree = ""; }; @@ -317,6 +319,8 @@ 9BD8CCFA2937407100E6EA2F /* FollowingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingCell.swift; sourceTree = ""; }; 9BD8CCFF293829DD00E6EA2F /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = ""; }; 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastFollowingCell.swift; sourceTree = ""; }; + A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewModel.swift; sourceTree = ""; }; + A5003AB5293F601E00082A9C /* SignUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewController.swift; sourceTree = ""; }; A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultQuestsRepository.swift; sourceTree = ""; }; A50DE910292B74C500E1FD60 /* DTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DTO.swift; sourceTree = ""; }; A50F9A3329266F45005C00FE /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; @@ -426,6 +430,7 @@ isa = PBXGroup; children = ( 34113BE72934917500AB4919 /* LoginViewModel.swift */, + A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -525,6 +530,7 @@ children = ( 342830A9292E12C700AE811B /* SettingsViewController.swift */, 34113BEA2934A3B200AB4919 /* LoginViewController.swift */, + A5003AB5293F601E00082A9C /* SignUpViewController.swift */, ); path = ViewController; sourceTree = ""; @@ -1263,6 +1269,7 @@ 34CAE318292B19A3007653AD /* QuestsRepository.swift in Sources */, A50DE911292B74C500E1FD60 /* DTO.swift in Sources */, 3449AD5D2922197000B87619 /* User.swift in Sources */, + A5003AB6293F601E00082A9C /* SignUpViewController.swift in Sources */, 9BD8CCF52935C38300E6EA2F /* UserDTO+Mapping.swift in Sources */, A51F01CD29233ABB0031ECA2 /* RealmUserInfoStorage.swift in Sources */, B5833F732924C08900503E0D /* CalendarView.swift in Sources */, @@ -1328,6 +1335,7 @@ 34283101292E2D7A00AE811B /* ToggleItemViewModel.swift in Sources */, 34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */, A5AC96E829223F27003B7637 /* RealmQuestsStorage.swift in Sources */, + A5003AB4293F5FEC00082A9C /* SignUpViewModel.swift in Sources */, 345687F829374D2500CA51E3 /* DayNamePickerView.swift in Sources */, 349955122923220E007AB99E /* SwiftUIPreview.swift in Sources */, 9BD8CD022938418500E6EA2F /* LastFollowingCell.swift in Sources */, diff --git a/DailyQuest/DailyQuest/Data/Network/DataMapping/UserDTO+Mapping.swift b/DailyQuest/DailyQuest/Data/Network/DataMapping/UserDTO+Mapping.swift index db2f680..7adf2f9 100644 --- a/DailyQuest/DailyQuest/Data/Network/DataMapping/UserDTO+Mapping.swift +++ b/DailyQuest/DailyQuest/Data/Network/DataMapping/UserDTO+Mapping.swift @@ -32,6 +32,15 @@ struct UserDTO: DTO { self.description = user.description self.allow = user.allow } + + init(uuid: String, userDto: UserDTO) { + self.uuid = uuid + self.nickName = userDto.nickName + self.profileURL = userDto.profileURL + self.backgroundImageURL = userDto.backgroundImageURL + self.description = userDto.description + self.allow = userDto.allow + } } extension UserDTO { diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultAuthRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultAuthRepository.swift index a3cc947..03b2d45 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultAuthRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultAuthRepository.swift @@ -25,4 +25,8 @@ extension DefaultAuthRepository: AuthRepository { func signOut() -> Single { return self.networkService.signOut() } + + func signUp(email: String, password: String, user: User) -> Single { + return self.networkService.signUp(email: email, password: password, userDto: user.toDTO()) + } } diff --git a/DailyQuest/DailyQuest/Domain/Interfaces/Repositories/AuthRepository.swift b/DailyQuest/DailyQuest/Domain/Interfaces/Repositories/AuthRepository.swift index 75b6b65..71640aa 100644 --- a/DailyQuest/DailyQuest/Domain/Interfaces/Repositories/AuthRepository.swift +++ b/DailyQuest/DailyQuest/Domain/Interfaces/Repositories/AuthRepository.swift @@ -19,4 +19,12 @@ protocol AuthRepository { /// 로그아웃 동작을 수행합니다. /// - Returns: 성공하면 true를, 실패하면 error을 방출하는 Observable을 반환합니다. func signOut() -> Single + + /// 회원가입 동작을 수행합니다. + /// - Parameters: + /// - email: 사용자의 email 입니다. + /// - password: 사용자의 password입니다. + /// - user: 사용자의 정보입니다. + /// - Returns: 성공하면 true를, 실패하면 error를 방출하는 Observable을 반환합니다. + func signUp(email: String, password: String, user: User) -> Single } diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultAuthUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultAuthUseCase.swift index 14abcd7..1ca3c0f 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultAuthUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultAuthUseCase.swift @@ -11,7 +11,7 @@ import RxSwift final class DefaultAuthUseCase { private let authRepository: AuthRepository - + init(authRepository: AuthRepository) { self.authRepository = authRepository } @@ -22,17 +22,26 @@ extension DefaultAuthUseCase: AuthUseCase { return authRepository .signIn(email: email, password: password) .catch { _ in - return .just(false) - } + return .just(false) + } .asObservable() } - + func signOut() -> Observable { return authRepository .signOut() .catch { _ in - return .just(false) - } + return .just(false) + } + .asObservable() + } + + func signUp(email: String, password: String, user: User) -> Observable { + return authRepository + .signUp(email: email, password: password, user: user) + .catch { _ in + return .just(false) + } .asObservable() } } diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/AuthUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/AuthUseCase.swift index d1859ed..f4c9067 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/AuthUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/AuthUseCase.swift @@ -12,4 +12,5 @@ import RxSwift protocol AuthUseCase { func signIn(email: String, password: String) -> Observable func signOut() -> Observable + func signUp(email: String, password: String, user: User) -> Observable } diff --git a/DailyQuest/DailyQuest/Infrastructure/FirebaseService/FirebaseService.swift b/DailyQuest/DailyQuest/Infrastructure/FirebaseService/FirebaseService.swift index e619f15..c727d0b 100644 --- a/DailyQuest/DailyQuest/Infrastructure/FirebaseService/FirebaseService.swift +++ b/DailyQuest/DailyQuest/Infrastructure/FirebaseService/FirebaseService.swift @@ -29,36 +29,9 @@ final class FirebaseService: NetworkService { uid.accept(auth.currentUser?.uid) } - @discardableResult - private func documentReference(userCase: UserCase) throws -> DocumentReference { - switch userCase { - case .currentUser: - guard let currentUserUid = uid.value else { throw NetworkServiceError.noAuthError } - return db.collection(userCase.path).document(currentUserUid) - case let .anotherUser(uid): - return db.collection(userCase.path).document(uid) - } - } - - private func checkPermission(crud: CRUD, userCase: UserCase, access: Access) throws { - switch userCase { - case .currentUser: - switch access { - case .receiveQuests: - if crud == .create { throw NetworkServiceError.permissionDenied } - default: - break - } - case .anotherUser: - switch access { - case .receiveQuests: - if crud == .delete { throw NetworkServiceError.permissionDenied } - default: - if crud != .read { throw NetworkServiceError.permissionDenied } - } - } - } +} +extension FirebaseService { func signIn(email: String, password: String) -> Single { return Single.create { [weak self] single in do { @@ -93,6 +66,65 @@ final class FirebaseService: NetworkService { } } + func signUp(email: String, password: String, userDto: UserDTO) -> Single { + return Single.create { [weak self] single in + guard let self = self else { + single(.failure(NetworkServiceError.noNetworkService)) + return Disposables.create() + } + + self.auth.createUser(withEmail: email, password: password) { authResult, error in + do { + if let error = error { throw error } + guard let authResult = authResult else { throw NetworkServiceError.noAuthError } + try self.createUser(uuid: authResult.user.uid, userDto: userDto) + single(.success(true)) + } catch let error { + single(.failure(error)) + } + } + return Disposables.create() + } + } + + func createUser(uuid: String, userDto: UserDTO) throws { + let userDto = UserDTO(uuid: uuid, userDto: userDto) + try db.collection(UserCase.currentUser.path).document(uuid) + .setData(from: userDto) + } +} + +extension FirebaseService { + @discardableResult + private func documentReference(userCase: UserCase) throws -> DocumentReference { + switch userCase { + case .currentUser: + guard let currentUserUid = uid.value else { throw NetworkServiceError.noAuthError } + return db.collection(userCase.path).document(currentUserUid) + case let .anotherUser(uid): + return db.collection(userCase.path).document(uid) + } + } + + private func checkPermission(crud: CRUD, userCase: UserCase, access: Access) throws { + switch userCase { + case .currentUser: + switch access { + case .receiveQuests: + if crud == .create { throw NetworkServiceError.permissionDenied } + default: + break + } + case .anotherUser: + switch access { + case .receiveQuests: + if crud == .delete { throw NetworkServiceError.permissionDenied } + default: + if crud != .read { throw NetworkServiceError.permissionDenied } + } + } + } + /// Create /// - Parameters: /// - userCase: current User / another User diff --git a/DailyQuest/DailyQuest/Infrastructure/NetworkService.swift b/DailyQuest/DailyQuest/Infrastructure/NetworkService.swift index d101564..fff6537 100644 --- a/DailyQuest/DailyQuest/Infrastructure/NetworkService.swift +++ b/DailyQuest/DailyQuest/Infrastructure/NetworkService.swift @@ -23,6 +23,7 @@ protocol NetworkService { func signIn(email: String, password: String) -> Single func signOut() -> Single + func signUp(email: String, password: String, userDto: UserDTO) -> Single func create(userCase: UserCase, access: Access, dto: T) -> Single func read(type: T.Type, userCase: UserCase, access: Access, filter: DateFilter?) -> Observable @@ -32,6 +33,6 @@ protocol NetworkService { func uploadDataStorage(data: Data, path: StoragePath) -> Single func downloadDataStorage(fileName: String) -> Single func deleteDataStorage(fileName: String) -> Single - - func getAllowUsers(limit: Int)->Observable + + func getAllowUsers(limit: Int) -> Observable } diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift new file mode 100644 index 0000000..3566794 --- /dev/null +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift @@ -0,0 +1,106 @@ +// +// SignUpViewController.swift +// DailyQuest +// +// Created by 이전희 on 2022/12/06. +// + +import UIKit + +import RxSwift +import RxCocoa +import SnapKit + +final class SignUpViewController: UIViewController { + private var viewModel: LoginViewModel! + private var disposableBag = DisposeBag() + + private lazy var container: UIStackView = { + let container = UIStackView() + container.axis = .vertical + container.spacing = 10 + + return container + }() + + private lazy var emailField: TextFieldForm = { + let emailField = TextFieldForm() + emailField.placeholder = "email" + + return emailField + }() + + private lazy var passwordField: TextFieldForm = { + let passwordField = TextFieldForm() + passwordField.placeholder = "password" + + return passwordField + }() + + private lazy var submitButton: UIButton = { + var config = UIButton.Configuration.filled() + config.baseBackgroundColor = .maxYellow + config.title = "로그인" + + return UIButton(configuration: config) + }() + + // MARK: Life Cycle + static func create(with viewModel: LoginViewModel) -> LoginViewController { + let vc = LoginViewController() + vc.setup(with: viewModel) + + return vc + } + + override func viewDidLoad() { + super.viewDidLoad() + + configureUI() + + bind() + } + + private func configureUI() { + view.backgroundColor = .white + + container.addArrangedSubview(emailField) + container.addArrangedSubview(passwordField) + container.addArrangedSubview(submitButton) + + view.addSubview(container) + + container.snp.makeConstraints { make in + make.center.equalToSuperview() + make.width.equalToSuperview().multipliedBy(0.8) + } + } + + private func setup(with authViewModel: LoginViewModel) { + viewModel = authViewModel + } +} + +extension LoginViewController { + private func bind() { + let input = LoginViewModel.Input( + emailFieldDidEditEvent: emailField.rx.text.orEmpty.asObservable(), + passwordFieldDidEditEvent: passwordField.rx.text.orEmpty.asObservable(), + submitButtonDidTapEvent: submitButton.rx.tap.asObservable() + ) + + let output = viewModel.transform(input: input, disposeBag: disposableBag) + + output + .buttonEnabled + .drive(submitButton.rx.isEnabled) + .disposed(by: disposableBag) + + output + .loginResult + .subscribe(onNext: { result in + print("login result is :::: ", result) + }) + .disposed(by: disposableBag) + } +} diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift new file mode 100644 index 0000000..eab6306 --- /dev/null +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift @@ -0,0 +1,47 @@ +// +// SignUpViewModel.swift +// DailyQuest +// +// Created by 이전희 on 2022/12/06. +// + +import Foundation + +import RxSwift +import RxCocoa + +final class SignUpViewModel { + private let authUseCase: AuthUseCase + + init(authUseCase: AuthUseCase) { + self.authUseCase = authUseCase + } + + struct Input { + let emailFieldDidEditEvent: Observable + let passwordFieldDidEditEvent: Observable + let submitButtonDidTapEvent: Observable + } + + struct Output { + let buttonEnabled: Driver + let loginResult: Observable + } + + func transform(input: Input, disposeBag: DisposeBag) -> Output { + let buttonEnabled = Observable + .combineLatest(input.emailFieldDidEditEvent, + input.passwordFieldDidEditEvent) { !$0.isEmpty && !$1.isEmpty } + .asDriver(onErrorJustReturn: false) + + let loginResult = input + .submitButtonDidTapEvent + .withLatestFrom(Observable + .combineLatest(input.emailFieldDidEditEvent, + input.passwordFieldDidEditEvent)) + .flatMap(authUseCase.signIn(email:password:)) + + return Output(buttonEnabled: buttonEnabled, loginResult: loginResult) + } +} + From 81bdc95eb561fb5309058b5f21cd45dc8f266376 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 22:56:01 +0900 Subject: [PATCH 19/26] [feat] SignUpView --- .../DailyQuest/Domain/Entities/User.swift | 9 ++ .../ViewController/SignUpViewController.swift | 101 ++++++++++++------ .../Settings/ViewModel/SignUpViewModel.swift | 48 ++++++--- 3 files changed, 111 insertions(+), 47 deletions(-) diff --git a/DailyQuest/DailyQuest/Domain/Entities/User.swift b/DailyQuest/DailyQuest/Domain/Entities/User.swift index ebf0dd8..32ee39d 100644 --- a/DailyQuest/DailyQuest/Domain/Entities/User.swift +++ b/DailyQuest/DailyQuest/Domain/Entities/User.swift @@ -24,6 +24,15 @@ struct User { self.allow = false } + init(nickName: String){ + self.uuid = "" + self.nickName = nickName + self.profileURL = "" + self.backgroundImageURL = "" + self.description = "" + self.allow = false + } + init(uuid: String, nickName: String, profileURL: String, backgroundImageURL: String, description: String, allow: Bool) { self.uuid = uuid self.nickName = nickName diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift index 3566794..d8cc70d 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift @@ -12,95 +12,128 @@ import RxCocoa import SnapKit final class SignUpViewController: UIViewController { - private var viewModel: LoginViewModel! + private var viewModel: SignUpViewModel! private var disposableBag = DisposeBag() - + private lazy var container: UIStackView = { let container = UIStackView() container.axis = .vertical container.spacing = 10 - + return container }() - + private lazy var emailField: TextFieldForm = { let emailField = TextFieldForm() emailField.placeholder = "email" - + return emailField }() - + private lazy var passwordField: TextFieldForm = { let passwordField = TextFieldForm() passwordField.placeholder = "password" - + passwordField.isSecureTextEntry = true return passwordField }() - + + private lazy var passwordConfirmField: TextFieldForm = { + let passwordConfirmField = TextFieldForm() + passwordConfirmField.placeholder = "password 확인" + passwordField.isSecureTextEntry = true + return passwordConfirmField + }() + + private lazy var nickNameField: TextFieldForm = { + let nickNameField = TextFieldForm() + nickNameField.placeholder = "닉네임" + + return nickNameField + }() + private lazy var submitButton: UIButton = { var config = UIButton.Configuration.filled() config.baseBackgroundColor = .maxYellow - config.title = "로그인" - + config.title = "회원가입" + return UIButton(configuration: config) }() - + // MARK: Life Cycle - static func create(with viewModel: LoginViewModel) -> LoginViewController { - let vc = LoginViewController() + static func create(with viewModel: LoginViewModel) -> SignUpViewController { + let vc = SignUpViewController() vc.setup(with: viewModel) - return vc } - + override func viewDidLoad() { super.viewDidLoad() - + configureUI() - + bind() } - + private func configureUI() { view.backgroundColor = .white - - container.addArrangedSubview(emailField) - container.addArrangedSubview(passwordField) - container.addArrangedSubview(submitButton) - + + [emailField, + passwordField, + passwordConfirmField, + nickNameField, + submitButton].forEach { field in + container.addArrangedSubview(view) + } + view.addSubview(container) - + container.snp.makeConstraints { make in make.center.equalToSuperview() make.width.equalToSuperview().multipliedBy(0.8) } } - - private func setup(with authViewModel: LoginViewModel) { + + private func setup(with authViewModel: SignUpViewModel) { viewModel = authViewModel } } -extension LoginViewController { +extension SignUpViewController { private func bind() { - let input = LoginViewModel.Input( + let input = SignUpViewModel.Input( emailFieldDidEditEvent: emailField.rx.text.orEmpty.asObservable(), passwordFieldDidEditEvent: passwordField.rx.text.orEmpty.asObservable(), + passwordConfirmFieldDidEditEvent: passwordConfirmField.rx.text.orEmpty.asObservable(), + nickNameFieldDidEditEvent: nickNameField.rx.text.orEmpty.asObservable(), submitButtonDidTapEvent: submitButton.rx.tap.asObservable() ) - + let output = viewModel.transform(input: input, disposeBag: disposableBag) - + output .buttonEnabled .drive(submitButton.rx.isEnabled) .disposed(by: disposableBag) - + output - .loginResult + .signUpResult .subscribe(onNext: { result in - print("login result is :::: ", result) - }) + print("SignUp result is :::: ", result) + }) .disposed(by: disposableBag) } } + +#if canImport(SwiftUI) && DEBUG +import SwiftUI + +struct SignUpViewControllerPreview: PreviewProvider{ + static var previews: some View { + UIViewPreview { + let view = SignUpViewController().view! + return view + } + .previewLayout(.fixed(width: 500, height: 100)) + } +} +#endif diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift index eab6306..aea4127 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift @@ -12,36 +12,58 @@ import RxCocoa final class SignUpViewModel { private let authUseCase: AuthUseCase - + init(authUseCase: AuthUseCase) { self.authUseCase = authUseCase } - + struct Input { let emailFieldDidEditEvent: Observable let passwordFieldDidEditEvent: Observable + let passwordConfirmFieldDidEditEvent: Observable + let nickNameFieldDidEditEvent: Observable let submitButtonDidTapEvent: Observable } - + struct Output { let buttonEnabled: Driver - let loginResult: Observable + let signUpResult: Observable } - + func transform(input: Input, disposeBag: DisposeBag) -> Output { let buttonEnabled = Observable .combineLatest(input.emailFieldDidEditEvent, - input.passwordFieldDidEditEvent) { !$0.isEmpty && !$1.isEmpty } + input.passwordFieldDidEditEvent, + input.passwordConfirmFieldDidEditEvent, + input.nickNameFieldDidEditEvent, + resultSelector: checkButtonEnble(emailText: passwordText: passwordConfirmText: nickName:)) .asDriver(onErrorJustReturn: false) - - let loginResult = input + + let signUpResult = input .submitButtonDidTapEvent .withLatestFrom(Observable - .combineLatest(input.emailFieldDidEditEvent, - input.passwordFieldDidEditEvent)) - .flatMap(authUseCase.signIn(email:password:)) - - return Output(buttonEnabled: buttonEnabled, loginResult: loginResult) + .combineLatest(input.emailFieldDidEditEvent, + input.passwordFieldDidEditEvent, + input.nickNameFieldDidEditEvent, + resultSelector: { ($0, $1, User(nickName: $2)) })) + .flatMap (authUseCase.signUp(email:password:user:)) + + return Output(buttonEnabled: buttonEnabled, signUpResult: signUpResult) + } + + func checkEmpty(_ strArray: [String]) -> Bool { + return !strArray.reduce(false) { $0 || $1.isEmpty } + } + + func checkSame(str1: String, str2: String) -> Bool { + return str1 == str2 + } + + func checkButtonEnble(emailText: String, + passwordText: String, + passwordConfirmText: String, + nickName: String) -> Bool { + return checkEmpty([emailText, passwordText, passwordConfirmText, nickName]) && checkSame(str1: passwordText, str2: passwordConfirmText) } } From 7ab25b3cc1f3fb9fa3e3c726639ce9d0577cdb6f Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 22:56:42 +0900 Subject: [PATCH 20/26] [fix] SignUpViewModel --- .../ViewController/SignUpViewController.swift | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift index d8cc70d..a69f066 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift @@ -60,7 +60,7 @@ final class SignUpViewController: UIViewController { }() // MARK: Life Cycle - static func create(with viewModel: LoginViewModel) -> SignUpViewController { + static func create(with viewModel: SignUpViewModel) -> SignUpViewController { let vc = SignUpViewController() vc.setup(with: viewModel) return vc @@ -123,17 +123,3 @@ extension SignUpViewController { .disposed(by: disposableBag) } } - -#if canImport(SwiftUI) && DEBUG -import SwiftUI - -struct SignUpViewControllerPreview: PreviewProvider{ - static var previews: some View { - UIViewPreview { - let view = SignUpViewController().view! - return view - } - .previewLayout(.fixed(width: 500, height: 100)) - } -} -#endif From dbe81b9da39b2437ee6a7c36d166b6c421ff90d5 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 22:59:59 +0900 Subject: [PATCH 21/26] [feat] connect SignUpViewController Flow --- .../DIContainer/SettingsSceneDIContainer.swift | 8 ++++++++ .../Presentation/Settings/Flow/SettingsCoordinator.swift | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift b/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift index a61a0e6..479151e 100644 --- a/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift +++ b/DailyQuest/DailyQuest/Application/DIContainer/SettingsSceneDIContainer.swift @@ -24,11 +24,19 @@ final class SettingsSceneDIContainer { return LoginViewModel(authUseCase: makeAuthUseCase()) } + func makeSignUpViewModel() -> SignUpViewModel { + return SignUpViewModel(authUseCase: makeAuthUseCase()) + } + // MARK: - View Controller func makeLoginViewController() -> LoginViewController { return LoginViewController.create(with: makeLoginViewModel()) } + func makeSignUpViewController() -> SignUpViewController { + return SignUpViewController.create(with: makeSignUpViewModel()) + } + // MARK: - Flow func makeSettingsCoordinator(navigationController: UINavigationController, settingsSceneDIContainer: SettingsSceneDIContainer) -> SettingsCoordinator { diff --git a/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift b/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift index 6775f3d..2da0399 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift @@ -46,4 +46,9 @@ final class DefaultSettingsCoordinator: SettingsCoordinator { let loginViewController = settingsSceneDIContainer.makeLoginViewController() navigationController.pushViewController(loginViewController, animated: true) } + + func showSignUpFlow() { + let signUpViewControllser = settingsSceneDIContainer.makeSignUpViewController() + navigationController.pushViewController(signUpViewControllser, animated: true) + } } From f94979963966e1b884c69b5cd7c9c315a50e50e8 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 23:28:11 +0900 Subject: [PATCH 22/26] [feat] connect sign up view --- .../Settings/Flow/SettingsCoordinator.swift | 36 ++++++---- .../ViewController/LoginViewController.swift | 66 ++++++++++++------- .../ViewController/SignUpViewController.swift | 16 +++-- 3 files changed, 75 insertions(+), 43 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift b/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift index 2da0399..caef78e 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/Flow/SettingsCoordinator.swift @@ -15,40 +15,50 @@ protocol SettingsCoordinator: Coordinator { final class DefaultSettingsCoordinator: SettingsCoordinator { private var disposableBag = DisposeBag() - + var finishDelegate: CoordinatorFinishDelegate? var childCoordinators: [Coordinator] = [] var navigationController: UINavigationController let settingsSceneDIContainer: SettingsSceneDIContainer - + init(navigationController: UINavigationController, settingsSceneDIContainer: SettingsSceneDIContainer) { self.navigationController = navigationController self.settingsSceneDIContainer = settingsSceneDIContainer } - + func start() { let settingsController = SettingsViewController() navigationController.pushViewController(settingsController, animated: false) - + settingsController .itemDidClick .bind(onNext: { [weak self] event in - switch event { - case .showLoginFlow: - self?.showLoginFlow() - } - }) + switch event { + case .showLoginFlow: + self?.showLoginFlow() + } + }) .disposed(by: disposableBag) } - + func showLoginFlow() { let loginViewController = settingsSceneDIContainer.makeLoginViewController() + loginViewController + .itemDidClick + .bind(onNext: { [weak self] event in + switch event { + case .showSignUpFlow: + self?.showSignUpFlow() + } + }) + .disposed(by: disposableBag) + navigationController.pushViewController(loginViewController, animated: true) } - + func showSignUpFlow() { - let signUpViewControllser = settingsSceneDIContainer.makeSignUpViewController() - navigationController.pushViewController(signUpViewControllser, animated: true) + let signUpViewController = settingsSceneDIContainer.makeSignUpViewController() + navigationController.pushViewController(signUpViewController, animated: true) } } diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift index 0924658..0e95263 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/LoginViewController.swift @@ -12,70 +12,85 @@ import RxCocoa import SnapKit final class LoginViewController: UIViewController { + enum Event { + case showSignUpFlow + } + private var viewModel: LoginViewModel! private var disposableBag = DisposeBag() - + + var itemDidClick = PublishSubject() + private lazy var container: UIStackView = { let container = UIStackView() container.axis = .vertical container.spacing = 10 - + return container }() - + private lazy var emailField: TextFieldForm = { let emailField = TextFieldForm() emailField.placeholder = "email" - + emailField.autocapitalizationType = .none return emailField }() - + private lazy var passwordField: TextFieldForm = { let passwordField = TextFieldForm() passwordField.placeholder = "password" - + passwordField.isSecureTextEntry = true return passwordField }() - + private lazy var submitButton: UIButton = { var config = UIButton.Configuration.filled() config.baseBackgroundColor = .maxYellow config.title = "로그인" - + emailField.autocapitalizationType = .none + return UIButton(configuration: config) + }() + + private lazy var signUpButton: UIButton = { + var config = UIButton.Configuration.plain() + config.baseForegroundColor = .gray + config.title = "회원가입" + config.buttonSize = .small return UIButton(configuration: config) }() - + // MARK: Life Cycle static func create(with viewModel: LoginViewModel) -> LoginViewController { let vc = LoginViewController() vc.setup(with: viewModel) - + return vc } - + override func viewDidLoad() { super.viewDidLoad() - + configureUI() - + bind() } - + private func configureUI() { view.backgroundColor = .white - + container.addArrangedSubview(emailField) container.addArrangedSubview(passwordField) container.addArrangedSubview(submitButton) - + container.addArrangedSubview(signUpButton) + view.addSubview(container) - + container.snp.makeConstraints { make in make.center.equalToSuperview() make.width.equalToSuperview().multipliedBy(0.8) } } - + private func setup(with authViewModel: LoginViewModel) { viewModel = authViewModel } @@ -83,24 +98,29 @@ final class LoginViewController: UIViewController { extension LoginViewController { private func bind() { + signUpButton.rx.tap.bind(onNext: { [weak self] _ in + guard let self = self else { return } + self.itemDidClick.onNext(.showSignUpFlow) + }).disposed(by: disposableBag) + let input = LoginViewModel.Input( emailFieldDidEditEvent: emailField.rx.text.orEmpty.asObservable(), passwordFieldDidEditEvent: passwordField.rx.text.orEmpty.asObservable(), submitButtonDidTapEvent: submitButton.rx.tap.asObservable() ) - + let output = viewModel.transform(input: input, disposeBag: disposableBag) - + output .buttonEnabled .drive(submitButton.rx.isEnabled) .disposed(by: disposableBag) - + output .loginResult .subscribe(onNext: { result in - print("login result is :::: ", result) - }) + print("login result is :::: ", result) + }) .disposed(by: disposableBag) } } diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift index a69f066..c069c67 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift @@ -26,6 +26,7 @@ final class SignUpViewController: UIViewController { private lazy var emailField: TextFieldForm = { let emailField = TextFieldForm() emailField.placeholder = "email" + emailField.autocapitalizationType = .none return emailField }() @@ -34,20 +35,21 @@ final class SignUpViewController: UIViewController { let passwordField = TextFieldForm() passwordField.placeholder = "password" passwordField.isSecureTextEntry = true + return passwordField }() private lazy var passwordConfirmField: TextFieldForm = { let passwordConfirmField = TextFieldForm() passwordConfirmField.placeholder = "password 확인" - passwordField.isSecureTextEntry = true + passwordConfirmField.isSecureTextEntry = true return passwordConfirmField }() private lazy var nickNameField: TextFieldForm = { let nickNameField = TextFieldForm() nickNameField.placeholder = "닉네임" - + emailField.autocapitalizationType = .none return nickNameField }() @@ -78,11 +80,11 @@ final class SignUpViewController: UIViewController { view.backgroundColor = .white [emailField, - passwordField, - passwordConfirmField, - nickNameField, - submitButton].forEach { field in - container.addArrangedSubview(view) + passwordField, + passwordConfirmField, + nickNameField, + submitButton].forEach { field in + container.addArrangedSubview(field) } view.addSubview(container) From 7027d7a1f7c3bcb275a9dc9dd76ea0083cbc0181 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 23:33:21 +0900 Subject: [PATCH 23/26] [feat] update condition --- .../ViewController/SignUpViewController.swift | 2 +- .../Settings/ViewModel/SignUpViewModel.swift | 40 ++++++++++++------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift index c069c67..e445209 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewController/SignUpViewController.swift @@ -33,7 +33,7 @@ final class SignUpViewController: UIViewController { private lazy var passwordField: TextFieldForm = { let passwordField = TextFieldForm() - passwordField.placeholder = "password" + passwordField.placeholder = "password (6글자 이상)" passwordField.isSecureTextEntry = true return passwordField diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift index aea4127..c8ff273 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift @@ -12,11 +12,11 @@ import RxCocoa final class SignUpViewModel { private let authUseCase: AuthUseCase - + init(authUseCase: AuthUseCase) { self.authUseCase = authUseCase } - + struct Input { let emailFieldDidEditEvent: Observable let passwordFieldDidEditEvent: Observable @@ -24,12 +24,12 @@ final class SignUpViewModel { let nickNameFieldDidEditEvent: Observable let submitButtonDidTapEvent: Observable } - + struct Output { let buttonEnabled: Driver let signUpResult: Observable } - + func transform(input: Input, disposeBag: DisposeBag) -> Output { let buttonEnabled = Observable .combineLatest(input.emailFieldDidEditEvent, @@ -38,32 +38,44 @@ final class SignUpViewModel { input.nickNameFieldDidEditEvent, resultSelector: checkButtonEnble(emailText: passwordText: passwordConfirmText: nickName:)) .asDriver(onErrorJustReturn: false) - + let signUpResult = input .submitButtonDidTapEvent .withLatestFrom(Observable - .combineLatest(input.emailFieldDidEditEvent, - input.passwordFieldDidEditEvent, - input.nickNameFieldDidEditEvent, - resultSelector: { ($0, $1, User(nickName: $2)) })) - .flatMap (authUseCase.signUp(email:password:user:)) - + .combineLatest(input.emailFieldDidEditEvent, + input.passwordFieldDidEditEvent, + input.nickNameFieldDidEditEvent, + resultSelector: { ($0, $1, User(nickName: $2)) })) + .flatMap (authUseCase.signUp(email: password: user:)) + return Output(buttonEnabled: buttonEnabled, signUpResult: signUpResult) } - + func checkEmpty(_ strArray: [String]) -> Bool { return !strArray.reduce(false) { $0 || $1.isEmpty } } - + func checkSame(str1: String, str2: String) -> Bool { return str1 == str2 } + + func checkEmail(str: String) -> Bool { + guard let index = str.firstIndex(of: "@") else { return false } + return str.startIndex != index && str.endIndex != index + } + + func checkPasswordCount(str: String) -> Bool { + return str.count >= 6 + } func checkButtonEnble(emailText: String, passwordText: String, passwordConfirmText: String, nickName: String) -> Bool { - return checkEmpty([emailText, passwordText, passwordConfirmText, nickName]) && checkSame(str1: passwordText, str2: passwordConfirmText) + return checkEmail(str: emailText) && + checkEmpty([emailText, passwordText, passwordConfirmText, nickName]) && + checkSame(str1: passwordText, str2: passwordConfirmText) && + checkPasswordCount(str: passwordText) } } From 6cebb5948848e5ea11781c7e2e75c5a808a2f5ed Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Tue, 6 Dec 2022 23:45:35 +0900 Subject: [PATCH 24/26] [fix] fix condition --- .../Settings/ViewModel/SignUpViewModel.swift | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift index c8ff273..f154ae8 100644 --- a/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Settings/ViewModel/SignUpViewModel.swift @@ -12,11 +12,11 @@ import RxCocoa final class SignUpViewModel { private let authUseCase: AuthUseCase - + init(authUseCase: AuthUseCase) { self.authUseCase = authUseCase } - + struct Input { let emailFieldDidEditEvent: Observable let passwordFieldDidEditEvent: Observable @@ -24,12 +24,12 @@ final class SignUpViewModel { let nickNameFieldDidEditEvent: Observable let submitButtonDidTapEvent: Observable } - + struct Output { let buttonEnabled: Driver let signUpResult: Observable } - + func transform(input: Input, disposeBag: DisposeBag) -> Output { let buttonEnabled = Observable .combineLatest(input.emailFieldDidEditEvent, @@ -38,32 +38,34 @@ final class SignUpViewModel { input.nickNameFieldDidEditEvent, resultSelector: checkButtonEnble(emailText: passwordText: passwordConfirmText: nickName:)) .asDriver(onErrorJustReturn: false) - + let signUpResult = input .submitButtonDidTapEvent .withLatestFrom(Observable - .combineLatest(input.emailFieldDidEditEvent, - input.passwordFieldDidEditEvent, - input.nickNameFieldDidEditEvent, - resultSelector: { ($0, $1, User(nickName: $2)) })) + .combineLatest(input.emailFieldDidEditEvent, + input.passwordFieldDidEditEvent, + input.nickNameFieldDidEditEvent, + resultSelector: { ($0, $1, User(nickName: $2)) })) .flatMap (authUseCase.signUp(email: password: user:)) - + return Output(buttonEnabled: buttonEnabled, signUpResult: signUpResult) } - + func checkEmpty(_ strArray: [String]) -> Bool { return !strArray.reduce(false) { $0 || $1.isEmpty } } - + func checkSame(str1: String, str2: String) -> Bool { return str1 == str2 } - + func checkEmail(str: String) -> Bool { + guard let index = str.firstIndex(of: "@") else { return false } - return str.startIndex != index && str.endIndex != index + let pos = str.distance(from: str.startIndex, to: index) + return 0 < pos && pos < str.count - 1 } - + func checkPasswordCount(str: String) -> Bool { return str.count >= 6 } From ac5c3bad157070bea6393870334421227f6e21a1 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Wed, 7 Dec 2022 00:08:17 +0900 Subject: [PATCH 25/26] [feat] UserUseCase --- .../DailyQuest.xcodeproj/project.pbxproj | 8 ++++++ .../UseCases/Home/DefaultUserUseCase.swift | 27 +++++++++++++++++++ .../UseCases/Home/Protocols/UserUseCase.swift | 13 +++++++++ 3 files changed, 48 insertions(+) create mode 100644 DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift create mode 100644 DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift diff --git a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj index 4aa2e43..0b8a740 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj +++ b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj @@ -126,6 +126,8 @@ 9BD8CD022938418500E6EA2F /* LastFollowingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */; }; A5003AB4293F5FEC00082A9C /* SignUpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */; }; A5003AB6293F601E00082A9C /* SignUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003AB5293F601E00082A9C /* SignUpViewController.swift */; }; + A5003AB9293F909300082A9C /* UserUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003AB8293F909300082A9C /* UserUseCase.swift */; }; + A5003ABB293F914500082A9C /* DefaultUserUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003ABA293F914500082A9C /* DefaultUserUseCase.swift */; }; A50DE906292B53D900E1FD60 /* DefaultQuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */; }; A50DE90B292B73B900E1FD60 /* FirebaseDatabaseSwift in Frameworks */ = {isa = PBXBuildFile; productRef = A50DE90A292B73B900E1FD60 /* FirebaseDatabaseSwift */; }; A50DE911292B74C500E1FD60 /* DTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE910292B74C500E1FD60 /* DTO.swift */; }; @@ -325,6 +327,8 @@ 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastFollowingCell.swift; sourceTree = ""; }; A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewModel.swift; sourceTree = ""; }; A5003AB5293F601E00082A9C /* SignUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewController.swift; sourceTree = ""; }; + A5003AB8293F909300082A9C /* UserUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserUseCase.swift; sourceTree = ""; }; + A5003ABA293F914500082A9C /* DefaultUserUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultUserUseCase.swift; sourceTree = ""; }; A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultQuestsRepository.swift; sourceTree = ""; }; A50DE910292B74C500E1FD60 /* DTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DTO.swift; sourceTree = ""; }; A50F9A3329266F45005C00FE /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; @@ -445,6 +449,7 @@ 3416FC86292B54BF00B504C5 /* Protocols */, 3416FC89292B560800B504C5 /* DefaultQuestUseCase.swift */, 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */, + A5003ABA293F914500082A9C /* DefaultUserUseCase.swift */, ); path = Home; sourceTree = ""; @@ -454,6 +459,7 @@ children = ( 3416FC87292B54DB00B504C5 /* QuestUseCase.swift */, 344A4599293DC495007A3D37 /* EnrollUseCase.swift */, + A5003AB8293F909300082A9C /* UserUseCase.swift */, ); path = Protocols; sourceTree = ""; @@ -1289,6 +1295,7 @@ 342830FD292E2AF200AE811B /* NavigateField.swift in Sources */, 342830F2292E196E00AE811B /* CommonField.swift in Sources */, 342830A8292E0FAC00AE811B /* SettingsCoordinator.swift in Sources */, + A5003AB9293F909300082A9C /* UserUseCase.swift in Sources */, 342830FB292E2A5F00AE811B /* NavigateItemViewModel.swift in Sources */, A51F01C82923392F0031ECA2 /* UserInfoStorage.swift in Sources */, 34A529E429248178001BAD34 /* SettingsSceneDIContainer.swift in Sources */, @@ -1327,6 +1334,7 @@ A51F01CA2923397E0031ECA2 /* UserInfoEntity.swift in Sources */, 345687F42937329E00CA51E3 /* EnrollViewController.swift in Sources */, A511229029384FAF00384B4B /* DefaultUserRepository.swift in Sources */, + A5003ABB293F914500082A9C /* DefaultUserUseCase.swift in Sources */, 342830FF292E2B2A00AE811B /* NavigateCell.swift in Sources */, A51F01D8292343A80031ECA2 /* RealmBrowseQuestsStorage.swift in Sources */, A51F01DD2923468F0031ECA2 /* BrowseQuestEntity+Mapping.swift in Sources */, diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift new file mode 100644 index 0000000..a935a63 --- /dev/null +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift @@ -0,0 +1,27 @@ +// +// DefaultUserUseCase.swift +// DailyQuest +// +// Created by 이전희 on 2022/12/07. +// + +import RxSwift + +final class DefaultUserUseCase { + private let userRepository: UserRepository + + init(userRepository: UserRepository) { + self.userRepository = userRepository + } +} + +extension DefaultUserUseCase: UserUseCase { + func fetch() -> Observable { + return userRepository.readUser() + } + + func save(with user: User) -> Observable { + return userRepository.updateUser(by: user) + } +} + diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift new file mode 100644 index 0000000..3c7334b --- /dev/null +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift @@ -0,0 +1,13 @@ +// +// UserUseCase.swift +// DailyQuest +// +// Created by 이전희 on 2022/12/07. +// + +import RxSwift + +protocol UserUseCase { + func fetch() -> Observable + func save(with user: User) -> Observable +} From 83f4592b48768b6a9f0d6c00e05c9434862ae349 Mon Sep 17 00:00:00 2001 From: Jeonhui Date: Wed, 7 Dec 2022 00:57:01 +0900 Subject: [PATCH 26/26] [feat] User UseCase add delete User --- .../Data/Repositories/DefaultUserRepository.swift | 14 +++++++++----- .../Domain/UseCases/Home/DefaultUserUseCase.swift | 10 ++++++++-- .../UseCases/Home/Protocols/UserUseCase.swift | 2 ++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift b/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift index c4df458..141a444 100644 --- a/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift +++ b/DailyQuest/DailyQuest/Data/Repositories/DefaultUserRepository.swift @@ -49,13 +49,17 @@ extension DefaultUserRepository: UserRepository { extension DefaultUserRepository: ProtectedUserRepository { func deleteUser() -> Observable { - return self.persistentStorage.deleteUserInfo() + // return self.persistentStorage.deleteUserInfo() + // .map { _ in true } + // .asObservable() + // .concatMap { _ in + // return self.networkService.delete(userCase: .currentUser, access: .userInfo, dto: UserDTO()) + // .map { _ in true } + // } + return networkService.delete(userCase: .currentUser, access: .userInfo, dto: UserDTO()) .map { _ in true } + .catchAndReturn(false) .asObservable() - .concatMap { _ in - return self.networkService.delete(userCase: .currentUser, access: .userInfo, dto: UserDTO()) - .map { _ in true } - } } } diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift index a935a63..5b6d85e 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/DefaultUserUseCase.swift @@ -9,7 +9,7 @@ import RxSwift final class DefaultUserUseCase { private let userRepository: UserRepository - + init(userRepository: UserRepository) { self.userRepository = userRepository } @@ -19,9 +19,15 @@ extension DefaultUserUseCase: UserUseCase { func fetch() -> Observable { return userRepository.readUser() } - + func save(with user: User) -> Observable { return userRepository.updateUser(by: user) } + + func delete() -> Observable { + guard let userRepository = userRepository as? ProtectedUserRepository else { return Observable.just(false) } + return userRepository.deleteUser() + .catchAndReturn(false) + } } diff --git a/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift b/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift index 3c7334b..36f91c3 100644 --- a/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift +++ b/DailyQuest/DailyQuest/Domain/UseCases/Home/Protocols/UserUseCase.swift @@ -10,4 +10,6 @@ import RxSwift protocol UserUseCase { func fetch() -> Observable func save(with user: User) -> Observable + + func delete() -> Observable }