Skip to content

Commit

Permalink
Advanced Flow (#1)
Browse files Browse the repository at this point in the history
* advanced flow

- add `profileSettings` deeplink to move to profileSettings (even when in taskDetail)
- replace profile settings menu barbutton with showing an actual `ProfileSettings` vc

* cleanup

- moved the no step example to `No Step` feature
- updated logic for task cell
- update to readme
- cleanup handle(step:) methods
  • Loading branch information
laubengaier committed Oct 15, 2021
1 parent d46a7c2 commit de736b4
Show file tree
Hide file tree
Showing 15 changed files with 579 additions and 60 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dependencies: [
These steps should provide a simple way of getting started. If something is not clear please take a look at the demo provided or create an issue.

##### Quicknote:
The simplest way is to go forward with implementing `Step` and using `handle(step: Step)` which simplifies the coordination but if you want even more control or don't like steps there is a delegate example in the demo (ProfileCoordinator).
The simplest way is to go forward with implementing `Step` and using `handle(step: Step)` which simplifies the coordination but if you want even more control or don't like steps there is a delegate example in the demo (NoStepCoordinator).

#### 1. Define Steps

Expand Down Expand Up @@ -186,6 +186,8 @@ xcrun simctl openurl booted swordinator://tasks/1
xcrun simctl openurl booted swordinator://tasks
# profile, switch tab
xcrun simctl openurl booted swordinator://profile
# profile settings, switch tab to profile and open settings
xcrun simctl openurl booted swordinator://settings
# logout
xcrun simctl openurl booted swordinator://logout
```
Expand Down
48 changes: 48 additions & 0 deletions SwordinatorDemo/SwordinatorDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
F74BDC0A2710B26600B3F68A /* TaskListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74BDC092710B26600B3F68A /* TaskListCell.swift */; };
F7D3056C2716A298008B2552 /* SyncCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3056B2716A298008B2552 /* SyncCoordinator.swift */; };
F7D3056E2716A39F008B2552 /* SyncViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3056D2716A39F008B2552 /* SyncViewController.swift */; };
F7D3057427194B06008B2552 /* ProfileSettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3057327194B06008B2552 /* ProfileSettingsCoordinator.swift */; };
F7D3057627194B0D008B2552 /* ProfileSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3057527194B0D008B2552 /* ProfileSettingsViewModel.swift */; };
F7D3057827194B14008B2552 /* ProfileSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3057727194B14008B2552 /* ProfileSettingsViewController.swift */; };
F7D3057B27195F71008B2552 /* ProfileSettingsListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3057A27195F71008B2552 /* ProfileSettingsListCell.swift */; };
F7D3057E271968D5008B2552 /* NoStepCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3057D271968D5008B2552 /* NoStepCoordinator.swift */; };
F7D305802719691C008B2552 /* NoStepViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D3057F2719691C008B2552 /* NoStepViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -72,6 +78,12 @@
F74BDC092710B26600B3F68A /* TaskListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskListCell.swift; sourceTree = "<group>"; };
F7D3056B2716A298008B2552 /* SyncCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncCoordinator.swift; sourceTree = "<group>"; };
F7D3056D2716A39F008B2552 /* SyncViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncViewController.swift; sourceTree = "<group>"; };
F7D3057327194B06008B2552 /* ProfileSettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSettingsCoordinator.swift; sourceTree = "<group>"; };
F7D3057527194B0D008B2552 /* ProfileSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSettingsViewModel.swift; sourceTree = "<group>"; };
F7D3057727194B14008B2552 /* ProfileSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSettingsViewController.swift; sourceTree = "<group>"; };
F7D3057A27195F71008B2552 /* ProfileSettingsListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSettingsListCell.swift; sourceTree = "<group>"; };
F7D3057D271968D5008B2552 /* NoStepCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoStepCoordinator.swift; sourceTree = "<group>"; };
F7D3057F2719691C008B2552 /* NoStepViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoStepViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -141,6 +153,8 @@
A186D21127104B3C0047BA45 /* TaskList */,
A186D20B27104B3C0047BA45 /* TaskDetail */,
A186D21427104B3C0047BA45 /* Profile */,
F7D3057227194AEC008B2552 /* Profile Settings */,
F7D3057C271968AC008B2552 /* No Step */,
);
path = Features;
sourceTree = "<group>";
Expand Down Expand Up @@ -253,6 +267,34 @@
path = Sync;
sourceTree = "<group>";
};
F7D3057227194AEC008B2552 /* Profile Settings */ = {
isa = PBXGroup;
children = (
F7D3057327194B06008B2552 /* ProfileSettingsCoordinator.swift */,
F7D3057527194B0D008B2552 /* ProfileSettingsViewModel.swift */,
F7D3057727194B14008B2552 /* ProfileSettingsViewController.swift */,
F7D3057927195F66008B2552 /* Cells */,
);
path = "Profile Settings";
sourceTree = "<group>";
};
F7D3057927195F66008B2552 /* Cells */ = {
isa = PBXGroup;
children = (
F7D3057A27195F71008B2552 /* ProfileSettingsListCell.swift */,
);
path = Cells;
sourceTree = "<group>";
};
F7D3057C271968AC008B2552 /* No Step */ = {
isa = PBXGroup;
children = (
F7D3057D271968D5008B2552 /* NoStepCoordinator.swift */,
F7D3057F2719691C008B2552 /* NoStepViewController.swift */,
);
path = "No Step";
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -335,22 +377,28 @@
files = (
A186D22527104B3C0047BA45 /* ProfileCoordinator.swift in Sources */,
A186D21E27104B3C0047BA45 /* AppCoordinator.swift in Sources */,
F7D3057427194B06008B2552 /* ProfileSettingsCoordinator.swift in Sources */,
F7D3057827194B14008B2552 /* ProfileSettingsViewController.swift in Sources */,
F738C5C72714126900EA5812 /* LoginViewModel.swift in Sources */,
F738C5BF2713FB1500EA5812 /* TaskDetailSelectableCell.swift in Sources */,
A186D22227104B3C0047BA45 /* DashboardCoordinator.swift in Sources */,
F7D305802719691C008B2552 /* NoStepViewController.swift in Sources */,
A186D22127104B3C0047BA45 /* TaskDetailCoordinator.swift in Sources */,
F738C5BD2713F89E00EA5812 /* TaskDetailNameCell.swift in Sources */,
A186D22827104B3C0047BA45 /* AppStep.swift in Sources */,
A186D22027104B3C0047BA45 /* TaskDetailViewModel.swift in Sources */,
F7D3056E2716A39F008B2552 /* SyncViewController.swift in Sources */,
F7D3056C2716A298008B2552 /* SyncCoordinator.swift in Sources */,
F738C5C2271400E900EA5812 /* TaskDetailReminderViewController.swift in Sources */,
F7D3057B27195F71008B2552 /* ProfileSettingsListCell.swift in Sources */,
F738C5C92715551E00EA5812 /* TaskListViewModel.swift in Sources */,
F738C5C5271411A100EA5812 /* AppServices.swift in Sources */,
F7D3057E271968D5008B2552 /* NoStepCoordinator.swift in Sources */,
A186D22627104B3C0047BA45 /* ProfileViewController.swift in Sources */,
A186D22327104B3C0047BA45 /* TaskListCoordinator.swift in Sources */,
A186D1EE27104AF90047BA45 /* AppDelegate.swift in Sources */,
A186D1F027104AF90047BA45 /* SceneDelegate.swift in Sources */,
F7D3057627194B0D008B2552 /* ProfileSettingsViewModel.swift in Sources */,
F74BDC0A2710B26600B3F68A /* TaskListCell.swift in Sources */,
A186D22727104B3C0047BA45 /* ProfileViewModel.swift in Sources */,
A186D22A27104B3C0047BA45 /* LoginViewController.swift in Sources */,
Expand Down
11 changes: 10 additions & 1 deletion SwordinatorDemo/SwordinatorDemo/Features/AppStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ enum AppStep: Step {
case taskDetailReminder(task: Task)
case taskDetailPriority(task: Task)
case lazyTaskDetail(id: Int)

case taskDetailClose
// auth
case authWithSIWA
case authCompleted
Expand All @@ -25,8 +25,14 @@ enum AppStep: Step {
case sync
case syncCompleted

// profile
case profile
case profileSettings
case closeProfileSettings

// navigation
case close
case closeChildren
case dismiss
case pop
}
Expand All @@ -36,6 +42,7 @@ enum AppDeeplinkStep: DeeplinkStep {
case lazyTaskDetail(id: Int)
case tasks
case profile
case profileSettings
case logout
}

Expand Down Expand Up @@ -67,6 +74,8 @@ extension AppDeeplinkStep {
return .profile
} else if host == "logout" {
return .logout
} else if host == "settings" {
return .profileSettings
}
return nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ class DashboardCoordinator: NSObject, TabBarControllerCoordinator, ParentCoordin
rootCoordinator = taskListCoordinator
}

func handle(step: Step) {
guard let step = step as? AppStep else { return }
switch step {
case .profileSettings:
self.showProfile(shouldSelect: true)
case .logout:
self.logout()
default:
()
}
}

func handle(deepLink: DeeplinkStep) {
if let deepLink = deepLink as? AppDeeplinkStep {
switch deepLink {
Expand All @@ -65,6 +77,9 @@ class DashboardCoordinator: NSObject, TabBarControllerCoordinator, ParentCoordin
case .profile:
self.showProfile(shouldSelect: true)
return
case .profileSettings:
self.showProfileSettings()
return
default:
()
}
Expand All @@ -90,17 +105,27 @@ extension DashboardCoordinator {
print("🔄 changed rootCoordinator to taskList")
}

private func showProfile(shouldSelect: Bool = false) {
private func showProfile(shouldSelect: Bool = false, forwardStep: DeeplinkStep? = nil) {
guard
let profileCoordinator = childCoordinators.filter({ $0 is ProfileCoordinator }).first as? ProfileCoordinator
else { return }
if shouldSelect {
tabBarController.selectedIndex = 1
}
rootCoordinator = profileCoordinator
if let forwardStep = forwardStep {
profileCoordinator.handle(deepLink: forwardStep)
}
print("🔄 changed rootCoordinator to profile")
}

private func showProfileSettings() {
if let taskListCoordinator = childCoordinators.filter({ $0 is TaskListCoordinator }).first {
taskListCoordinator.handle(step: AppStep.closeChildren)
}
self.showProfile(shouldSelect: true, forwardStep: AppDeeplinkStep.profileSettings)
}

private func logout() {
childCoordinators.removeAll { $0 is TaskListCoordinator }
childCoordinators.removeAll { $0 is ProfileCoordinator }
Expand All @@ -122,16 +147,3 @@ extension DashboardCoordinator: UITabBarControllerDelegate {
}
}
}

// MARK: - ProfileCoordinatorHandling
extension DashboardCoordinator: ProfileCoordinatorHandling {
func handle(event: ProfileCoordinator.Event) {
switch event {
case .logout:
logout()
case .close:
childCoordinators.removeAll { $0 is TaskListCoordinator }
childCoordinators.removeAll { $0 is ProfileCoordinator }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// NoStepCoordinator.swift
// SwordinatorDemo
//
// Created by Timotheus Laubengaier on 2021/10/15.
//

import Foundation
import UIKit
import Swordinator

protocol NoStepCoordinatorHandling: AnyObject {
func handle(event: NoStepCoordinator.Event)
}


class NoStepCoordinator: NavigationControllerCoordinator, ParentCoordinated
{
enum Event {
case something
case something2
}

var parent: (Coordinator & NoStepCoordinatorHandling)?
var navigationController: UINavigationController
var childCoordinators: [Coordinator] = []

let services: AppServices

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

func start() {
let vc = NoStepViewController()
vc.coordinator = self
navigationController.setViewControllers([
vc
], animated: false)
}
}

// MARK: - NoStepViewControllerHandling
extension NoStepCoordinator: NoStepViewControllerHandling {
func handle(event: NoStepViewController.Event) {
switch event {
case .noStepExample1:
parent?.handle(event: .something)
case .noStepExample2:
parent?.handle(event: .something2)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// NoStepViewController.swift
// SwordinatorDemo
//
// Created by Timotheus Laubengaier on 2021/10/15.
//

import Foundation
import UIKit
import Swordinator

protocol NoStepViewControllerHandling: AnyObject {
func handle(event: NoStepViewController.Event)
}


class NoStepViewController: UIViewController, Coordinated {

enum Event {
case noStepExample1
case noStepExample2
}

weak var coordinator: Coordinator?

override func viewDidLoad() {
super.viewDidLoad()
title = "No Step"
view.backgroundColor = .systemBackground
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// ProfileSettingsListCell.swift
// SwordinatorDemo
//
// Created by Timotheus Laubengaier on 2021/10/15.
//

import Foundation
import UIKit

class ProfileSettingsListCell: UITableViewCell {

static let identifier = "ProfileSettingsListCell"

lazy var iconView: UIImageView = {
let view = UIImageView()
view.tintColor = .label
view.contentMode = .scaleAspectFit
return view
}()

lazy var titleLabel: UILabel = {
let view = UILabel()
view.font = .systemFont(ofSize: 14, weight: .medium)
return view
}()

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)

selectionStyle = .none
accessoryType = .disclosureIndicator

contentView.addSubview(iconView)
iconView.snp.makeConstraints { make in
make.leading.equalTo(contentView).inset(20)
make.top.equalTo(contentView).inset(15)
make.bottom.equalTo(contentView).inset(15).priority(999)
make.size.equalTo(20)
}

contentView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { make in
make.leading.equalTo(iconView.snp.trailing).offset(10)
make.top.bottom.equalTo(contentView)
make.trailing.equalTo(contentView).inset(20)
}
}

required init?(coder: NSCoder) { return nil }

override func prepareForReuse() {
super.prepareForReuse()
iconView.image = nil
titleLabel.text = ""
}

func setup(iconName: String, title: String, isDestructive: Bool = false, showDisclosureIndicator: Bool = false) {
iconView.image = UIImage(systemName: iconName)
titleLabel.text = title
iconView.tintColor = isDestructive ? .systemRed : .label
titleLabel.textColor = isDestructive ? .systemRed : .label
accessoryType = showDisclosureIndicator ? .none : .disclosureIndicator
}
}

0 comments on commit de736b4

Please sign in to comment.