diff --git a/Common/Database/DatabaseManager.swift b/Common/Database/DatabaseManager.swift index 7696c89..7c06484 100644 --- a/Common/Database/DatabaseManager.swift +++ b/Common/Database/DatabaseManager.swift @@ -32,15 +32,124 @@ final class DatabaseManager: NSPersistentContainer } } +extension DatabaseManager +{ + override func newBackgroundContext() -> NSManagedObjectContext + { + let context = super.newBackgroundContext() + context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + return context + } + + override func loadPersistentStores(completionHandler block: @escaping (NSPersistentStoreDescription, Error?) -> Void) + { + super.loadPersistentStores { (description, error) in + self.prepareDatabase { + block(description, error) + } + } + } +} + +//MARK: - Preparation - +private extension DatabaseManager +{ + func prepareDatabase(completion: @escaping (Void) -> Void) + { + self.performBackgroundTask { (context) in + + for gameType in Game.supportedTypes + { + guard let deltaControllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: gameType) else { continue } + + let controllerSkin = ControllerSkin(context: context) + controllerSkin.isStandard = true + controllerSkin.filename = deltaControllerSkin.fileURL.lastPathComponent + controllerSkin.name = deltaControllerSkin.name + controllerSkin.identifier = deltaControllerSkin.identifier + controllerSkin.gameType = deltaControllerSkin.gameType + } + + do + { + try context.save() + } + catch + { + print("Failed to import standard controller skins:", error) + } + + completion() + + } + } +} + //MARK: - Importing - /// Importing extension DatabaseManager { - func importGames(at urls: [URL], completion: (([String]) -> Void)?) + func importControllerSkins(at urls: [URL], completion: ((Set) -> Void)?) { self.performBackgroundTask { (context) in - var identifiers: [String] = [] + var identifiers = Set() + + for url in urls + { + guard let deltaControllerSkin = DeltaCore.ControllerSkin(fileURL: url) else { continue } + + let controllerSkin = ControllerSkin(context: context) + + // Manually copy values to be stored in database. + // Remaining ControllerSkinProtocol requirements will be provided by the ControllerSkin's private DeltaCore.ControllerSkin instance. + controllerSkin.filename = deltaControllerSkin.identifier + ".deltaskin" + controllerSkin.name = deltaControllerSkin.name + controllerSkin.identifier = deltaControllerSkin.identifier + controllerSkin.gameType = deltaControllerSkin.gameType + + do + { + if FileManager.default.fileExists(atPath: controllerSkin.fileURL.path) + { + // Normally we'd replace item instead of delete + move, but it's crashing as of iOS 10 + // FileManager.default.replaceItemAt(controllerSkin.fileURL, withItemAt: url) + + // Controller skin exists, but we replace it with the new skin + try FileManager.default.removeItem(at: controllerSkin.fileURL) + } + + try FileManager.default.moveItem(at: url, to: controllerSkin.fileURL) + + identifiers.insert(controllerSkin.identifier) + } + catch + { + print("Import Controller Skins error:", error) + controllerSkin.managedObjectContext?.delete(controllerSkin) + } + } + + do + { + try context.save() + } + catch + { + print("Failed to save controller skin import context:", error) + + identifiers.removeAll() + } + + completion?(identifiers) + } + } + + func importGames(at urls: [URL], completion: ((Set) -> Void)?) + { + self.performBackgroundTask { (context) in + + var identifiers = Set() for url in urls { @@ -63,6 +172,7 @@ extension DatabaseManager if FileManager.default.fileExists(atPath: destinationURL.path) { + // Game already exists, so we choose not to override it and just delete the new game instead try FileManager.default.removeItem(at: url) } else @@ -70,10 +180,11 @@ extension DatabaseManager try FileManager.default.moveItem(at: url, to: destinationURL) } - identifiers.append(game.identifier) + identifiers.insert(game.identifier) } catch { + print("Import Games error:", error) game.managedObjectContext?.delete(game) } @@ -90,11 +201,7 @@ extension DatabaseManager identifiers.removeAll() } - if let completion = completion - { - completion(identifiers) - } - + completion?(identifiers) } } } diff --git a/Common/Database/Model/ControllerSkin.swift b/Common/Database/Model/ControllerSkin.swift index 344cd61..2314d23 100644 --- a/Common/Database/Model/ControllerSkin.swift +++ b/Common/Database/Model/ControllerSkin.swift @@ -14,7 +14,7 @@ import DeltaCore public class ControllerSkin: _ControllerSkin { public var fileURL: URL { - let fileURL = DatabaseManager.controllerSkinsDirectoryURL(for: self.gameType).appendingPathComponent(self.filename) + let fileURL = self.isStandard ? self.controllerSkin!.fileURL : DatabaseManager.controllerSkinsDirectoryURL(for: self.gameType).appendingPathComponent(self.filename) return fileURL } @@ -22,7 +22,10 @@ public class ControllerSkin: _ControllerSkin return self.controllerSkin?.isDebugModeEnabled ?? false } - fileprivate lazy var controllerSkin: DeltaCore.ControllerSkin? = DeltaCore.ControllerSkin(fileURL: self.fileURL) + fileprivate lazy var controllerSkin: DeltaCore.ControllerSkin? = { + let controllerSkin = self.isStandard ? DeltaCore.ControllerSkin.standardControllerSkin(for: self.gameType) : DeltaCore.ControllerSkin(fileURL: self.fileURL) + return controllerSkin + }() } extension ControllerSkin: ControllerSkinProtocol diff --git a/Common/Database/Model/Delta.xcdatamodeld/Model.xcdatamodel/contents b/Common/Database/Model/Delta.xcdatamodeld/Model.xcdatamodel/contents index 29601f8..66f6b6a 100644 --- a/Common/Database/Model/Delta.xcdatamodeld/Model.xcdatamodel/contents +++ b/Common/Database/Model/Delta.xcdatamodeld/Model.xcdatamodel/contents @@ -27,6 +27,7 @@ + @@ -98,7 +99,7 @@ - + diff --git a/Common/Database/Model/Game.swift b/Common/Database/Model/Game.swift index 4d7f844..19c6221 100644 --- a/Common/Database/Model/Game.swift +++ b/Common/Database/Model/Game.swift @@ -75,8 +75,8 @@ extension Game extension Game { - class func supportedTypeIdentifiers() -> Set + class var supportedTypes: Set { - return [GameType.snes.rawValue, GameType.gba.rawValue] + return [GameType.snes, GameType.gba] } } diff --git a/Common/Database/Model/_ControllerSkin.swift b/Common/Database/Model/_ControllerSkin.swift index be93661..19db822 100644 --- a/Common/Database/Model/_ControllerSkin.swift +++ b/Common/Database/Model/_ControllerSkin.swift @@ -20,6 +20,8 @@ public class _ControllerSkin: NSManagedObject @NSManaged public var identifier: String + @NSManaged public var isStandard: Bool + @NSManaged public var name: String // MARK: - Relationships diff --git a/Common/Importing/GamePickerController.swift b/Common/Importing/GamePickerController.swift deleted file mode 100644 index 29402b4..0000000 --- a/Common/Importing/GamePickerController.swift +++ /dev/null @@ -1,165 +0,0 @@ -// -// GamePickerController.swift -// Delta -// -// Created by Riley Testut on 10/10/15. -// Copyright © 2015 Riley Testut. All rights reserved. -// - -import UIKit -import ObjectiveC - -import DeltaCore - -protocol GamePickerControllerDelegate -{ - func gamePickerController(_ gamePickerController: GamePickerController, didImportGames games: [Game]) - - /** Optional **/ - func gamePickerControllerDidCancel(_ gamePickerController: GamePickerController) -} - -extension GamePickerControllerDelegate -{ - func gamePickerControllerDidCancel(_ gamePickerController: GamePickerController) - { - // Empty Implementation - } -} - -class GamePickerController: NSObject -{ - var delegate: GamePickerControllerDelegate? - - fileprivate weak var presentingViewController: UIViewController? - - fileprivate func presentGamePickerControllerFromPresentingViewController(_ presentingViewController: UIViewController, animated: Bool, completion: ((Void) -> Void)?) - { - self.presentingViewController = presentingViewController - - #if os(iOS) - let documentMenuController = UIDocumentMenuViewController(documentTypes: Array(Game.supportedTypeIdentifiers()), 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 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 gameURLs = contents.filter({ GameCollection.gameSystemCollectionForPathExtension($0.pathExtension, inManagedObjectContext: context).identifier != GameType.delta.rawValue }) - self.importGamesAtURLs(gameURLs) - } - - } - catch let error as NSError - { - print(error) - } - - self.presentingViewController?.gamePickerController = nil - - } - alertController.addAction(importAction) - - let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { action in - self.delegate?.gamePickerControllerDidCancel(self) - self.presentingViewController?.gamePickerController = nil - } - alertController.addAction(cancelAction) - - self.presentingViewController?.present(alertController, animated: true, completion: completion) - } - - fileprivate func importGamesAtURLs(_ 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?.gamePickerController(self, didImportGames: games) - - self.presentingViewController?.gamePickerController = nil - - } - } - } -} - -#if os(iOS) - - extension GamePickerController: 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?.gamePickerControllerDidCancel(self) - - self.presentingViewController?.gamePickerController = nil - } - - } - - extension GamePickerController: UIDocumentPickerDelegate - { - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) - { - self.importGamesAtURLs([url]) - - self.presentingViewController?.gamePickerController = nil - } - - func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) - { - self.delegate?.gamePickerControllerDidCancel(self) - - self.presentingViewController?.gamePickerController = nil - } - } - -#endif - -private var GamePickerControllerKey: UInt8 = 0 - -extension UIViewController -{ - fileprivate(set) var gamePickerController: GamePickerController? - { - set - { - objc_setAssociatedObject(self, &GamePickerControllerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) - } - get - { - return objc_getAssociatedObject(self, &GamePickerControllerKey) as? GamePickerController - } - } - - func presentGamePickerController(_ gamePickerController: GamePickerController, animated: Bool, completion: ((Void) -> Void)?) - { - self.gamePickerController = gamePickerController - - gamePickerController.presentGamePickerControllerFromPresentingViewController(self, animated: animated, completion: completion) - } -} diff --git a/Common/Importing/ImportController.swift b/Common/Importing/ImportController.swift new file mode 100644 index 0000000..09b1c2b --- /dev/null +++ b/Common/Importing/ImportController.swift @@ -0,0 +1,196 @@ +// +// 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) + } +} diff --git a/Cores/DeltaCore b/Cores/DeltaCore index 6558b6e..4320885 160000 --- a/Cores/DeltaCore +++ b/Cores/DeltaCore @@ -1 +1 @@ -Subproject commit 6558b6e5198ef9ae20e5ba9e68e4389fb210b66f +Subproject commit 43208853591dd1e24bd6aedaa81a6271a2016e28 diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index be9e2e7..ec6055d 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -63,7 +63,7 @@ BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */; }; BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */; }; BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540041C5DA70400C1184C /* SaveStatesViewController.swift */; }; - BFDB28451BC9DA7B001D0C83 /* GamePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB28441BC9DA7B001D0C83 /* GamePickerController.swift */; }; + BFDB28451BC9DA7B001D0C83 /* ImportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB28441BC9DA7B001D0C83 /* ImportController.swift */; }; BFDD04EF1D5E27DB002D450E /* NSFetchedResultsController+Conveniences.m in Sources */ = {isa = PBXBuildFile; fileRef = BF02BCFF1D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m */; }; BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */; }; BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */; }; @@ -161,7 +161,7 @@ BFC853361DB039B500E8C372 /* ControllerSkin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControllerSkin.swift; sourceTree = ""; }; BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatsViewController.swift; path = "Pause Menu/Cheats/CheatsViewController.swift"; sourceTree = ""; }; BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewControllerContextTransitioning+Conveniences.swift"; sourceTree = ""; }; - BFDB28441BC9DA7B001D0C83 /* GamePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamePickerController.swift; sourceTree = ""; }; + BFDB28441BC9DA7B001D0C83 /* ImportController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportController.swift; sourceTree = ""; }; BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = ""; }; BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SaveStatesStoryboardSegue.swift; path = Segues/SaveStatesStoryboardSegue.swift; sourceTree = ""; }; BFEC732C1AAECC4A00650035 /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -410,7 +410,7 @@ BFDB28431BC9D9D1001D0C83 /* Importing */ = { isa = PBXGroup; children = ( - BFDB28441BC9DA7B001D0C83 /* GamePickerController.swift */, + BFDB28441BC9DA7B001D0C83 /* ImportController.swift */, ); path = Importing; sourceTree = ""; @@ -706,7 +706,7 @@ BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */, BF2898231DAAFD720023D8E9 /* _GameCollection.swift in Sources */, BF353FF21C5D7FB000C1184C /* PauseViewController.swift in Sources */, - BFDB28451BC9DA7B001D0C83 /* GamePickerController.swift in Sources */, + BFDB28451BC9DA7B001D0C83 /* ImportController.swift in Sources */, BF2898151DAAFC2A0023D8E9 /* Cheat.swift in Sources */, BF696B801D9B2B02009639E0 /* Theme.swift in Sources */, BF7AE8081C2E858400B1B5BC /* PauseMenuViewController.swift in Sources */, diff --git a/Delta/Game Selection/GamesViewController.swift b/Delta/Game Selection/GamesViewController.swift index 9a72d1b..5c6dc29 100644 --- a/Delta/Game Selection/GamesViewController.swift +++ b/Delta/Game Selection/GamesViewController.swift @@ -246,20 +246,25 @@ private extension GamesViewController //MARK: - Importing - /// Importing -extension GamesViewController: GamePickerControllerDelegate +extension GamesViewController: ImportControllerDelegate { @IBAction fileprivate func importFiles() { - let gamePickerController = GamePickerController() - gamePickerController.delegate = self - self.presentGamePickerController(gamePickerController, animated: true, completion: nil) + let importController = ImportController() + importController.delegate = self + self.present(importController, animated: true, completion: nil) } - //MARK: - GamePickerControllerDelegate - func gamePickerController(_ gamePickerController: GamePickerController, didImportGames games: [Game]) + //MARK: - ImportControllerDelegate + @nonobjc func importController(_ importController: ImportController, didImport games: Set) { print(games) } + + @nonobjc func importController(_ importController: ImportController, didImport controllerSkins: Set) + { + print(controllerSkins) + } } //MARK: - UIPageViewController - diff --git a/Delta/Supporting Files/Info.plist b/Delta/Supporting Files/Info.plist index d5e31d6..f6feb5a 100644 --- a/Delta/Supporting Files/Info.plist +++ b/Delta/Supporting Files/Info.plist @@ -32,6 +32,20 @@ com.rileytestut.delta.game.gba + + CFBundleTypeIconFiles + + CFBundleTypeName + Delta Controller Skin + CFBundleTypeRole + Viewer + LSHandlerRank + Owner + LSItemContentTypes + + com.rileytestut.delta.skin + + CFBundleExecutable $(EXECUTABLE_NAME) @@ -118,6 +132,22 @@ gba + + UTTypeConformsTo + + public.data + public.content + + UTTypeDescription + Delta Controller Skin + UTTypeIdentifier + com.rileytestut.delta.skin + UTTypeTagSpecification + + public.filename-extension + deltaskin + +