mastodon-ios/Mastodon/Coordinator/SceneCoordinator.swift

221 lines
8.6 KiB
Swift
Raw Normal View History

2021-01-27 07:50:13 +01:00
//
// SceneCoordinator.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-1-27.
import UIKit
import SafariServices
2021-02-20 06:56:24 +01:00
import CoreDataStack
2021-01-27 07:50:13 +01:00
final public class SceneCoordinator {
private weak var scene: UIScene!
private weak var sceneDelegate: SceneDelegate!
private weak var appContext: AppContext!
let id = UUID().uuidString
init(scene: UIScene, sceneDelegate: SceneDelegate, appContext: AppContext) {
self.scene = scene
self.sceneDelegate = sceneDelegate
self.appContext = appContext
scene.session.sceneCoordinator = self
}
}
extension SceneCoordinator {
enum Transition {
case show // push
case showDetail // replace
case modal(animated: Bool, completion: (() -> Void)? = nil)
case custom(transitioningDelegate: UIViewControllerTransitioningDelegate)
case customPush
case safariPresent(animated: Bool, completion: (() -> Void)? = nil)
case activityViewControllerPresent(animated: Bool, completion: (() -> Void)? = nil)
case alertController(animated: Bool, completion: (() -> Void)? = nil)
}
enum Scene {
2021-02-26 11:27:47 +01:00
// onboarding
2021-02-20 06:56:24 +01:00
case welcome
2021-02-26 11:27:47 +01:00
case mastodonPickServer(viewMode: MastodonPickServerViewModel)
2021-02-02 12:31:10 +01:00
case mastodonPinBasedAuthentication(viewModel: MastodonPinBasedAuthenticationViewModel)
2021-02-05 10:53:00 +01:00
case mastodonRegister(viewModel: MastodonRegisterViewModel)
2021-02-22 09:20:44 +01:00
case mastodonServerRules(viewModel: MastodonServerRulesViewModel)
2021-02-23 08:38:05 +01:00
case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel)
case mastodonResendEmail(viewModel: MastodonResendEmailViewModel)
2021-02-03 09:01:08 +01:00
2021-02-26 11:27:47 +01:00
// misc
2021-02-03 09:01:08 +01:00
case alertController(alertController: UIAlertController)
2021-02-24 11:07:11 +01:00
#if DEBUG
case publicTimeline
#endif
2021-02-26 11:27:47 +01:00
var isOnboarding: Bool {
switch self {
case .welcome,
.mastodonPickServer,
.mastodonPinBasedAuthentication,
.mastodonRegister,
.mastodonServerRules,
.mastodonConfirmEmail,
.mastodonResendEmail:
return true
default:
return false
}
}
2021-01-27 07:50:13 +01:00
}
}
extension SceneCoordinator {
func setup() {
2021-02-26 11:27:47 +01:00
let viewController = MainTabBarController(context: appContext, coordinator: self)
sceneDelegate.window?.rootViewController = viewController
}
func setupOnboardingIfNeeds(animated: Bool) {
// Check user authentication status and show onboarding if needs
2021-02-20 06:56:24 +01:00
do {
2021-02-26 11:27:47 +01:00
let request = MastodonAuthentication.sortedFetchRequest
if try appContext.managedObjectContext.fetch(request).isEmpty {
DispatchQueue.main.async {
self.present(
scene: .welcome,
from: nil,
transition: .modal(animated: animated, completion: nil)
)
2021-02-20 06:56:24 +01:00
}
}
} catch {
2021-02-26 11:27:47 +01:00
assertionFailure(error.localizedDescription)
2021-02-20 06:56:24 +01:00
}
2021-01-27 07:50:13 +01:00
}
@discardableResult
func present(scene: Scene, from sender: UIViewController?, transition: Transition) -> UIViewController? {
guard let viewController = get(scene: scene) else {
return nil
}
guard var presentingViewController = sender ?? sceneDelegate.window?.rootViewController?.topMost else {
return nil
}
if let mainTabBarController = presentingViewController as? MainTabBarController,
let navigationController = mainTabBarController.selectedViewController as? UINavigationController,
let topViewController = navigationController.topViewController {
presentingViewController = topViewController
}
switch transition {
case .show:
presentingViewController.show(viewController, sender: sender)
case .showDetail:
let navigationController = UINavigationController(rootViewController: viewController)
presentingViewController.showDetailViewController(navigationController, sender: sender)
case .modal(let animated, let completion):
2021-02-26 11:27:47 +01:00
let modalNavigationController: UINavigationController = {
if scene.isOnboarding {
return DarkContentStatusBarStyleNavigationController(rootViewController: viewController)
} else {
return UINavigationController(rootViewController: viewController)
}
}()
2021-01-27 07:50:13 +01:00
if let adaptivePresentationControllerDelegate = viewController as? UIAdaptivePresentationControllerDelegate {
modalNavigationController.presentationController?.delegate = adaptivePresentationControllerDelegate
}
presentingViewController.present(modalNavigationController, animated: animated, completion: completion)
case .custom(let transitioningDelegate):
viewController.modalPresentationStyle = .custom
viewController.transitioningDelegate = transitioningDelegate
sender?.present(viewController, animated: true, completion: nil)
case .customPush:
// set delegate in view controller
assert(sender?.navigationController?.delegate != nil)
sender?.navigationController?.pushViewController(viewController, animated: true)
case .safariPresent(let animated, let completion):
presentingViewController.present(viewController, animated: animated, completion: completion)
case .activityViewControllerPresent(let animated, let completion):
presentingViewController.present(viewController, animated: animated, completion: completion)
case .alertController(let animated, let completion):
presentingViewController.present(viewController, animated: animated, completion: completion)
}
return viewController
}
}
private extension SceneCoordinator {
func get(scene: Scene) -> UIViewController? {
let viewController: UIViewController?
2021-02-02 08:38:54 +01:00
switch scene {
2021-02-20 06:56:24 +01:00
case .welcome:
let _viewController = WelcomeViewController()
viewController = _viewController
2021-02-26 11:27:47 +01:00
case .mastodonPickServer(let viewModel):
let _viewController = MastodonPickServerViewController()
2021-02-02 08:38:54 +01:00
_viewController.viewModel = viewModel
viewController = _viewController
2021-02-02 12:31:10 +01:00
case .mastodonPinBasedAuthentication(let viewModel):
let _viewController = MastodonPinBasedAuthenticationViewController()
_viewController.viewModel = viewModel
viewController = _viewController
2021-02-05 10:53:00 +01:00
case .mastodonRegister(let viewModel):
let _viewController = MastodonRegisterViewController()
_viewController.viewModel = viewModel
viewController = _viewController
2021-02-22 09:20:44 +01:00
case .mastodonServerRules(let viewModel):
let _viewController = MastodonServerRulesViewController()
_viewController.viewModel = viewModel
viewController = _viewController
2021-02-23 08:38:05 +01:00
case .mastodonConfirmEmail(let viewModel):
let _viewController = MastodonConfirmEmailViewController()
_viewController.viewModel = viewModel
viewController = _viewController
case .mastodonResendEmail(let viewModel):
let _viewController = MastodonResendEmailViewController()
_viewController.viewModel = viewModel
viewController = _viewController
2021-02-03 09:01:08 +01:00
case .alertController(let alertController):
if let popoverPresentationController = alertController.popoverPresentationController {
assert(
popoverPresentationController.sourceView != nil ||
popoverPresentationController.sourceRect != .zero ||
popoverPresentationController.barButtonItem != nil
)
}
viewController = alertController
2021-02-24 11:07:11 +01:00
#if DEBUG
case .publicTimeline:
let _viewController = PublicTimelineViewController()
_viewController.viewModel = PublicTimelineViewModel(context: appContext)
viewController = _viewController
#endif
2021-02-02 08:38:54 +01:00
}
2021-01-27 07:50:13 +01:00
setupDependency(for: viewController as? NeedsDependency)
return viewController
}
private func setupDependency(for needs: NeedsDependency?) {
needs?.context = appContext
needs?.coordinator = self
}
}