Skip to content

Commit

Permalink
Merge pull request #31 from kimkyuchul/feature/#30
Browse files Browse the repository at this point in the history
[REFACTOR] Coordinator
  • Loading branch information
kimkyuchul authored Nov 25, 2024
2 parents 521565c + 5263d2b commit b2e2a43
Show file tree
Hide file tree
Showing 43 changed files with 1,239 additions and 402 deletions.
269 changes: 207 additions & 62 deletions Makgulli.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions Makgulli.xcworkspace/xcshareddata/swiftpm/Package.resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "dcee1f64719827fe357ae6a446c89603385ee9415dc75343f62f976875b3bec0",
"originHash" : "2e12ae3ccf19a62525d5bb352166d7187485cc2d9ffd159d0d55f722a0854c89",
"pins" : [
{
"identity" : "abseil-cpp-binary",
Expand All @@ -15,8 +15,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire",
"state" : {
"revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad",
"version" : "5.8.1"
"revision" : "e16d3481f5ed35f0472cb93350085853d754913f",
"version" : "5.10.1"
}
},
{
Expand Down Expand Up @@ -123,17 +123,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/ashleymills/Reachability.swift",
"state" : {
"revision" : "c01127cb51f591045696128effe43c16840d08bf",
"version" : "5.2.0"
"revision" : "21d1dc412cfecbe6e34f1f4c4eb88d3f912654a6",
"version" : "5.2.4"
}
},
{
"identity" : "realm-core",
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/realm-core.git",
"state" : {
"revision" : "a5e87a39cffdcc591f3203c11cfca68100d0b9a6",
"version" : "13.26.0"
"revision" : "85eeca41654cc9070ad81a21a4b1d153ad467c33",
"version" : "14.13.1"
}
},
{
Expand All @@ -142,7 +142,7 @@
"location" : "https://github.com/realm/realm-swift",
"state" : {
"branch" : "master",
"revision" : "a56145813ef5e7c4b5c5450fabfa1b1a098247b0"
"revision" : "5553cfd1c789efdb3d6daf7f0cc0733cfe601846"
}
},
{
Expand Down
61 changes: 61 additions & 0 deletions Makgulli/Application/Coordinator/AppCoordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// AppCoordinator.swift
// Makgulli
//
// Created by kyuchul on 11/22/24.
//

import UIKit

import Combine

enum AppFlow {
case main
case login
}

final class AppCoordinator: Coordinator {
weak var parentCoordinator: (any Coordinator)?
var childCoordinators: [any Coordinator] = []
var navigationController: UINavigationController
let flow = PassthroughSubject<AppFlow, Never>()
private var cancellable = Set<AnyCancellable>()

init(navigationController: UINavigationController) {
self.navigationController = navigationController
bindState()
}

func bindState() {
flow
.sink { [weak self] flow in
switch flow {
case .main:
self?.startTabBar()
case .login:
break
}
}
.store(in: &cancellable)
}

func start() {
startSplash()
}
}

extension AppCoordinator {
private func startSplash() {
let splashViewController = SplashViewController(coordinator: self)
navigationController.setNavigationBarHidden(true, animated: false)
setViewController(viewController: splashViewController, animated: false)
}

private func startTabBar() {
let tabBarCoordinator = TabBarCoordinator(navigationController: navigationController)
tabBarCoordinator.parentCoordinator = self
tabBarCoordinator.start()

self.addDependency(tabBarCoordinator)
}
}
78 changes: 78 additions & 0 deletions Makgulli/Application/Coordinator/Coordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// Coordinator.swift
// Makgulli
//
// Created by kyuchul on 11/22/24.
//

import UIKit

protocol Coordinatable {
associatedtype CoordinatorType: Coordinator

var coordinator: CoordinatorType? { get }
}

protocol Coordinator: AnyObject {
// 부모 코디네이터
var parentCoordinator: Coordinator? { get set }
// 모든 코디네이터는 자신의 자식 코디네이터를 관리
var childCoordinators: [Coordinator] { get set }
// 뷰컨트롤러를 보여줄 때 사용될 내비게이션 컨트롤러를 저장
var navigationController: UINavigationController { get set }
// 해당 코디네이터가 제어권을 갖도록 하는 메서드. 완전히 만들고 준비되었을 때만 코디네이터를 활성화
func start()
}

extension Coordinator {
func addDependency(_ coordinator: Coordinator) {
for element in childCoordinators {
if element === coordinator { return }
}
childCoordinators.append(coordinator)
}

func removeDependency(_ coordinator: Coordinator?) {
for (index, element) in childCoordinators.enumerated() where element === coordinator {
childCoordinators.remove(at: index)
break
}
}

func printStack() {
let viewControllers = navigationController.viewControllers
for (index, viewController) in viewControllers.enumerated() {
print("\(index): \(Swift.type(of: viewController))")
}
}
}

extension Coordinator {
func push(viewController: UIViewController, navibarHidden: Bool = true, swipe: Bool = true, animated: Bool = true) {
navigationController.setNavigationBarHidden(navibarHidden, animated: true)

if swipe {
self.navigationController.interactivePopGestureRecognizer?.isEnabled = swipe
self.navigationController.interactivePopGestureRecognizer?.delegate = nil
}

navigationController.pushViewController(viewController, animated: animated)
}

func present(_ viewController: UIViewController, style: UIModalPresentationStyle) {
viewController.modalPresentationStyle = style
navigationController.present(viewController, animated: true)
}

func pop() {
navigationController.popViewController(animated: true)
}

func dismiss(animated: Bool = true,completion: (() -> Void)? = nil) {
navigationController.dismiss(animated: animated, completion: completion)
}

func setViewController(viewController: UIViewController, animated: Bool = true) {
navigationController.setViewControllers([viewController], animated: animated)
}
}
4 changes: 4 additions & 0 deletions Makgulli/Application/DIContainer/AppDIContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ final class AppDIContainer {
func makeFavoriteDIContainer() -> FavoriteDIContainer {
return FavoriteDIContainer()
}

func makeAppInfoDIContainer() -> AppInfoDIContainer {
return AppInfoDIContainer()
}
}
15 changes: 15 additions & 0 deletions Makgulli/Application/DIContainer/AppInfoDIContainer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// SettingDIContainer.swift
// Makgulli
//
// Created by kyuchul on 11/25/24.
//

import Foundation

final class AppInfoDIContainer {
// MARK: - ViewModel
func makeAppInfoViewModel() -> AppInfoViewModel {
AppInfoViewModel()
}
}
8 changes: 4 additions & 4 deletions Makgulli/Application/DIContainer/EpisodeDIContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ final class EpisodeDIContainer {
}

// MARK: - UseCases
private func makeLocationUseCase() -> WriteEpisodeUseCase {
private func makeWriteEpisodeUseCase() -> WriteEpisodeUseCase {
DefaultWriteEpisodeUseCase(
writeEpisodeRepository: makeWriteEpisodeRepository(),
writeEpisodeLocalRepository: makeWriteEpisodeLocalRepository()
Expand All @@ -60,14 +60,14 @@ final class EpisodeDIContainer {
}

// MARK: - ViewModel
func makeLocationViewModel(store: StoreVO) -> WriteEpisodeViewModel {
func makeWriteEpisodeViewModel(store: StoreVO) -> WriteEpisodeViewModel {
WriteEpisodeViewModel(
storeVO: store,
writeEpisodeUseCase: makeLocationUseCase()
writeEpisodeUseCase: makeWriteEpisodeUseCase()
)
}

func makeLocationViewModel(episode: Episode, storeId: String) -> EpisodeDetailViewModel {
func makeEpisodeDetailViewModel(episode: Episode, storeId: String) -> EpisodeDetailViewModel {
EpisodeDetailViewModel(
episode: episode,
storeId: storeId,
Expand Down
9 changes: 8 additions & 1 deletion Makgulli/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,20 @@ import Reachability

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

private var coordinator: AppCoordinator?
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 = SplashViewController()

let navigationController = UINavigationController()
coordinator = AppCoordinator(navigationController: navigationController)

window?.rootViewController = navigationController
window?.makeKeyAndVisible()

coordinator?.start()
}

func sceneDidDisconnect(_ scene: UIScene) {
Expand Down
17 changes: 17 additions & 0 deletions Makgulli/Common/Extension/UIApplication+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// UIApplication+.swift
// Makgulli
//
// Created by kyuchul on 11/25/24.
//

import UIKit

extension UIApplication {
var keyWindowInConnectedScenes: UIWindow? {
return connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first { $0.isKeyWindow }
}
}
1 change: 1 addition & 0 deletions Makgulli/Common/Literal/ImageLiteral.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum ImageLiteral {
//MARK: - Favorite

//MARK: - System image
static var back: UIImage { .load(systemName: "chevron.backward") }
static var checkIcon: UIImage { .load(systemName: "checkmark")}
static var bookMarkIcon: UIImage { .load(systemName: "bookmark") }
static var fillBookMarkIcon: UIImage { .load(systemName: "bookmark.fill") }
Expand Down
109 changes: 109 additions & 0 deletions Makgulli/Common/UIComponent/NavigationBar/JumakNavigationBar.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//
// JumakNavigationBar.swift
// Makgulli
//
// Created by kyuchul on 11/25/24.
//

import UIKit

import RxSwift
import RxCocoa

final class JumakNavigationBar: BaseView {

private let containerView = UIView()
private let backButton: UIButton = {
let button = UIButton()
button.setImage(ImageLiteral.back, for: .normal)
button.tintColor = .black
return button
}()

private let titleLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.font = UIFont.boldLineSeed(size: ._16)
label.textAlignment = .center
return label
}()

private var rightItems: [UIView] = []
private let rightStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.spacing = 8
stackView.alignment = .center
return stackView
}()

init(rightItems: [UIView] = []) {
self.rightItems = rightItems
super.init(frame: .zero)
configureRightItems()
}

override func setHierarchy() {
addSubview(containerView)

[backButton, titleLabel, rightStackView]
.forEach {
containerView.addSubview($0)
}
}

override func setConstraints() {
self.snp.makeConstraints { make in
make.height.equalTo(52)
}

containerView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}

backButton.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(12)
make.centerY.equalToSuperview()
make.size.equalTo(26)
}

titleLabel.snp.makeConstraints { make in
make.center.equalToSuperview()
}

rightStackView.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(12)
make.centerY.equalToSuperview()
}
}

override func setLayout() {
self.backgroundColor = .white
}
}

private extension JumakNavigationBar {
func configureRightItems() {
rightItems.forEach {
$0.snp.makeConstraints { make in
make.size.equalTo(26)
}
}

rightItems.forEach { rightStackView.addArrangedSubview($0) }
}
}

extension JumakNavigationBar {
func setTitle(_ title: String) {
titleLabel.text = title
}

func hideBackButton() {
backButton.isHidden = true
}

func backButtonAction() -> Observable<Void> {
return backButton.rx.tap.asObservable()
}
}
Loading

0 comments on commit b2e2a43

Please sign in to comment.