GBA-8-19/Delta/Scenes/SceneDelegate.swift
2024-06-14 17:15:51 +08:00

191 lines
6.6 KiB
Swift

//
// SceneDelegate.swift
// Hthik
//
// Created by Hthik on 6/6/22.
// Copyright © 2022 Hthik. All rights reserved.
//
import UIKit
import DeltaCore
import Harmony
@objc(SceneDelegate) @available(iOS 13, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate
{
var window: UIWindow? {
get {
if _window == nil
{
_window = GameWindow()
}
return _window
}
set {
_window = newValue as? GameWindow
}
}
private var _window: GameWindow?
private let deepLinkController = DeepLinkController()
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).
self.window?.tintColor = .deltaPurple
if let context = connectionOptions.urlContexts.first
{
self.handle(.url(context.url))
}
if let shortcutItem = connectionOptions.shortcutItem
{
self.handle(.shortcut(shortcutItem))
}
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 necessarily 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.
}
}
@available(iOS 13, *)
extension SceneDelegate
{
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)
{
guard let context = URLContexts.first else { return }
self.handle(.url(context.url))
}
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void)
{
self.handle(.shortcut(shortcutItem))
completionHandler(true)
}
}
@available(iOS 13, *)
private extension SceneDelegate
{
func handle(_ deepLink: DeepLink)
{
guard DatabaseManager.shared.isStarted else {
// Wait until DatabaseManager is ready before handling deep link.
// NotificationCenter.default.notifications requires iOS 15 or later :(
// _ = await NotificationCenter.default.notifications(named: DatabaseManager.didStartNotification).first(where: { _ in true })
var observer: NSObjectProtocol?
observer = NotificationCenter.default.addObserver(forName: DatabaseManager.didStartNotification, object: DatabaseManager.shared, queue: .main) { [weak observer] _ in
observer.map { NotificationCenter.default.removeObserver($0) }
self.handle(deepLink)
}
return
}
DispatchQueue.main.async {
// DeepLinkController expects to be called from main thread.
switch deepLink
{
case .shortcut:
_ = self.deepLinkController.handle(deepLink)
case .url(let url):
if url.isFileURL
{
if GameType(fileExtension: url.pathExtension) != nil || url.pathExtension.lowercased() == "zip"
{
self.importGame(at: url)
}
else if url.pathExtension.lowercased() == "deltaskin"
{
self.importControllerSkin(at: url)
}
}
else if url.scheme?.hasPrefix("db-") == true
{
_ = DropboxService.shared.handleDropboxURL(url)
}
else if url.scheme?.lowercased() == "delta"
{
_ = self.deepLinkController.handle(deepLink)
}
}
}
}
func importGame(at url: URL)
{
DatabaseManager.shared.importGames(at: [url]) { (games, errors) in
if errors.count > 0
{
let alertController = UIAlertController.alertController(for: .games, with: errors)
self.present(alertController)
}
}
}
func importControllerSkin(at url: URL)
{
DatabaseManager.shared.importControllerSkins(at: [url]) { (games, errors) in
if errors.count > 0
{
let alertController = UIAlertController.alertController(for: .controllerSkins, with: errors)
self.present(alertController)
}
}
}
func present(_ alertController: UIAlertController)
{
var rootViewController = self.window?.rootViewController
while rootViewController?.presentedViewController != nil
{
rootViewController = rootViewController?.presentedViewController
}
rootViewController?.present(alertController, animated: true, completion: nil)
}
}