168 lines
5.3 KiB
Swift
168 lines
5.3 KiB
Swift
import Eureka
|
|
import Shared
|
|
import SwiftUI
|
|
import UIKit
|
|
|
|
enum OnboardingBarAppearance {
|
|
case normal
|
|
case hidden
|
|
}
|
|
|
|
protocol OnboardingViewController {
|
|
var preferredBarAppearance: OnboardingBarAppearance { get }
|
|
}
|
|
|
|
class OnboardingNavigationViewController: UINavigationController, RowControllerType {
|
|
enum OnboardingStyle {
|
|
enum RequiredType {
|
|
case full
|
|
case permissions
|
|
}
|
|
|
|
case initial
|
|
case required(RequiredType)
|
|
case secondary
|
|
|
|
var insertsCancelButton: Bool {
|
|
switch self {
|
|
case .initial, .required: return false
|
|
case .secondary: return true
|
|
}
|
|
}
|
|
|
|
var modalPresentationStyle: UIModalPresentationStyle {
|
|
switch self {
|
|
case .initial, .required: return .fullScreen
|
|
case .secondary:
|
|
return .automatic
|
|
}
|
|
}
|
|
}
|
|
|
|
public static var requiredOnboardingStyle: OnboardingStyle? {
|
|
if Current.servers.all.isEmpty {
|
|
return .required(.full)
|
|
} else if OnboardingPermissionViewControllerFactory.hasControllers {
|
|
return .required(.permissions)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
public let onboardingStyle: OnboardingStyle
|
|
public var onDismissCallback: ((UIViewController) -> Void)?
|
|
|
|
public init(onboardingStyle: OnboardingStyle) {
|
|
self.onboardingStyle = onboardingStyle
|
|
|
|
let rootViewController: UIViewController
|
|
|
|
let onboardingWelcomeViewController = UIHostingController(rootView: OnboardingWelcomeView())
|
|
|
|
switch onboardingStyle {
|
|
case .initial: rootViewController = onboardingWelcomeViewController
|
|
case .secondary: rootViewController = OnboardingScanningViewController()
|
|
case let .required(type):
|
|
switch type {
|
|
case .full:
|
|
rootViewController = onboardingWelcomeViewController
|
|
case .permissions:
|
|
rootViewController = OnboardingPermissionViewControllerFactory.next(server: nil)
|
|
}
|
|
}
|
|
|
|
super.init(rootViewController: rootViewController)
|
|
modalPresentationStyle = onboardingStyle.modalPresentationStyle
|
|
|
|
if onboardingStyle.insertsCancelButton {
|
|
var leftItems = rootViewController.navigationItem.leftBarButtonItems ?? []
|
|
leftItems.append(
|
|
UIBarButtonItem(
|
|
barButtonSystemItem: .cancel,
|
|
target: self,
|
|
action: #selector(cancelTapped(_:))
|
|
)
|
|
)
|
|
rootViewController.navigationItem.leftBarButtonItems = leftItems
|
|
}
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
delegate = self
|
|
view.tintColor = Asset.Colors.haPrimary.color
|
|
navigationController?.navigationBar.tintColor = Asset.Colors.haPrimary.color
|
|
|
|
let appearance = with(UINavigationBarAppearance()) {
|
|
$0.configureWithOpaqueBackground()
|
|
$0.backgroundColor = .systemBackground
|
|
$0.shadowColor = .clear
|
|
$0.titleTextAttributes = [.foregroundColor: UIColor.label]
|
|
}
|
|
navigationBar.standardAppearance = appearance
|
|
navigationBar.scrollEdgeAppearance = appearance
|
|
navigationBar.tintColor = .label
|
|
}
|
|
|
|
@objc private func cancelTapped(_ sender: UIBarButtonItem) {
|
|
dismiss()
|
|
}
|
|
|
|
func dismiss() {
|
|
dismiss(animated: true, completion: nil)
|
|
onDismissCallback?(self)
|
|
}
|
|
|
|
override func show(_ vc: UIViewController, sender: Any?) {
|
|
if vc is OnboardingTerminalViewController {
|
|
Current.onboardingObservation.complete()
|
|
dismiss()
|
|
} else if sender as? UIViewController == topViewController {
|
|
super.show(vc, sender: sender)
|
|
} else {
|
|
Current.Log.error("unknown sender \(String(describing: sender)) wanted us to present: \(vc)")
|
|
}
|
|
}
|
|
}
|
|
|
|
extension OnboardingNavigationViewController: UINavigationControllerDelegate {
|
|
private func updateNavigationBar(for controller: UIViewController?, animated: Bool) {
|
|
let appearance: OnboardingBarAppearance
|
|
|
|
if let controller = controller as? OnboardingViewController {
|
|
appearance = controller.preferredBarAppearance
|
|
} else {
|
|
appearance = .normal
|
|
}
|
|
|
|
switch appearance {
|
|
case .normal:
|
|
setNavigationBarHidden(false, animated: animated)
|
|
case .hidden:
|
|
setNavigationBarHidden(true, animated: animated)
|
|
}
|
|
}
|
|
|
|
func navigationController(
|
|
_ navigationController: UINavigationController,
|
|
willShow viewController: UIViewController,
|
|
animated: Bool
|
|
) {
|
|
updateNavigationBar(for: viewController, animated: animated)
|
|
|
|
transitionCoordinator?.animate(alongsideTransition: { _ in
|
|
// putting the navigation bar change here causes the bar to animate in/out
|
|
}, completion: { [weak self] context in
|
|
if context.isCancelled {
|
|
self?.updateNavigationBar(for: self?.topViewController, animated: animated)
|
|
}
|
|
})
|
|
}
|
|
}
|