AutoCat/AutoCat/SceneDelegate.swift

252 lines
9.4 KiB
Swift

import UIKit
import os.log
import AVFoundation
import PKHUD
import AutoCatCore
import SwiftLocation
import CoreLocation
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
var number: String?
if let activity = connectionOptions.userActivities.first {
if let url = activity.webpageURL {
if let param = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.first, let token = param.value {
if let jwt = JWT<NumberPayload>(string: token) {
number = jwt.payload.plateNumber
}
}
}
}
Task {
try? await registerServices()
setupRootController(scene: scene, openReport: number)
}
}
func registerServices() async throws {
let container = ServiceContainer.shared
let settingsService = await SettingsService()
container.register(SettingsServiceProtocol.self, instance: settingsService)
let apiService = ApiService(settingsService: settingsService)
container.register(ApiServiceProtocol.self, instance: apiService)
let locationService = LocationService(
geocoder: CLGeocoder(),
locationManager: Location(),
settingsService: settingsService
)
container.register(LocationServiceProtocol.self, instance: locationService)
let storageService = try await StorageService(settingsService: settingsService)
container.register(StorageServiceProtocol.self, instance: storageService)
let vehicleService = VehicleService(apiService: apiService,
storageService: storageService,
locationService: locationService)
container.register(VehicleServiceProtocol.self, instance: vehicleService)
let audioRecordService = AudioRecordService()
container.register(AudioRecordServiceProtocol.self, instance: audioRecordService)
let vehicleRecordService = VehicleRecordService(
recordService: audioRecordService,
locationService: locationService,
settingsService: settingsService
)
container.register(VehicleRecordServiceProtocol.self, instance: vehicleRecordService)
container.register(RecordPlayerServiceProtocol.self, instance: RecordPlayerService())
}
func setupRootController(scene: UIScene, openReport number: String?) {
guard let windowScene = (scene as? UIWindowScene) else {
return
}
self.window = UIWindow(windowScene: windowScene)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let settingsService = ServiceContainer.shared.resolve(SettingsServiceProtocol.self)
if settingsService.user.token.isEmpty {
let coordinator = AuthCoordinator(window: self.window)
self.window?.rootViewController = coordinator.start()
//self.window?.rootViewController = storyboard.instantiateViewController(identifier: "AuthController")
} else {
self.window?.rootViewController = storyboard.instantiateViewController(identifier: "MainSplitController")
if let number {
Task { await openReport(with: number) }
}
}
#if targetEnvironment(macCatalyst)
let toolbar = NSToolbar(identifier: "main")
toolbar.delegate = self
toolbar.displayMode = .iconOnly
if let titlebar = windowScene.titlebar {
titlebar.toolbar = toolbar
if #available(macCatalyst 14.0, *) {
titlebar.toolbarStyle = .unifiedCompact
}
}
#endif
self.window?.makeKeyAndVisible()
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
if let url = userActivity.webpageURL {
if let param = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.first, let token = param.value {
if let jwt = JWT<NumberPayload>(string: token) {
Task { await self.openReport(with: jwt.payload.plateNumber) }
}
}
}
}
func openReport(with number: String) async {
guard let rootController = self.window?.rootViewController else { return }
let apiService: ApiServiceProtocol = ServiceContainer.shared.resolve(ApiServiceProtocol.self)
do {
HUD.show(.progress)
let vehicle = try await apiService.getReport(for: number)
Task {
let screen = ReportScreen(vehicle: vehicle, isPersistent: false, onUpdate: { _ in })
let controller = UIHostingController(rootView: screen)
let navController = UINavigationController(rootViewController: controller)
rootController.present(navController, animated: true)
}
HUD.hide()
} catch {
HUD.show(error: error)
}
}
}
#if targetEnvironment(macCatalyst)
extension NSToolbarItem.Identifier {
static let addNumber = NSToolbarItem.Identifier("pro.aliencat.add.number")
}
extension SceneDelegate: NSToolbarDelegate {
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
let identifiers: [NSToolbarItem.Identifier] = [
.addNumber
]
return identifiers
}
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return toolbarDefaultItemIdentifiers(toolbar)
}
func toolbar(_ toolbar: NSToolbar,
itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,
willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
var toolbarItem: NSToolbarItem?
switch itemIdentifier {
case .addNumber:
let item = NSToolbarItem(itemIdentifier: itemIdentifier)
item.image = UIImage(systemName: "plus")
item.label = "Add"
item.target = self
item.action = #selector(showAddNumberPanel)
toolbarItem = item
default:
toolbarItem = nil
}
return toolbarItem
}
@objc func showAddNumberPanel() {
let controller = NewNumberController()
controller.preferredContentSize = CGSize(width: 400, height: 350)
controller.onCheck = { number in
controller.dismiss(animated: true) { [weak self] in
self?.checkNewNumber(number)
}
}
self.window?.rootViewController?.present(controller, animated: true)
}
func checkNewNumber(_ number: String) {
guard let split = self.window?.rootViewController as? MainSplitController,
let tabvc = split.viewControllers.first as? MainTabController
else {
return
}
tabvc.selectedIndex = 0
Task {
await tabvc.historyViewModel?.checkNewNumber(number)
}
}
}
#endif