Skip to content

Instantly share code, notes, and snippets.

@lamprosg
Last active February 7, 2021 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lamprosg/e62b1fef70e81450abde2ab39e80431d to your computer and use it in GitHub Desktop.
Save lamprosg/e62b1fef70e81450abde2ab39e80431d to your computer and use it in GitHub Desktop.
(iOS) Onboarding flow
/// The list of the onboarding steps
enum OnboardingStep: String {
case overview
case documentScan
case saveAndLogin
}
/// The onboarding errors
///
/// - failed: Onboarding failed with the described error
enum OnboardingError: Error {
case failed(String)
}
/// Onboarding step coordinator
class OnboardingCoordinator {
private weak var navigation: UINavigationController!
private var stepManager: OnboardingStepManager!
var steps: [OnboardingStep] = []
/// OnboardingCoordinator initializer
///
/// - Parameter navigation: The navigation controller where steps will be pushed
/// - data: Any onboarding data if available
init(navigation:UINavigationController, data: OnboardingData? = nil) {
super.init()
self.navigation = navigation
self.stepManager = OnboardingStepManager(navigation: navigation, coordinator: self, data: data)
self.setUpSteps()
//Start with 1st step if available
if let firstStep = self.steps.first {
self.show(step: firstStep)
}
}
/// This should not be used
private override init() {}
/************************************=**/
/// Set up your steps here
private func setUpSteps() -> Void {
self.steps = [.overview, //Includes .editLoanDetails which is added in real time based on the user's decision to edit them
.documentScan , //Passport VC. Shows capture camera VC too
.saveAndLogin
]
updateSignatureStepFromSettings()
}
private func updateSignatureStepFromSettings() {
let showSignature: Bool = UserDefaults.standard.bool(forKey: "showSignature")
if !showSignature {
let signatureIndex = self.steps.firstIndex(of: .signature)
if let index = signatureIndex {
self.steps.remove(at: index)
}
}
}
/************************************=**/
/// Starts the onboarding flow
private func show(step:OnboardingStep) -> Void {
self.stepManager.currentStep = self.getStepIndex(for: step)
self.getMethodFor(step: step)() { [weak self] (data: OnboardingData?) in
guard let this = self else { return }
this.stepManager.data = data?.copy() as? OnboardingData
if this.stepManager.currentStep == (this.steps.count-1) {
let firstVC = this.navigation.viewControllers.first
if let loginVC: LoginViewController = firstVC as? LoginViewController {
loginVC.startDemo()
}
}
else {
this.stepManager.currentStep += 1
this.show(step: this.steps[this.stepManager.currentStep])
}
}
}
private func getMethodFor(step: OnboardingStep) -> (@escaping(_ data: OnboardingData?) -> Void) -> Void {
switch step {
case .overview:
return self.stepManager.showOverview
case .documentScan:
return self.stepManager.showDocumentScan
case .saveAndLogin:
return self.stepManager.showSaveAndLogin
}
}
private func getStepIndex(for step: OnboardingStep) -> Int {
guard let index = self.steps.firstIndex(of: step) else {
return 0
}
return index
}
func update(stepIndex:Int) -> Void {
self.stepManager.currentStep = stepIndex
}
func popViewController(with data: OnboardingData?) -> Void {
self.stepManager.data = data?.copy() as? OnboardingData
self.navigation.popViewController(animated: true)
}
}
// MARK: - Step manager
/// Onboarding step
class OnboardingStepManager {
private weak var navigation: UINavigationController!
var data: OnboardingData?
private weak var coordinator: OnboardingCoordinator?
var currentStep:Int = 0
/// Convenience OnboardingStepManager initializer
///
/// - Parameters:
/// - navigation: The navigation controller where steps will be pushed
/// - coordinator: The onboarding coordinator
/// - data: The onboarding data model if any
init(navigation:UINavigationController, coordinator: OnboardingCoordinator, data: OnboardingData? = nil) {
self.navigation = navigation
self.coordinator = coordinator
self.data = data?.copy() as? OnboardingData
}
/// This should not be used
private init() {}
/// Welcome / overview step
func showOverview(completion:@escaping(_ data: OnboardingData?) -> Void) -> Void {
let welcomeVC: WelcomeVC = WelcomeVC()
welcomeVC.stepFinishedWithSuccess = completion
welcomeVC.data = self.data?.copy() as? OnboardingData
welcomeVC.coordinator = self.coordinator
welcomeVC.currentStep = currentStep
self.navigation.pushViewController(welcomeVC, animated: true)
}
func showDocumentScan(completion: @escaping(_ data: OnboardingData?) -> Void) -> Void {
let documentScanVC: DocumentScanVC = DocumentScanVC()
documentScanVC.stepFinishedWithSuccess = completion
documentScanVC.data = self.data?.copy() as? OnboardingData
documentScanVC.coordinator = self.coordinator
documentScanVC.currentStep = currentStep
self.navigation.pushViewController(documentScanVC, animated: true)
}
func showSaveAndLogin(completion: @escaping(_ data: OnboardingData?) -> Void) -> Void {
let saveAndLoginVC: SaveAndLoginVC = aveAndLoginVC()
saveAndLoginVC.stepFinishedWithSuccess = completion
saveAndLoginVC.data = self.data?.copy() as? OnboardingData
saveAndLoginVC.coordinator = self.coordinator
saveAndLoginVC.currentStep = currentStep
self.navigation.pushViewController(saveAndLoginVC, animated: true)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment