Tusker/Tusker/Shortcuts/UserActivityHandlingContext...

125 lines
3.3 KiB
Swift

//
// UserActivityHandlingContext.swift
// Tusker
//
// Created by Shadowfacts on 2/25/23.
// Copyright © 2023 Shadowfacts. All rights reserved.
//
import UIKit
#if canImport(Duckable)
import Duckable
#endif
import ComposeUI
@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 !os(visionOS)
if #available(iOS 16.0, *),
let duckedDraft = UserActivityManager.getDuckedDraft(from: activity) {
self.root.compose(editing: duckedDraft, animated: false, isDucked: true)
}
#endif
}
enum State: Comparable {
case initial
case selectedRoute
case pushed
case presented
}
}