// // ImportController.swift // Delta // // Created by Riley Testut on 10/10/15. // Copyright © 2015 Riley Testut. All rights reserved. // import UIKit import ObjectiveC import DeltaCore protocol ImportControllerDelegate { func importController(_ importController: ImportController, didImport games: Set) func importController(_ importController: ImportController, didImport controllerSkins: Set) /** Optional **/ func importControllerDidCancel(_ importController: ImportController) } extension ImportControllerDelegate { func importControllerDidCancel(_ importController: ImportController) { // Empty Implementation } } class ImportController: NSObject { var delegate: ImportControllerDelegate? fileprivate weak var presentingViewController: UIViewController? fileprivate func presentImportController(from presentingViewController: UIViewController, animated: Bool, completion: ((Void) -> Void)?) { self.presentingViewController = presentingViewController var documentTypes = Game.supportedTypes.map { $0.rawValue } documentTypes.append(kUTTypeDeltaControllerSkin as String) #if os(iOS) let documentMenuController = UIDocumentMenuViewController(documentTypes: documentTypes, in: .import) documentMenuController.delegate = self documentMenuController.addOption(withTitle: NSLocalizedString("iTunes", comment: ""), image: nil, order: .first) { self.importFromiTunes(nil) } self.presentingViewController?.present(documentMenuController, animated: true, completion: nil) #else self.importFromiTunes(completion) #endif } private func importFromiTunes(_ completion: ((Void) -> Void)?) { let alertController = UIAlertController(title: NSLocalizedString("Import from iTunes?", comment: ""), message: NSLocalizedString("Delta will import the games and controller skins copied over via iTunes.", comment: ""), preferredStyle: .alert) let importAction = UIAlertAction(title: NSLocalizedString("Import", comment: ""), style: .default) { action in let documentsDirectoryURL = DatabaseManager.defaultDirectoryURL().deletingLastPathComponent() do { let contents = try FileManager.default.contentsOfDirectory(at: documentsDirectoryURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles) DatabaseManager.shared.performBackgroundTask { (context) in let controllerSkinURLs = contents.filter { $0.pathExtension == "deltaskin" } self.importControllerSkins(at: controllerSkinURLs) let gameURLs = contents.filter { GameCollection.gameSystemCollectionForPathExtension($0.pathExtension, inManagedObjectContext: context).identifier != GameType.delta.rawValue } self.importGames(at: gameURLs) } } catch let error as NSError { print(error) } self.presentingViewController?.importController = nil } alertController.addAction(importAction) let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { action in self.delegate?.importControllerDidCancel(self) self.presentingViewController?.importController = nil } alertController.addAction(cancelAction) self.presentingViewController?.present(alertController, animated: true, completion: completion) } fileprivate func importGames(at urls: [URL]) { DatabaseManager.shared.importGames(at: urls) { identifiers in DatabaseManager.shared.viewContext.perform() { let predicate = NSPredicate(format: "%K IN (%@)", #keyPath(Game.identifier), identifiers) let games = Game.instancesWithPredicate(predicate, inManagedObjectContext: DatabaseManager.shared.viewContext, type: Game.self) self.delegate?.importController(self, didImport: Set(games)) self.presentingViewController?.importController = nil } } } fileprivate func importControllerSkins(at urls: [URL]) { DatabaseManager.shared.importControllerSkins(at: urls) { identifiers in DatabaseManager.shared.viewContext.perform() { let predicate = NSPredicate(format: "%K IN (%@)", #keyPath(ControllerSkin.identifier), identifiers) let controllerSkins = ControllerSkin.instancesWithPredicate(predicate, inManagedObjectContext: DatabaseManager.shared.viewContext, type: ControllerSkin.self) self.delegate?.importController(self, didImport: Set(controllerSkins)) self.presentingViewController?.importController = nil } } } } #if os(iOS) extension ImportController: UIDocumentMenuDelegate { func documentMenu(_ documentMenu: UIDocumentMenuViewController, didPickDocumentPicker documentPicker: UIDocumentPickerViewController) { documentPicker.delegate = self self.presentingViewController?.present(documentPicker, animated: true, completion: nil) } func documentMenuWasCancelled(_ documentMenu: UIDocumentMenuViewController) { self.delegate?.importControllerDidCancel(self) self.presentingViewController?.importController = nil } } extension ImportController: UIDocumentPickerDelegate { func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) { if url.pathExtension == "deltaskin" { self.importControllerSkins(at: [url]) } else { self.importGames(at: [url]) } self.presentingViewController?.importController = nil } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { self.delegate?.importControllerDidCancel(self) self.presentingViewController?.importController = nil } } #endif private var ImportControllerKey: UInt8 = 0 extension UIViewController { fileprivate(set) var importController: ImportController? { set { objc_setAssociatedObject(self, &ImportControllerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } get { return objc_getAssociatedObject(self, &ImportControllerKey) as? ImportController } } func present(_ importController: ImportController, animated: Bool, completion: ((Void) -> Void)?) { self.importController = importController importController.presentImportController(from: self, animated: animated, completion: completion) } }