Tusker/Tusker/AppDelegate.swift

157 lines
5.8 KiB
Swift

//
// AppDelegate.swift
// Tusker
//
// Created by Shadowfacts on 8/15/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import UIKit
import CoreData
import OSLog
import Sentry
let stateRestorationLogger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "StateRestoration")
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
configureSentry()
swizzleStatusBar()
AppShortcutItem.createItems(for: application)
DispatchQueue.global(qos: .userInitiated).async {
AudioSessionHelper.disable()
AudioSessionHelper.setDefault()
}
if let oldSavedData = SavedDataManager.load() {
do {
for account in oldSavedData.accountIDs {
guard let account = LocalData.shared.getAccount(id: account) else {
continue
}
let controller = MastodonController.getForAccount(account)
try oldSavedData.migrateToCoreData(accountID: account.id, context: controller.persistentContainer.viewContext)
if controller.persistentContainer.viewContext.hasChanges {
try controller.persistentContainer.viewContext.save()
}
}
try SavedDataManager.destroy()
} catch {
// no-op
}
}
return true
}
private func configureSentry() {
guard let dsn = Bundle.main.object(forInfoDictionaryKey: "SentryDSN") as? String,
!dsn.isEmpty else {
return
}
SentrySDK.start { options in
#if DEBUG
options.debug = true
options.environment = "dev"
#endif
// the '//' in the full url can't be escaped, so we have to add the scheme back
options.dsn = "https://\(dsn)"
options.enableSwizzling = false
// required to support releases/release health
options.enableAutoSessionTracking = true
options.enableOutOfMemoryTracking = false
options.enableAutoPerformanceTracking = false
options.enableNetworkTracking = false
options.enableAppHangTracking = false
options.enableCoreDataTracking = false
// we don't care about events like battery, keyboard show/hide
options.enableAutoBreadcrumbTracking = false
options.beforeSend = { event in
// just no, why would anyone need this information
event.context?.removeValue(forKey: "culture")
return Preferences.shared.reportErrorsAutomatically ? event : nil
}
}
}
override func buildMenu(with builder: UIMenuBuilder) {
if builder.system == .main {
MenuController.buildMainMenu(builder: builder)
}
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
let name = getSceneNameForActivity(options.userActivities.first)
return UISceneConfiguration(name: name, sessionRole: connectingSceneSession.role)
}
private func getSceneNameForActivity(_ activity: NSUserActivity?) -> String {
guard let activity = activity,
let type = UserActivityType(rawValue: activity.activityType) else {
return "main-scene"
}
switch type {
case .mainScene:
return "main-scene"
case .showConversation,
.showTimeline,
.checkNotifications,
.search,
.bookmarks,
.myProfile,
.showProfile:
if activity.displaysAuxiliaryScene {
stateRestorationLogger.info("Using auxiliary scene for \(type.rawValue, privacy: .public)")
return "auxiliary"
} else {
return "main-scene"
}
case .newPost:
return "compose"
}
}
@objc func closeWindow() {
guard let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) else {
return
}
UIApplication.shared.requestSceneSessionDestruction(scene.session, options: nil)
}
private func swizzleStatusBar() {
let selector = Selector(("handleTapAction:"))
var originalIMP: IMP?
let imp = imp_implementationWithBlock({ (self: UIStatusBarManager, sender: AnyObject) in
let original = unsafeBitCast(originalIMP!, to: (@convention(c) (UIStatusBarManager, Selector, AnyObject) -> Void).self)
guard let windowScene = self.perform(Selector(("windowScene"))).takeUnretainedValue() as? UIWindowScene,
let xPosition = sender.value(forKey: "xPosition") as? CGFloat,
let delegate = windowScene.delegate as? TuskerSceneDelegate else {
original(self, selector, sender)
return
}
switch delegate.handleStatusBarTapped(xPosition: xPosition) {
case .stop:
return
case .continue:
original(self, selector, sender)
}
} as @convention(block) (UIStatusBarManager, AnyObject) -> Void)
originalIMP = class_replaceMethod(UIStatusBarManager.self, selector, imp, "v@:@")
if originalIMP == nil {
Logging.general.error("Unable to swizzle status bar manager")
}
}
}