Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REFACTOR] Coordinator #31

Merged
merged 16 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading