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

start step refactoring (improvements) #3

Merged
merged 1 commit into from
Mar 7, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PackageDescription

let package = Package(
name: "Swordinator",
platforms: [.iOS(.v14)],
platforms: [.iOS(.v13)],
products: [
.library(name: "Swordinator", targets: ["Swordinator"]),
],
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Swordinator is a minimal, lightweight and easy customizable navigation framework

[![Tests](https://github.com/laubengaier/Swordinator/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/laubengaier/Swordinator/actions/workflows/ci.yml) ![SPM Compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen)
## Requirements
iOS 14.0+, Swift 5.0+
iOS 13.0+, Swift 5.0+

## Installation

Expand Down Expand Up @@ -58,17 +58,17 @@ class AppCoordinator: Coordinator

let services: AppServices

init(window: UIWindow, services: AppServices) {
init(window: UIWindow, services: AppServices, step: AppStep) {
self.window = window
self.services = services
start()
start(step: step)
}

func start() {
func start(step: Step) {
if services.isAuthenticated {
self.showTaskList()
handle(step: .dashboard)
} else {
self.showLogin()
handle(step: .auth)
}
}

Expand Down
7 changes: 6 additions & 1 deletion Sources/Swordinator/Swordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import UIKit

public protocol Coordinator: AnyObject
{
var id: UUID { get }
var childCoordinators: [Coordinator] { get set }
func start()
func start(step: Step)
func handle(step: Step)
func releaseChild<T: Coordinator>(type: T.Type)
}

public extension Coordinator {
var id: UUID { return UUID() }
func start(step: Step) {
handle(step: step)
}
func handle(step: Step) {
print("⚠️ step handler is not implemented for \(String(describing: Self.self))")
}
Expand Down
8 changes: 4 additions & 4 deletions SwordinatorDemo/SwordinatorDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -577,12 +577,12 @@
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.1;
PRODUCT_BUNDLE_IDENTIFIER = com.laubengaier.SwordinatorDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -605,12 +605,12 @@
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.1;
PRODUCT_BUNDLE_IDENTIFIER = com.laubengaier.SwordinatorDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down
2 changes: 1 addition & 1 deletion SwordinatorDemo/SwordinatorDemo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
print("⚔️ Swordinator demo started")
print("⚔️ Swordinator-Demo started")
return true
}

Expand Down
29 changes: 21 additions & 8 deletions SwordinatorDemo/SwordinatorDemo/Features/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,46 @@ class AppCoordinator: Coordinator, Deeplinkable {
var rootCoordinator: (Coordinator & Deeplinkable)?
var childCoordinators: [Coordinator] = []

init(window: UIWindow, services: AppServices) {
init(window: UIWindow, services: AppServices, step: AppStep) {
self.window = window
self.services = services
start()
start(step: step)
}

deinit {
print("🗑 \(String(describing: Self.self))")
}

func start() {
// no matter what step is triggered from AppDelegate it's overriden here
// otherwise just call the step handler
func start(step: Step) {
print("⬇️ Navigated to \(String(describing: Self.self))")
if services.isAuthenticated {
services.isSyncRequired ? showSync() : showTabbar()
services.isSyncRequired ? handle(step: AppStep.sync) : handle(step: AppStep.dashboard)
} else {
self.showLogin()
handle(step: AppStep.auth)
}
}

func handle(step: Step) {
print(" ➡️ \(String(describing: Self.self)) -> \(step)")
guard let step = step as? AppStep else { return }
switch step {

case .dashboard:
return showTabbar()
case .auth:
showLogin()
case .sync:
showSync()

case .logout:
showLogin()
case .authCompleted:
services.isSyncRequired ? showSync() : showTabbar()
case .syncCompleted:
showTabbar()

default:
return
}
Expand All @@ -69,23 +82,23 @@ class AppCoordinator: Coordinator, Deeplinkable {
extension AppCoordinator {
private func showTabbar() {
let tbc = UITabBarController()
let coordinator = DashboardCoordinator(tabBarController: tbc, services: services)
let coordinator = DashboardCoordinator(tabBarController: tbc, services: services, step: .dashboard)
coordinator.parent = self
rootCoordinator = coordinator
window.rootViewController = tbc
}

private func showLogin() {
let nvc = UINavigationController()
let coordinator = LoginCoordinator(navigationController: nvc, services: services)
let coordinator = LoginCoordinator(navigationController: nvc, services: services, step: .auth)
coordinator.parent = self
rootCoordinator = coordinator
window.rootViewController = nvc
}

private func showSync() {
let nvc = UINavigationController()
let coordinator = SyncCoordinator(navigationController: nvc, services: services)
let coordinator = SyncCoordinator(navigationController: nvc, services: services, step: .sync)
coordinator.parent = self
rootCoordinator = coordinator
window.rootViewController = nvc
Expand Down
7 changes: 7 additions & 0 deletions SwordinatorDemo/SwordinatorDemo/Features/AppStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import MBProgressHUD

enum AppStep: Step {

// tabbar
case dashboard

// task list
case taskList

// task
case taskDetail(task: Task, completion: (() -> Void)?)
case taskDetailLazy(id: Int)
Expand All @@ -20,6 +26,7 @@ enum AppStep: Step {
case taskDetailCompleted

// auth
case auth
case authWithSIWA
case authCompleted
case logout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,32 @@ class DashboardCoordinator: NSObject, TabBarControllerCoordinator, ParentCoordin

let services: AppServices

init(tabBarController: UITabBarController, services: AppServices) {
init(tabBarController: UITabBarController, services: AppServices, step: AppStep) {
self.tabBarController = tabBarController
self.services = services
super.init()
start()
start(step: step)
}

deinit {
print("🗑 \(String(describing: Self.self))")
}

func start() {
print("➡️ navigated to \(String(describing: Self.self))")

tabBarController.delegate = self

let nvc1 = UINavigationController()
nvc1.tabBarItem = UITabBarItem(title: "Tasks", image: UIImage(systemName: "app"), tag: 0)
let taskListCoordinator = TaskListCoordinator(navigationController: nvc1, services: services)
taskListCoordinator.parent = self
childCoordinators.append(taskListCoordinator)

let nvc2 = UINavigationController()
nvc2.tabBarItem = UITabBarItem(title: "Profile", image: UIImage(systemName: "person"), tag: 1)
let profileCoordinator = ProfileCoordinator(navigationController: nvc2, services: services)
profileCoordinator.parent = self
childCoordinators.append(profileCoordinator)


tabBarController.setViewControllers([
nvc1,
nvc2
], animated: false)

// assign the selected root & update via tabbar delegate
rootCoordinator = taskListCoordinator
func start(step: Step) {
print("⬇️ Navigated to \(String(describing: Self.self))")
handle(step: step)
}

func handle(step: Step) {
print(" ➡️ \(String(describing: Self.self)) -> \(step)")
guard let step = step as? AppStep else { return }
switch step {
case .dashboard:
navigateToDashboard()
case .profileSettings:
self.showProfile(shouldSelect: true)
showProfile(shouldSelect: true)
case .logout:
self.logout()
logout()
default:
()
}
Expand All @@ -72,13 +53,13 @@ class DashboardCoordinator: NSObject, TabBarControllerCoordinator, ParentCoordin
if let deepLink = deepLink as? AppDeeplinkStep {
switch deepLink {
case .tasks:
self.showTasks(shouldSelect: true)
showTasks(shouldSelect: true)
return
case .profile:
self.showProfile(shouldSelect: true)
showProfile(shouldSelect: true)
return
case .profileSettings:
self.showProfileSettings()
showProfileSettings()
return
default:
()
Expand All @@ -94,6 +75,30 @@ class DashboardCoordinator: NSObject, TabBarControllerCoordinator, ParentCoordin

// MARK: - Actions
extension DashboardCoordinator {
private func navigateToDashboard() {
tabBarController.delegate = self

let nvc1 = UINavigationController()
nvc1.tabBarItem = UITabBarItem(title: "Tasks", image: UIImage(systemName: "app"), tag: 0)
let taskListCoordinator = TaskListCoordinator(navigationController: nvc1, services: services, step: .taskList)
taskListCoordinator.parent = self
childCoordinators.append(taskListCoordinator)

let nvc2 = UINavigationController()
nvc2.tabBarItem = UITabBarItem(title: "Profile", image: UIImage(systemName: "person"), tag: 1)
let profileCoordinator = ProfileCoordinator(navigationController: nvc2, services: services, step: .profile)
profileCoordinator.parent = self
childCoordinators.append(profileCoordinator)


tabBarController.setViewControllers([
nvc1,
nvc2
], animated: false)

// assign the selected root & update via tabbar delegate
rootCoordinator = taskListCoordinator
}
private func showTasks(shouldSelect: Bool = false) {
guard
let taskListCoordinator = childCoordinators.filter({ $0 is TaskListCoordinator }).first as? TaskListCoordinator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extension NavCoordinator {

func navigateToTask(task: Task) {
let nvc = UINavigationController()
let coordinator = TaskDetailCoordinator(navigationController: nvc, services: services, task: task)
let coordinator = TaskDetailCoordinator(navigationController: nvc, services: services, step: .taskDetail(task: task, completion: nil))
coordinator.parent = self
navigationController.present(nvc, animated: true, completion: nil)
childCoordinators.append(coordinator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@ class LoginCoordinator: NavigationControllerCoordinator, ParentCoordinated, Deep

let services: AppServices

init(navigationController: UINavigationController, services: AppServices) {
init(navigationController: UINavigationController, services: AppServices, step: AppStep) {
self.navigationController = navigationController
self.services = services
start()
start(step: step)
}

deinit {
print("🗑 \(String(describing: Self.self))")
}

func start() {
let vm = LoginViewModel(services: services)
let vc = LoginViewController(coordinator: self, viewModel: vm)
navigationController.setViewControllers([
vc
], animated: false)
func start(step: Step) {
print("⬇️ Navigated to \(String(describing: Self.self))")
handle(step: step)
}

func handle(step: Step) {
print(" ➡️ \(String(describing: Self.self)) -> \(step)")
// handle steps
guard let step = step as? AppStep else { return }
switch step {
case .auth:
navigateToLogin()
case .authWithSIWA:
print("🙋‍♂️ logged in with siwa")
parent?.handle(step: AppStep.authCompleted)
Expand All @@ -55,5 +55,11 @@ class LoginCoordinator: NavigationControllerCoordinator, ParentCoordinated, Deep

// MARK: - Actions
extension LoginCoordinator {

private func navigateToLogin() {
let vm = LoginViewModel(services: services, coordinator: self)
let vc = LoginViewController(viewModel: vm)
navigationController.setViewControllers([
vc
], animated: false)
}
}