// // UserActivityHandlingContext.swift // Tusker // // Created by Shadowfacts on 2/25/23. // Copyright © 2023 Shadowfacts. All rights reserved. // import UIKit import Duckable @MainActor protocol UserActivityHandlingContext { var isHandoff: Bool { get } func select(route: TuskerRoute) func present(_ vc: UIViewController) var topViewController: UIViewController? { get } func popToRoot() func push(_ vc: UIViewController) func compose(editing draft: Draft) func finalize(activity: NSUserActivity) } struct ActiveAccountUserActivityHandlingContext: UserActivityHandlingContext { let isHandoff: Bool let root: TuskerRootViewController var navigationDelegate: TuskerNavigationDelegate { root.getNavigationDelegate()! } func select(route: TuskerRoute) { root.select(route: route, animated: true) } func present(_ vc: UIViewController) { navigationDelegate.present(vc, animated: true) } var topViewController: UIViewController? { root.getNavigationController().topViewController } func popToRoot() { _ = root.getNavigationController().popToRootViewController(animated: true) } func push(_ vc: UIViewController) { navigationDelegate.show(vc, sender: nil) } func compose(editing draft: Draft) { navigationDelegate.compose(editing: draft, animated: true, isDucked: true) } func finalize(activity: NSUserActivity) { } } class StateRestorationUserActivityHandlingContext: UserActivityHandlingContext { private var state = State.initial let root: TuskerRootViewController init(root: TuskerRootViewController) { self.root = root } var isHandoff: Bool { false } func select(route: TuskerRoute) { root.select(route: route, animated: false) state = .selectedRoute } var topViewController: UIViewController? { root.getNavigationController().topViewController } func popToRoot() { // unnecessary during state restoration } func push(_ vc: UIViewController) { precondition(state >= .selectedRoute) root.getNavigationController().pushViewController(vc, animated: false) state = .pushed } func present(_ vc: UIViewController) { root.present(vc, animated: false) state = .presented } func compose(editing draft: Draft) { if #available(iOS 16.0, *), UIDevice.current.userInterfaceIdiom == .phone { self.root.compose(editing: draft, animated: false, isDucked: true) } else { DispatchQueue.main.async { self.root.compose(editing: draft, animated: true, isDucked: false) } } state = .presented } func finalize(activity: NSUserActivity) { precondition(state > .initial) if #available(iOS 16.0, *), let duckedDraft = UserActivityManager.getDuckedDraft(from: activity) { self.root.compose(editing: duckedDraft, animated: false, isDucked: true) } } enum State: Comparable { case initial case selectedRoute case pushed case presented } }