From 46130f27ae03e8be229217028095bd60421d9c35 Mon Sep 17 00:00:00 2001 From: J0onYEong Date: Mon, 1 Jul 2024 11:47:35 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[IDLE-89]=20=EC=9A=94=EC=96=91=EB=B3=B4?= =?UTF-8?q?=ED=98=B8=EC=82=AC(Agent)=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project/Makefile | 2 +- .../AuthFeatureDependency.swift | 13 ++ project/Projects/App/Project.swift | 1 + .../Auth/AgentAuthCoordinator.swift | 61 +++++++ .../Auth/AuthCoordinator+Extension.swift | 37 ++++ .../Auth/AuthCoordinator.swift | 44 +++++ .../RootCoordinator+Extension.swift | 6 + .../RootCoordinator/RootCoordinator.swift | 64 +------ .../TestMain/TestMainTabBarCoodinator.swift | 94 ++++++++++ .../Sources/Prototype/ButtonPrototype.swift | 61 +++++++ .../DSKit/Sources/TestComponent.swift | 8 - .../Resources/LaunchScreen.storyboard | 45 +++++ .../Auth/ExampleApp/Sources/AppDelegate.swift | 36 ++++ .../ExampleApp/Sources/SceneDelegate.swift | 23 +++ .../ExampleApp}/Sources/ViewController.swift | 2 +- .../Presentation/Feature/Auth/Project.swift | 81 +++++++++ .../Feature/Auth/Resources/Empty.md | 2 + .../Agent/AgentAuthMainCoodinator.swift | 48 ++++++ .../Agent/AgentRegisterCoordinator.swift | 160 ++++++++++++++++++ .../SelectAuthTypeCoordinator.swift | 51 ++++++ .../Agent/AgentAuthMainViewController.swift | 53 ++++++ .../Agent/AgentRegisterViewController.swift | 73 ++++++++ .../Register/SelectGenderViewController.swift | 34 ++++ .../Register/EnterNameViewController.swift | 34 ++++ .../ValidatePhoneNumberViewController.swift | 34 ++++ .../View/SelectAuthTypeViewController.swift | 88 ++++++++++ .../ScreenCoordinating/Coordinator.swift | 58 ++++++- .../Auth/AgentAuthCoordinatable.swift | 14 ++ .../Interface/Auth/AuthCoordinatable.swift | 22 +++ .../Sources/Util/DebugingLog.swift | 14 ++ 30 files changed, 1190 insertions(+), 73 deletions(-) create mode 100644 project/Plugins/DependencyPlugin/ProjectDescriptionHelpers/AuthFeatureDependency.swift create mode 100644 project/Projects/App/Sources/RootCoordinator/Auth/AgentAuthCoordinator.swift create mode 100644 project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator+Extension.swift create mode 100644 project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift create mode 100644 project/Projects/App/Sources/RootCoordinator/TestMain/TestMainTabBarCoodinator.swift create mode 100644 project/Projects/Presentation/DSKit/Sources/Prototype/ButtonPrototype.swift delete mode 100644 project/Projects/Presentation/DSKit/Sources/TestComponent.swift create mode 100644 project/Projects/Presentation/Feature/Auth/ExampleApp/Resources/LaunchScreen.storyboard create mode 100644 project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/AppDelegate.swift create mode 100644 project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/SceneDelegate.swift rename project/Projects/{App => Presentation/Feature/Auth/ExampleApp}/Sources/ViewController.swift (93%) create mode 100644 project/Projects/Presentation/Feature/Auth/Project.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Resources/Empty.md create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentAuthMainCoodinator.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentRegisterCoordinator.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/Coordinator/SelectAuthTypeCoordinator.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentAuthMainViewController.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentRegisterViewController.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/View/Agent/Register/SelectGenderViewController.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/EnterNameViewController.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/ValidatePhoneNumberViewController.swift create mode 100644 project/Projects/Presentation/Feature/Auth/Sources/View/SelectAuthTypeViewController.swift create mode 100644 project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AgentAuthCoordinatable.swift create mode 100644 project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AuthCoordinatable.swift create mode 100644 project/Projects/Presentation/PresentationCore/Sources/Util/DebugingLog.swift diff --git a/project/Makefile b/project/Makefile index a4b74f8f..c7bcc165 100644 --- a/project/Makefile +++ b/project/Makefile @@ -4,7 +4,7 @@ USER_NAME = $(shell python3 Scaffold/Scripts/author_name.py) CURRENT_DATE = $(shell pipenv run python Scaffold/Scripts/current_date.py) Feature: - @mkdir Projects/Presentation/Feature/${name}; + @mkdir -p Projects/Presentation/Feature/${name}; @tuist scaffold Feature \ --project-name ${name} \ --author "$(USER_NAME)" \ diff --git a/project/Plugins/DependencyPlugin/ProjectDescriptionHelpers/AuthFeatureDependency.swift b/project/Plugins/DependencyPlugin/ProjectDescriptionHelpers/AuthFeatureDependency.swift new file mode 100644 index 00000000..d4c5e31b --- /dev/null +++ b/project/Plugins/DependencyPlugin/ProjectDescriptionHelpers/AuthFeatureDependency.swift @@ -0,0 +1,13 @@ +// +// AuthFeatureDependency.swift +// DependencyPlugin +// +// Created by 최준영 on 6/21/24. +// + +import ProjectDescription + +public extension ModuleDependency.Presentation { + + static let AuthFeature: TargetDependency = .project(target: "AuthFeature", path: .relativeToRoot("Projects/Presentation/Feature/Auth")) +} diff --git a/project/Projects/App/Project.swift b/project/Projects/App/Project.swift index bb0749ca..2cf9ecf1 100644 --- a/project/Projects/App/Project.swift +++ b/project/Projects/App/Project.swift @@ -30,6 +30,7 @@ let project = Project( // Presentation D.Presentation.PresentationCore, + D.Presentation.AuthFeature, // Domain D.Domain.ConcreteUseCase, diff --git a/project/Projects/App/Sources/RootCoordinator/Auth/AgentAuthCoordinator.swift b/project/Projects/App/Sources/RootCoordinator/Auth/AgentAuthCoordinator.swift new file mode 100644 index 00000000..e1ae11ed --- /dev/null +++ b/project/Projects/App/Sources/RootCoordinator/Auth/AgentAuthCoordinator.swift @@ -0,0 +1,61 @@ +// +// AgentAuthCoordinator.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore +import AuthFeature + +class AgentAuthCoordinator: ParentCoordinator { + + var childCoordinators: [Coordinator] = [] + + var navigationController: UINavigationController + + var parent: AuthCoordinator? + + init(navigationController: UINavigationController) { + self.navigationController = navigationController + } + + deinit { + printIfDebug("deinit \(Self.self)") + } + + func start() { + + let coordinator = AgentAuthMainCoodinator( + navigationController: navigationController + ) + + coordinator.parent = self + + addChildCoordinator(coordinator) + + coordinator.start() + } +} + +extension AgentAuthCoordinator: AgentAuthCoordinatable { + + func register() { + + let coordinator = AgentRegisterCoordinator( + navigationController: navigationController + ) + + coordinator.parent = self + + addChildCoordinator(coordinator) + + coordinator.start() + } + + func authFinished() { + + parent?.authFinished() + } +} diff --git a/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator+Extension.swift b/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator+Extension.swift new file mode 100644 index 00000000..f6b1c623 --- /dev/null +++ b/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator+Extension.swift @@ -0,0 +1,37 @@ +// +// AuthCoordinator+Extension.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import Foundation +import PresentationCore + +extension AuthCoordinator: AuthCoordinatable { + + public func auth(type: AuthType) { + + switch type { + case .agent: + + let coordinator = AgentAuthCoordinator(navigationController: navigationController) + + addChildCoordinator(coordinator) + + coordinator.parent = self + + coordinator.start() + + case .agency: + return + } + } + + public func authFinished() { + + clearChildren() + + parent?.removeChildCoordinator(self) + } +} diff --git a/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift b/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift new file mode 100644 index 00000000..7a17e606 --- /dev/null +++ b/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift @@ -0,0 +1,44 @@ +// +// AuthCoordinator.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore +import AuthFeature + +public class AuthCoordinator: ParentCoordinator { + + public var childCoordinators: [Coordinator] = [] + + public var parent: ParentCoordinator? + + public var navigationController: UINavigationController + + public init(navigationController: UINavigationController) { + self.navigationController = navigationController + } + + deinit { + printIfDebug("deinit \(Self.self)") + } + + public func start() { + + let coordinator = SelectAuthTypeCoordinator( + navigationController: navigationController + ) + coordinator.parent = self + + addChildCoordinator(coordinator) + ` + coordinator.start() + } + + public func popViewController() { + + navigationController.popViewController(animated: true) + } +} diff --git a/project/Projects/App/Sources/RootCoordinator/RootCoordinator+Extension.swift b/project/Projects/App/Sources/RootCoordinator/RootCoordinator+Extension.swift index 9addf432..8170c072 100644 --- a/project/Projects/App/Sources/RootCoordinator/RootCoordinator+Extension.swift +++ b/project/Projects/App/Sources/RootCoordinator/RootCoordinator+Extension.swift @@ -6,10 +6,16 @@ // import Foundation +import AuthFeature extension RootCoordinator { func auth() { + let authCoordinator = AuthCoordinator( + navigationController: navigationController + ) + + authCoordinator.start() } } diff --git a/project/Projects/App/Sources/RootCoordinator/RootCoordinator.swift b/project/Projects/App/Sources/RootCoordinator/RootCoordinator.swift index 3286aa6d..a8d720ea 100644 --- a/project/Projects/App/Sources/RootCoordinator/RootCoordinator.swift +++ b/project/Projects/App/Sources/RootCoordinator/RootCoordinator.swift @@ -20,6 +20,8 @@ class RootCoordinator: ParentCoordinator { func start() { + navigationController.navigationBar.isHidden = true + let coordinator = TestMainTabBarCoodinator( navigationController: navigationController ) @@ -34,65 +36,3 @@ class RootCoordinator: ParentCoordinator { navigationController.popViewController(animated: false) } } - - -// MARK: Test MainTabBar -class TestMainTabBarCoodinator: ChildCoordinator { - - var navigationController: UINavigationController - - var parent: RootCoordinator? - - weak var viewControllerRef: DisposableViewController? - - init(navigationController: UINavigationController) { - self.navigationController = navigationController - } - - func start() { - - let viewController = TestMainTabBarController() - viewController.coordinator = self - - self.viewControllerRef = viewController - - navigationController.pushViewController(viewController, animated: false) - } - - func popViewController() { - - navigationController.popViewController(animated: true) - } - - func coordinatorDidFinish() { - - parent?.removeChildCoordinator(self) - } -} - -public class TestMainTabBarController: DisposableViewController { - - var coordinator: TestMainTabBarCoodinator? - - public func cleanUp() { - - coordinator?.coordinatorDidFinish() - } - - public override func viewDidLoad() { - - let initialLabel = UILabel() - - initialLabel.text = "테스트용 메인 탭바 화면입니다." - - view.backgroundColor = .white - - view.addSubview(initialLabel) - initialLabel.translatesAutoresizingMaskIntoConstraints = false - - NSLayoutConstraint.activate([ - initialLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), - initialLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), - ]) - } -} diff --git a/project/Projects/App/Sources/RootCoordinator/TestMain/TestMainTabBarCoodinator.swift b/project/Projects/App/Sources/RootCoordinator/TestMain/TestMainTabBarCoodinator.swift new file mode 100644 index 00000000..4a397975 --- /dev/null +++ b/project/Projects/App/Sources/RootCoordinator/TestMain/TestMainTabBarCoodinator.swift @@ -0,0 +1,94 @@ +// +// TestVC.swift +// Idle-iOS +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import DSKit +import PresentationCore + +// MARK: Test MainTabBar +class TestMainTabBarCoodinator: ChildCoordinator { + + var navigationController: UINavigationController + + var parent: RootCoordinator? + + weak var viewControllerRef: DisposableViewController? + + init(navigationController: UINavigationController) { + self.navigationController = navigationController + } + + func start() { + + let viewController = TestMainTabBarController() + viewController.coordinator = self + + self.viewControllerRef = viewController + + navigationController.pushViewController(viewController, animated: false) + } + + func popViewController() { + + navigationController.popViewController(animated: true) + } + + func coordinatorDidFinish() { + + parent?.removeChildCoordinator(self) + } + + func startAuth() { + + parent?.auth() + } +} + +public class TestMainTabBarController: DisposableViewController { + + var coordinator: TestMainTabBarCoodinator? + + lazy var startLoginButton = ButtonPrototype(text: "로그인 시작") { [weak self] in + self?.coordinator?.startAuth() + } + + public func cleanUp() { + + coordinator?.coordinatorDidFinish() + } + + public override func viewDidLoad() { + + let titleLabel = UILabel() + + titleLabel.text = "테스트용 메인 탭바 화면입니다." + + view.backgroundColor = .white + + [ + titleLabel, + startLoginButton + ].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + view.addSubview($0) + } + + view.layoutMargins = .init(top: 0, left: 20, bottom: 0, right: 20) + + view.addSubview(titleLabel) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), + + startLoginButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + startLoginButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), + startLoginButton.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor) + ]) + } +} diff --git a/project/Projects/Presentation/DSKit/Sources/Prototype/ButtonPrototype.swift b/project/Projects/Presentation/DSKit/Sources/Prototype/ButtonPrototype.swift new file mode 100644 index 00000000..50a3e853 --- /dev/null +++ b/project/Projects/Presentation/DSKit/Sources/Prototype/ButtonPrototype.swift @@ -0,0 +1,61 @@ +// +// RowButtonPrototype.swift +// DSKit +// +// Created by choijunios on 6/30/24. +// + +import UIKit + +public class ButtonPrototype: UIView { + + private let onTouch: () -> Void + + public let label = UILabel() + + public init(text: String, onTouch: @escaping () -> Void) { + + self.onTouch = onTouch + + super.init(frame: .zero) + + self.backgroundColor = .black + + label.text = text + label.textColor = .white + + [ + label + ].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + addSubview($0) + } + + self.layoutMargins = .init(top: 10, left: 0, bottom: 10, right: 0) + + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: centerXAnchor), + label.topAnchor.constraint(equalTo: self.layoutMarginsGuide.topAnchor), + label.bottomAnchor.constraint(equalTo: self.layoutMarginsGuide.bottomAnchor) + ]) + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onTouchAction)) + + self.addGestureRecognizer(tapGesture) + } + + @objc + func onTouchAction(_ TapGesture: UITapGestureRecognizer) { + onTouch() + + let orginColor: UIColor = .black + self.backgroundColor = .gray + + UIView.animate(withDuration: 0.3) { + + self.backgroundColor = orginColor + } + } + + required init?(coder: NSCoder) { fatalError() } +} diff --git a/project/Projects/Presentation/DSKit/Sources/TestComponent.swift b/project/Projects/Presentation/DSKit/Sources/TestComponent.swift deleted file mode 100644 index f899dc89..00000000 --- a/project/Projects/Presentation/DSKit/Sources/TestComponent.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// TestComponent.swift -// FeatureManifests -// -// Created by 최준영 on 6/21/24. -// - -import Foundation diff --git a/project/Projects/Presentation/Feature/Auth/ExampleApp/Resources/LaunchScreen.storyboard b/project/Projects/Presentation/Feature/Auth/ExampleApp/Resources/LaunchScreen.storyboard new file mode 100644 index 00000000..a2157a3e --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/ExampleApp/Resources/LaunchScreen.storyboard @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/AppDelegate.swift b/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/AppDelegate.swift new file mode 100644 index 00000000..00267bb5 --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// +// +// Created by 최준영 on 6/19/24. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/SceneDelegate.swift b/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/SceneDelegate.swift new file mode 100644 index 00000000..015452b5 --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/SceneDelegate.swift @@ -0,0 +1,23 @@ +// +// SceneDelegate.swift +// +// +// Created by 최준영 on 6/19/24. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + + guard let windowScene = scene as? UIWindowScene else { return } + + + window = UIWindow(windowScene: windowScene) + window?.rootViewController = ViewController() + window?.makeKeyAndVisible() + } +} diff --git a/project/Projects/App/Sources/ViewController.swift b/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/ViewController.swift similarity index 93% rename from project/Projects/App/Sources/ViewController.swift rename to project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/ViewController.swift index 9ed1ad23..e439d432 100644 --- a/project/Projects/App/Sources/ViewController.swift +++ b/project/Projects/Presentation/Feature/Auth/ExampleApp/Sources/ViewController.swift @@ -13,7 +13,7 @@ class ViewController: UIViewController { let initialLabel = UILabel() - initialLabel.text = "Hello world" + initialLabel.text = "Example app" view.backgroundColor = .white diff --git a/project/Projects/Presentation/Feature/Auth/Project.swift b/project/Projects/Presentation/Feature/Auth/Project.swift new file mode 100644 index 00000000..dd58a4da --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Project.swift @@ -0,0 +1,81 @@ +// +// Project.swift +// ProjectDescriptionHelpers +// +// Created by choijunios on 2024/06/30 +// + +import ProjectDescription +import ProjectDescriptionHelpers +import ConfigurationPlugin +import DependencyPlugin + +let project = Project( + name: "Auth", + settings: .settings( + configurations: IdleConfiguration.emptyConfigurations + ), + targets: [ + + /// FeatureConcrete + .target( + name: "AuthFeature", + destinations: DeploymentSettings.platform, + product: .staticFramework, + bundleId: "$(PRODUCT_BUNDLE_IDENTIFIER)", + deploymentTargets: DeploymentSettings.deployment_version, + sources: ["Sources/**"], + resources: ["Resources/**"], + dependencies: [ + // Presentation + D.Presentation.PresentationCore, + D.Presentation.DSKit, + + // Domain + D.Domain.UseCaseInterface, + D.Domain.RepositoryInterface, + + // ThirdParty + D.ThirdParty.RxSwift, + D.ThirdParty.RxCocoa, + ], + settings: .settings( + configurations: IdleConfiguration.presentationConfigurations + ) + ), + + /// FeatureConcrete ExampleApp + .target( + name: "Auth_ExampleApp", + destinations: DeploymentSettings.platform, + product: .app, + bundleId: "$(PRODUCT_BUNDLE_IDENTIFIER)", + deploymentTargets: DeploymentSettings.deployment_version, + infoPlist: IdleInfoPlist.exampleAppDefault, + sources: ["ExampleApp/Sources/**"], + resources: ["ExampleApp/Resources/**"], + dependencies: [ + .target(name: "AuthFeature"), + ], + settings: .settings( + configurations: IdleConfiguration.presentationConfigurations + ) + ), + ], + schemes: [ + Scheme.makeSchemes( + .target("AuthFeature"), + configNames: [ + IdleConfiguration.debugConfigName, + IdleConfiguration.releaseConfigName + ] + ), + Scheme.makeSchemes( + .target("Auth_ExampleApp"), + configNames: [ + IdleConfiguration.debugConfigName, + IdleConfiguration.releaseConfigName + ] + ) + ].flatMap { $0 } +) diff --git a/project/Projects/Presentation/Feature/Auth/Resources/Empty.md b/project/Projects/Presentation/Feature/Auth/Resources/Empty.md new file mode 100644 index 00000000..64e53d46 --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Resources/Empty.md @@ -0,0 +1,2 @@ +# <#Title#> + diff --git a/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentAuthMainCoodinator.swift b/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentAuthMainCoodinator.swift new file mode 100644 index 00000000..789ec36c --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentAuthMainCoodinator.swift @@ -0,0 +1,48 @@ +// +// AgentAuthMainCoodinator.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore + +public class AgentAuthMainCoodinator: ChildCoordinator { + + public var navigationController: UINavigationController + + public weak var viewControllerRef: DisposableViewController? + + public var parent: AgentAuthCoordinatable? + + public init(navigationController: UINavigationController) { + + self.navigationController = navigationController + } + + deinit { + printIfDebug("deinit \(SelectAuthTypeCoordinator.self)") + } + + public func start() { + + let viewController = AgentAuthMainViewController() + viewController.coordinator = self + + viewControllerRef = viewController + + navigationController.pushViewController(viewController, animated: true) + } + + public func coordinatorDidFinish() { + parent?.removeChildCoordinator(self) + } + + func register() { + + parent?.register() + } +} + + diff --git a/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentRegisterCoordinator.swift b/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentRegisterCoordinator.swift new file mode 100644 index 00000000..cc6c8345 --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/Agent/AgentRegisterCoordinator.swift @@ -0,0 +1,160 @@ +// +// AgentRegisterCoordinator.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore + +enum AgentRegisterStage: Int { + + case phoneNumber=0 + case name=1 + case gender=2 + case finish=3 + + var nextStage: Self? { + + switch self { + case .phoneNumber: + return .name + case .name: + return .gender + case .gender: + return .finish + default: + return nil + } + } +} + +public class AgentRegisterCoordinator: ChildCoordinator { + + public var parent: AgentAuthCoordinatable? + + public let navigationController: UINavigationController + + public weak var viewControllerRef: DisposableViewController? + + weak var pageViewController: UIPageViewController? + + var stageViewControllers: [DisposableViewController] = [] + + var currentStage: AgentRegisterStage? + + public init(navigationController: UINavigationController) { + + self.navigationController = navigationController + } + + deinit { + printIfDebug("deinit \(Self.self)") + } + + public func start() { + + stageViewControllers = [ + ValidatePhoneNumberViewController(), + EnterNameViewController(), + SelectGenderViewController(), + ] + + let pageViewController = UIPageViewController( + transitionStyle: .scroll, + navigationOrientation: .horizontal, + options: nil + ) + + self.pageViewController = pageViewController + + let viewController = AgentRegisterViewController( + pageViewController: pageViewController + ) + + viewController.coordinator = self + + viewControllerRef = viewController + + navigationController.pushViewController(viewController, animated: true) + + phoneNumberStage() + } + + public func coordinatorDidFinish() { + + viewControllerRef?.cleanUp() + + parent?.removeChildCoordinator(self) + } +} + +extension AgentRegisterCoordinator { + + func next() { + + if let nextStage = currentStage?.nextStage { + + switch nextStage { + case .name: + nameStage() + case .gender: + genderStage() + case .finish: + authFinished() + default: + return + } + } + } + + func phoneNumberStage() { + + let viewController = stageViewControllers[AgentRegisterStage.phoneNumber.rawValue] + + let phoneStage = viewController as! ValidatePhoneNumberViewController + + phoneStage.coordinater = self + + showStage(viewController: phoneStage) + + currentStage = .phoneNumber + } + + func nameStage() { + + let viewController = stageViewControllers[AgentRegisterStage.name.rawValue] + + let nameStage = viewController as! EnterNameViewController + + nameStage.coordinater = self + + showStage(viewController: nameStage) + + currentStage = .name + } + + func genderStage() { + + let viewController = stageViewControllers[AgentRegisterStage.gender.rawValue] + + let genderStage = viewController as! SelectGenderViewController + + genderStage.coordinater = self + + showStage(viewController: genderStage) + + currentStage = .gender + } + + func showStage(viewController: UIViewController) { + + pageViewController?.setViewControllers([viewController], direction: .forward, animated: true) + } + + func authFinished() { + + parent?.authFinished() + } +} diff --git a/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/SelectAuthTypeCoordinator.swift b/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/SelectAuthTypeCoordinator.swift new file mode 100644 index 00000000..0e311b1f --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/Coordinator/SelectAuthTypeCoordinator.swift @@ -0,0 +1,51 @@ +// +// SelectAuthTypeCoordinator.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore + +public class SelectAuthTypeCoordinator: ChildCoordinator { + + public var navigationController: UINavigationController + + public weak var viewControllerRef: DisposableViewController? + + public var parent: AuthCoordinatable? + + public init(navigationController: UINavigationController) { + self.navigationController = navigationController + } + + public func start() { + let viewController = SelectAuthTypeViewController() + viewController.coordinator = self + viewControllerRef = viewController + navigationController.pushViewController(viewController, animated: true) + } + + public func coordinatorDidFinish() { + popViewController() + parent?.removeChildCoordinator(self) + } + + deinit { + printIfDebug("deinit \(Self.self)") + } +} + +extension SelectAuthTypeCoordinator { + + func authAgent() { + + parent?.auth(type: .agent) + } + + func authAgency() { + + parent?.auth(type: .agency) + } +} diff --git a/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentAuthMainViewController.swift b/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentAuthMainViewController.swift new file mode 100644 index 00000000..e9a5ace6 --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentAuthMainViewController.swift @@ -0,0 +1,53 @@ +// +// AgentAuthMainViewController.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import DSKit +import PresentationCore + +public class AgentAuthMainViewController: DisposableViewController { + + var coordinator: AgentAuthMainCoodinator? + + lazy var startRegisterButton = ButtonPrototype(text: "요양보호사 등록") { [weak self] in + + self?.coordinator?.register() + } + + public override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + + let title = UILabel() + title.text = "요양보호사 등록" + title.font = UIFont.systemFont(ofSize: 24, weight: .bold) + title.textColor = .black + + [ + title, + startRegisterButton + ].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + view.addSubview($0) + } + + NSLayoutConstraint.activate([ + + title.centerXAnchor.constraint(equalTo: view.centerXAnchor), + title.centerYAnchor.constraint(equalTo: view.centerYAnchor), + + startRegisterButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + startRegisterButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + startRegisterButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + ]) + } + + public func cleanUp() { + coordinator?.coordinatorDidFinish() + } +} diff --git a/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentRegisterViewController.swift b/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentRegisterViewController.swift new file mode 100644 index 00000000..be71f21e --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/AgentRegisterViewController.swift @@ -0,0 +1,73 @@ +// +// AgentRegisterViewController.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import DSKit +import PresentationCore + +class AgentRegisterViewController: DisposableViewController { + + var coordinator: AgentRegisterCoordinator? + + var pageViewController: UIPageViewController + + lazy var nextButton = ButtonPrototype(text: "다음") { [weak self] in + + self?.coordinator?.next() + } + + init(pageViewController: UIPageViewController) { + + self.pageViewController = pageViewController + + super.init(nibName: nil, bundle: nil) + + addChild(pageViewController) + } + + required init?(coder: NSCoder) { fatalError() } + + override func viewDidLoad() { + + view.backgroundColor = .white + + let statusView = UILabel() + + statusView.textColor = .black + statusView.text = "스테이터스 바" + + [ + statusView, + pageViewController.view, + nextButton + ].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + view.addSubview($0) + } + + NSLayoutConstraint.activate([ + + statusView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + statusView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + statusView.heightAnchor.constraint(equalToConstant: 100), + + pageViewController.view.topAnchor.constraint(equalTo: statusView.bottomAnchor), + pageViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + pageViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + pageViewController.view.bottomAnchor.constraint(equalTo: nextButton.topAnchor), + + nextButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + nextButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 20), + nextButton.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -20) + ]) + } + + func cleanUp() { + + coordinator?.stageViewControllers = [] + } +} diff --git a/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/Register/SelectGenderViewController.swift b/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/Register/SelectGenderViewController.swift new file mode 100644 index 00000000..ad208d4f --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/View/Agent/Register/SelectGenderViewController.swift @@ -0,0 +1,34 @@ +// +// SelectGenderViewController.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore + +class SelectGenderViewController: DisposableViewController { + + var coordinater: AgentRegisterCoordinator? + + override func viewDidLoad() { + + view.backgroundColor = .white + + let label = UILabel() + label.text = "성별 입력" + + view.addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: view.centerXAnchor), + label.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + func cleanUp() { + coordinater?.coordinatorDidFinish() + } +} diff --git a/project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/EnterNameViewController.swift b/project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/EnterNameViewController.swift new file mode 100644 index 00000000..41ddeb30 --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/EnterNameViewController.swift @@ -0,0 +1,34 @@ +// +// EnterNameViewController.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore + +class EnterNameViewController: DisposableViewController { + + var coordinater: AgentRegisterCoordinator? + + override func viewDidLoad() { + + view.backgroundColor = .white + + let label = UILabel() + label.text = "이름 입력" + + view.addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: view.centerXAnchor), + label.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + func cleanUp() { + + } +} diff --git a/project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/ValidatePhoneNumberViewController.swift b/project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/ValidatePhoneNumberViewController.swift new file mode 100644 index 00000000..64cee1df --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/View/Common/Register/ValidatePhoneNumberViewController.swift @@ -0,0 +1,34 @@ +// +// ValidatePhoneNumberViewController.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import PresentationCore + +class ValidatePhoneNumberViewController: DisposableViewController { + + var coordinater: AgentRegisterCoordinator? + + override func viewDidLoad() { + + view.backgroundColor = .white + + let label = UILabel() + label.text = "폰 번호 검증" + + view.addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: view.centerXAnchor), + label.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + func cleanUp() { + + } +} diff --git a/project/Projects/Presentation/Feature/Auth/Sources/View/SelectAuthTypeViewController.swift b/project/Projects/Presentation/Feature/Auth/Sources/View/SelectAuthTypeViewController.swift new file mode 100644 index 00000000..3f3b0610 --- /dev/null +++ b/project/Projects/Presentation/Feature/Auth/Sources/View/SelectAuthTypeViewController.swift @@ -0,0 +1,88 @@ +// +// SelectAuthTypeViewController.swift +// AuthFeature +// +// Created by choijunios on 6/30/24. +// + +import UIKit +import DSKit +import PresentationCore + +class SelectAuthTypeViewController: DisposableViewController { + + var coordinator: SelectAuthTypeCoordinator? + + lazy var startAgentButton = ButtonPrototype(text: "요양보호사로 시작") { [weak self] in + self?.coordinator?.authAgent() + } + lazy var startAgencyButton = ButtonPrototype(text: "센터장으로 시작") { [weak self] in + self?.coordinator?.authAgency() + } + lazy var closeButton = ButtonPrototype(text: "닫기") { [weak self] in + self?.coordinator?.coordinatorDidFinish() + } + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "어떤 사용자로 시작하시겠습니까?" + label.font = .systemFont(ofSize: 24, weight: .bold) + label.textAlignment = .center + return label + }() + + init() { + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { fatalError() } + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + + [ + titleLabel, + startAgentButton, + startAgencyButton, + closeButton + ].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + view.addSubview($0) + } + + setLayout() + } + + func setLayout() { + + view.layoutMargins = .init(top: 0, left: 20, bottom: 0, right: 20) + + NSLayoutConstraint.activate([ + + titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100), + titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + + // Agency Button + closeButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + closeButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), + closeButton.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor), + + // Agency Button + startAgencyButton.bottomAnchor.constraint(equalTo: closeButton.topAnchor, constant: -20), + startAgencyButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), + startAgencyButton.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor), + + // Agent Button + startAgentButton.bottomAnchor.constraint(equalTo: startAgencyButton.topAnchor, constant: -20), + startAgentButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), + startAgentButton.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor) + ]) + } + + func cleanUp() { + + } +} diff --git a/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Coordinator.swift b/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Coordinator.swift index 1f30101a..0a0920ea 100644 --- a/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Coordinator.swift +++ b/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Coordinator.swift @@ -13,7 +13,15 @@ public protocol Coordinator: AnyObject { var navigationController: UINavigationController { get } func start() - func popViewController() + func popViewController(animated: Bool) +} + +public extension Coordinator { + + func popViewController(animated: Bool = true) { + + navigationController.popViewController(animated: animated) + } } // MARK: ParentCoordinator @@ -23,6 +31,8 @@ public protocol ParentCoordinator: Coordinator { func addChildCoordinator(_ coordinator: Coordinator) func removeChildCoordinator(_ coordinator: Coordinator) + + func clearChildren() } public extension ParentCoordinator { @@ -34,6 +44,52 @@ public extension ParentCoordinator { func removeChildCoordinator(_ coordinator: Coordinator) { childCoordinators = childCoordinators.filter { $0 !== coordinator } } + + func clearChildren() { + + let lastCoordinator = childCoordinators.popLast() + + var middleViewControllers: [UIViewController?] = [] + + childCoordinators.reversed().forEach { coordinator in + + if coordinator is ChildCoordinator { + + let child = coordinator as! ChildCoordinator + + child.viewControllerRef?.cleanUp() + + if let middleViewController = child.viewControllerRef { + + middleViewControllers.append(middleViewController) + } + + self.removeChildCoordinator(child) + } + } + + navigationController.viewControllers = navigationController.viewControllers.filter({ viewController in + !middleViewControllers.contains(where: { $0 === viewController }) + }) + + if lastCoordinator is ParentCoordinator { + + (lastCoordinator as! ParentCoordinator).clearChildren() + + } else { + + if let lastCoordinator { + + if lastCoordinator is ChildCoordinator { + + (lastCoordinator as! ChildCoordinator).viewControllerRef?.cleanUp() + } + + self.removeChildCoordinator(lastCoordinator) + lastCoordinator.popViewController() + } + } + } } // MARK: ChildCoordinator diff --git a/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AgentAuthCoordinatable.swift b/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AgentAuthCoordinatable.swift new file mode 100644 index 00000000..6db28b85 --- /dev/null +++ b/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AgentAuthCoordinatable.swift @@ -0,0 +1,14 @@ +// +// AgentAuthCoordinatable.swift +// PresentationCore +// +// Created by choijunios on 7/1/24. +// + +import Foundation + +public protocol AgentAuthCoordinatable: ParentCoordinator { + + func register() + func authFinished() +} diff --git a/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AuthCoordinatable.swift b/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AuthCoordinatable.swift new file mode 100644 index 00000000..52eddcb7 --- /dev/null +++ b/project/Projects/Presentation/PresentationCore/Sources/ScreenCoordinating/Interface/Auth/AuthCoordinatable.swift @@ -0,0 +1,22 @@ +// +// AuthCoordinatable.swift +// PresentationCore +// +// Created by choijunios on 7/1/24. +// + +import Foundation + +public enum AuthType { + + case agent + case agency +} + +public protocol AuthCoordinatable: ParentCoordinator { + + func auth(type: AuthType) + func authFinished() +} + + diff --git a/project/Projects/Presentation/PresentationCore/Sources/Util/DebugingLog.swift b/project/Projects/Presentation/PresentationCore/Sources/Util/DebugingLog.swift new file mode 100644 index 00000000..b43dba2a --- /dev/null +++ b/project/Projects/Presentation/PresentationCore/Sources/Util/DebugingLog.swift @@ -0,0 +1,14 @@ +// +// DebugLog.swift +// PresentationCore +// +// Created by choijunios on 7/1/24. +// + +import Foundation + +public func printIfDebug(_ items: Any..., separator: String = " ", terminator: String = "\n") { + #if DEBUG + print(items, separator: separator, terminator: terminator) + #endif +} From f48f40e5588772aa7a1bf4cbe3284d8608890930 Mon Sep 17 00:00:00 2001 From: J0onYEong Date: Mon, 1 Jul 2024 11:48:27 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[IDLE-89]=20=EC=BB=B4=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98(=EB=AC=B8=EB=B2=95=20=EC=98=A4=EB=A5=98)=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../App/Sources/RootCoordinator/Auth/AuthCoordinator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift b/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift index 7a17e606..e233ea94 100644 --- a/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift +++ b/project/Projects/App/Sources/RootCoordinator/Auth/AuthCoordinator.swift @@ -33,7 +33,7 @@ public class AuthCoordinator: ParentCoordinator { coordinator.parent = self addChildCoordinator(coordinator) - ` + coordinator.start() }