Updated UI for pagination between GameCollections
This commit is contained in:
parent
4a2b5cd1dd
commit
925fb9454d
@ -11,15 +11,13 @@ import CoreData
|
||||
|
||||
class GameCollectionViewDataSource: NSObject
|
||||
{
|
||||
var gameTypeIdentifiers: [String] = [] {
|
||||
var supportedGameCollectionIdentifiers: [String]? {
|
||||
didSet
|
||||
{
|
||||
self.updateFetchedResultsController()
|
||||
}
|
||||
}
|
||||
|
||||
var sectionTitles: [String] = []
|
||||
|
||||
var cellConfigurationHandler: ((GameCollectionViewCell, Game) -> Void)?
|
||||
|
||||
private(set) var fetchedResultsController: NSFetchedResultsController = NSFetchedResultsController()
|
||||
@ -47,10 +45,13 @@ class GameCollectionViewDataSource: NSObject
|
||||
|
||||
var predicates: [NSPredicate] = []
|
||||
|
||||
for typeIdentifier in self.gameTypeIdentifiers
|
||||
if let identifiers = self.supportedGameCollectionIdentifiers
|
||||
{
|
||||
let predicate = NSPredicate(format: "%K == %@", GameAttributes.typeIdentifier.rawValue, typeIdentifier)
|
||||
predicates.append(predicate)
|
||||
for identifier in identifiers
|
||||
{
|
||||
let predicate = NSPredicate(format: "SUBQUERY(%K, $x, $x.%K == %@).@count > 0", GameAttributes.gameCollections.rawValue, GameCollectionAttributes.identifier.rawValue, identifier)
|
||||
predicates.append(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
if predicates.count > 0
|
||||
@ -58,7 +59,7 @@ class GameCollectionViewDataSource: NSObject
|
||||
fetchRequest.predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
|
||||
}
|
||||
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: GameAttributes.name.rawValue, ascending: true)]
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: GameAttributes.typeIdentifier.rawValue, ascending: true), NSSortDescriptor(key: GameAttributes.name.rawValue, ascending: true)]
|
||||
|
||||
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.sharedManager.managedObjectContext, sectionNameKeyPath: GameAttributes.typeIdentifier.rawValue, cacheName: nil)
|
||||
self.fetchedResultsController.delegate = previousDelegate
|
||||
@ -117,6 +118,4 @@ extension GameCollectionViewDataSource: UICollectionViewDelegate
|
||||
let size = self.prototypeCell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
|
||||
return size
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -88,8 +88,9 @@ class DatabaseManager
|
||||
self.validationManagedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
|
||||
self.validationManagedObjectContext.parentContext = self.managedObjectContext
|
||||
self.validationManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
||||
|
||||
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("managedObjectContextDidSave:"), name: NSManagedObjectContextDidSaveNotification, object: nil)
|
||||
|
||||
}
|
||||
|
||||
func startWithCompletion(completionBlock: ((performingMigration: Bool) -> Void)?)
|
||||
@ -158,9 +159,9 @@ class DatabaseManager
|
||||
game.identifier = identifier
|
||||
game.filename = filename
|
||||
|
||||
if let pathExtension = URL.pathExtension,
|
||||
gameCollection = GameCollection.gameSystemCollectionForPathExtension(pathExtension, inManagedObjectContext: managedObjectContext)
|
||||
if let pathExtension = URL.pathExtension
|
||||
{
|
||||
let gameCollection = GameCollection.gameSystemCollectionForPathExtension(pathExtension, inManagedObjectContext: managedObjectContext)
|
||||
game.typeIdentifier = gameCollection.identifier
|
||||
game.gameCollections.insert(gameCollection)
|
||||
}
|
||||
@ -171,7 +172,19 @@ class DatabaseManager
|
||||
|
||||
do
|
||||
{
|
||||
try NSFileManager.defaultManager().moveItemAtURL(URL, toURL: DatabaseManager.gamesDirectoryURL.URLByAppendingPathComponent(game.identifier + ".smc"))
|
||||
let destinationURL = DatabaseManager.gamesDirectoryURL.URLByAppendingPathComponent(game.identifier + "." + game.preferredFileExtension)
|
||||
|
||||
if let path = destinationURL.path
|
||||
{
|
||||
if NSFileManager.defaultManager().fileExistsAtPath(path)
|
||||
{
|
||||
try NSFileManager.defaultManager().removeItemAtURL(URL)
|
||||
}
|
||||
else
|
||||
{
|
||||
try NSFileManager.defaultManager().moveItemAtURL(URL, toURL: destinationURL)
|
||||
}
|
||||
}
|
||||
|
||||
identifiers.append(game.identifier)
|
||||
}
|
||||
@ -275,7 +288,36 @@ private extension DatabaseManager
|
||||
{
|
||||
guard let managedObjectContext = notification.object as? NSManagedObjectContext where managedObjectContext.parentContext == self.validationManagedObjectContext else { return }
|
||||
|
||||
self.save()
|
||||
self.validationManagedObjectContext.performBlockAndWait {
|
||||
|
||||
// Remove deleted games from disk
|
||||
if let deletedObjects = notification.userInfo?[NSDeletedObjectsKey] as? Set<NSManagedObject>
|
||||
{
|
||||
let games = deletedObjects.filter({ $0 is Game }).map({ self.validationManagedObjectContext.objectWithID($0.objectID) as! Game })
|
||||
|
||||
for game in games
|
||||
{
|
||||
do
|
||||
{
|
||||
try NSFileManager.defaultManager().removeItemAtURL(game.fileURL)
|
||||
}
|
||||
catch let error as NSError
|
||||
{
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty collections
|
||||
let collections = GameCollection.instancesWithPredicate(NSPredicate(format: "%K.@count == 0", GameCollectionAttributes.games.rawValue), inManagedObjectContext: self.validationManagedObjectContext, type: GameCollection.self)
|
||||
|
||||
for collection in collections
|
||||
{
|
||||
self.validationManagedObjectContext.deleteObject(collection)
|
||||
}
|
||||
|
||||
self.save()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ import CoreData
|
||||
import DeltaCore
|
||||
import SNESDeltaCore
|
||||
|
||||
public let kUTTypeGBAGame: CFStringRef = "com.rileytestut.delta.game.gba"
|
||||
|
||||
@objc(Game)
|
||||
class Game: NSManagedObject, GameType
|
||||
{
|
||||
@ -19,12 +21,22 @@ class Game: NSManagedObject, GameType
|
||||
let fileURL = DatabaseManager.gamesDirectoryURL.URLByAppendingPathComponent(self.filename)
|
||||
return fileURL
|
||||
}
|
||||
|
||||
var preferredFileExtension: String {
|
||||
switch self.typeIdentifier
|
||||
{
|
||||
case kUTTypeSNESGame as String as String: return "smc"
|
||||
case kUTTypeGBAGame as String as String: return "gba"
|
||||
case kUTTypeDeltaGame as String as String: fallthrough
|
||||
default: return "delta"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Game
|
||||
{
|
||||
class func supportedTypeIdentifiers() -> Set<String>
|
||||
{
|
||||
return [kUTTypeSNESGame as String]
|
||||
return [kUTTypeSNESGame as String, kUTTypeGBAGame as String]
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,18 +14,16 @@ import CoreData
|
||||
|
||||
enum GameCollectionAttributes: String
|
||||
{
|
||||
case name
|
||||
case identifier
|
||||
case shortName
|
||||
case index
|
||||
|
||||
case games
|
||||
}
|
||||
|
||||
extension GameCollection {
|
||||
|
||||
@NSManaged var name: String
|
||||
@NSManaged var identifier: String
|
||||
@NSManaged var shortName: String?
|
||||
@NSManaged var index: Int16
|
||||
|
||||
@NSManaged var games: Set<Game>
|
||||
}
|
||||
|
||||
@ -9,31 +9,54 @@
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
import DeltaCore
|
||||
import SNESDeltaCore
|
||||
|
||||
@objc(GameCollection)
|
||||
class GameCollection: NSManagedObject
|
||||
{
|
||||
class func gameSystemCollectionForPathExtension(pathExtension: String?, inManagedObjectContext managedObjectContext: NSManagedObjectContext) -> GameCollection?
|
||||
var name: String {
|
||||
|
||||
switch self.identifier
|
||||
{
|
||||
case kUTTypeSNESGame as String as String: return NSLocalizedString("Super Nintendo Entertainment System", comment: "")
|
||||
case kUTTypeGBAGame as String as String: return NSLocalizedString("Game Boy Advance", comment: "")
|
||||
case kUTTypeDeltaGame as String as String: return NSLocalizedString("Unsupported Games", comment: "")
|
||||
default: return NSLocalizedString("Unknown", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
var shortName: String {
|
||||
|
||||
switch self.identifier
|
||||
{
|
||||
case kUTTypeSNESGame as String as String: return NSLocalizedString("SNES", comment: "")
|
||||
case kUTTypeGBAGame as String as String: return NSLocalizedString("GBA", comment: "")
|
||||
case kUTTypeDeltaGame as String as String: return NSLocalizedString("Unsupported", comment: "")
|
||||
default: return NSLocalizedString("Unknown", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
class func gameSystemCollectionForPathExtension(pathExtension: String?, inManagedObjectContext managedObjectContext: NSManagedObjectContext) -> GameCollection
|
||||
{
|
||||
guard let pathExtension = pathExtension else { return nil }
|
||||
|
||||
let identifier: String
|
||||
let name: String
|
||||
let shortName: String
|
||||
let index: Int16
|
||||
|
||||
switch pathExtension
|
||||
switch pathExtension ?? ""
|
||||
{
|
||||
case "smc": fallthrough
|
||||
case "sfc": fallthrough
|
||||
case "fig":
|
||||
identifier = kUTTypeSNESGame as String
|
||||
name = "Super Nintendo Entertainment System"
|
||||
shortName = "SNES"
|
||||
index = 1990
|
||||
|
||||
case "gba":
|
||||
identifier = kUTTypeGBAGame as String
|
||||
index = 2001
|
||||
|
||||
|
||||
default: return nil
|
||||
default:
|
||||
identifier = kUTTypeDeltaGame as String
|
||||
index = Int16(INT16_MAX)
|
||||
}
|
||||
|
||||
let predicate = NSPredicate(format: "%K == %@", GameCollectionAttributes.identifier.rawValue, identifier)
|
||||
@ -43,10 +66,9 @@ class GameCollection: NSManagedObject
|
||||
{
|
||||
gameCollection = GameCollection.insertIntoManagedObjectContext(managedObjectContext)
|
||||
gameCollection?.identifier = identifier
|
||||
gameCollection?.name = name
|
||||
gameCollection?.shortName = shortName
|
||||
gameCollection?.index = index
|
||||
}
|
||||
|
||||
return gameCollection
|
||||
return gameCollection!
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15A284" minimumToolsVersion="Xcode 7.0">
|
||||
<model userDefinedModelVersionIdentifier="1.0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Xcode 7.0">
|
||||
<entity name="Game" representedClassName="Game" syncable="YES">
|
||||
<attribute name="artworkURL" optional="YES" attributeType="Transformable" syncable="YES">
|
||||
<userInfo>
|
||||
@ -23,8 +23,7 @@
|
||||
</entity>
|
||||
<entity name="GameCollection" representedClassName="GameCollection" syncable="YES">
|
||||
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||
<attribute name="shortName" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="index" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
|
||||
<relationship name="games" toMany="YES" deletionRule="Nullify" destinationEntity="Game" inverseName="gameCollections" inverseEntity="Game" syncable="YES"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
@ -33,7 +32,7 @@
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Game" positionX="-200" positionY="9" width="128" height="133"/>
|
||||
<element name="GameCollection" positionX="-198" positionY="-207" width="128" height="103"/>
|
||||
<element name="Game" positionX="-200" positionY="9" width="128" height="135"/>
|
||||
<element name="GameCollection" positionX="-198" positionY="-207" width="128" height="90"/>
|
||||
</elements>
|
||||
</model>
|
||||
@ -9,6 +9,8 @@
|
||||
import UIKit
|
||||
import ObjectiveC
|
||||
|
||||
import DeltaCore
|
||||
|
||||
protocol GamePickerControllerDelegate
|
||||
{
|
||||
func gamePickerController(gamePickerController: GamePickerController, didImportGames games: [Game])
|
||||
@ -59,7 +61,7 @@ class GamePickerController: NSObject
|
||||
|
||||
let managedObjectContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
|
||||
managedObjectContext.performBlock() {
|
||||
let gameURLs = contents.filter({ GameCollection.gameSystemCollectionForPathExtension($0.pathExtension, inManagedObjectContext: managedObjectContext) != nil })
|
||||
let gameURLs = contents.filter({ GameCollection.gameSystemCollectionForPathExtension($0.pathExtension, inManagedObjectContext: managedObjectContext).identifier != kUTTypeDeltaGame as String })
|
||||
self.importGamesAtURLs(gameURLs)
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
AF0535CD7331785FA15E0864 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* Pods.framework */; };
|
||||
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */ = {isa = PBXBuildFile; fileRef = BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */; };
|
||||
BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF107EC31BF413F000E0C32C /* GamesViewController.swift */; };
|
||||
BF27CC8B1BC9FE4D00A20D89 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF27CC8A1BC9FE4D00A20D89 /* Pods.framework */; };
|
||||
BF27CC8C1BC9FE5300A20D89 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* Pods.framework */; };
|
||||
BF27CC8D1BC9FE5300A20D89 /* Pods.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* Pods.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@ -17,7 +18,6 @@
|
||||
BF27CC911BCB156200A20D89 /* EmulationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF27CC901BCB156200A20D89 /* EmulationViewController.swift */; };
|
||||
BF27CC951BCB7B7A00A20D89 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF27CC941BCB7B7A00A20D89 /* GameController.framework */; };
|
||||
BF27CC971BCC890700A20D89 /* GamesCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */; };
|
||||
BF27CC991BCC8AE600A20D89 /* GamesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF27CC981BCC8AE600A20D89 /* GamesViewController.swift */; };
|
||||
BF2A53FB1BB74FC10052BD0C /* SNESDeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */; };
|
||||
BF2A53FC1BB74FC10052BD0C /* SNESDeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BF2A53FD1BB74FC60052BD0C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; };
|
||||
@ -112,12 +112,12 @@
|
||||
BF090CF11B490D8300DCAB45 /* Delta-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Delta-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
BF090CF21B490D8300DCAB45 /* UIDevice+Vibration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+Vibration.h"; sourceTree = "<group>"; };
|
||||
BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+Vibration.m"; sourceTree = "<group>"; };
|
||||
BF107EC31BF413F000E0C32C /* GamesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamesViewController.swift; sourceTree = "<group>"; };
|
||||
BF27CC861BC9E3C600A20D89 /* Delta.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Delta.entitlements; sourceTree = "<group>"; };
|
||||
BF27CC8A1BC9FE4D00A20D89 /* Pods.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pods.framework; path = "Pods/../build/Debug-appletvos/Pods.framework"; sourceTree = "<group>"; };
|
||||
BF27CC901BCB156200A20D89 /* EmulationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmulationViewController.swift; sourceTree = "<group>"; };
|
||||
BF27CC941BCB7B7A00A20D89 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; };
|
||||
BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamesCollectionViewController.swift; sourceTree = "<group>"; };
|
||||
BF27CC981BCC8AE600A20D89 /* GamesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamesViewController.swift; sourceTree = "<group>"; };
|
||||
BF4566E71BC090B6007BFA1A /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; };
|
||||
BF50DC411BD851740024C720 /* GameCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameCollectionViewCell.swift; path = "Collection View/GameCollectionViewCell.swift"; sourceTree = "<group>"; };
|
||||
BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
|
||||
@ -204,7 +204,6 @@
|
||||
BF4566E31BC09026007BFA1A /* Common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BFC273151BE612CE00D22B05 /* Model */,
|
||||
BFF1E55F1BE04BF6000E9EF6 /* Components */,
|
||||
BF9257571BD8244800B109DA /* Collection View */,
|
||||
BF4566E41BC0902E007BFA1A /* Database */,
|
||||
@ -238,7 +237,7 @@
|
||||
BF46894D1AAC469800A2586D /* Game Selection */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF27CC981BCC8AE600A20D89 /* GamesViewController.swift */,
|
||||
BF107EC31BF413F000E0C32C /* GamesViewController.swift */,
|
||||
BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */,
|
||||
);
|
||||
path = "Game Selection";
|
||||
@ -308,13 +307,6 @@
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BFC273151BE612CE00D22B05 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BFDB28431BC9D9D1001D0C83 /* Importing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -632,7 +624,6 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BF27CC991BCC8AE600A20D89 /* GamesViewController.swift in Sources */,
|
||||
BFF4EA011BE1B2420056AAA4 /* GameCollectionViewLayoutAttributes.swift in Sources */,
|
||||
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */,
|
||||
BF50DC421BD851740024C720 /* GameCollectionViewCell.swift in Sources */,
|
||||
@ -650,6 +641,7 @@
|
||||
BFA5342A1BDC6B520088F1BE /* GameCollectionViewLayout.swift in Sources */,
|
||||
BF762E9E1BC19D31002C8866 /* DatabaseManager.swift in Sources */,
|
||||
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */,
|
||||
BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */,
|
||||
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */,
|
||||
BFDB28451BC9DA7B001D0C83 /* GamePickerController.swift in Sources */,
|
||||
BFDE393A1BC0CEDF003F72E8 /* Game+CoreDataProperties.swift in Sources */,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "A1BF268530E217C860B34A81A1DA1B446006BF9E",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
|
||||
|
||||
},
|
||||
@ -6,6 +7,7 @@
|
||||
"377491A212AA92C1503AD101C88ADDBD6FD62CF0" : 0,
|
||||
"C14902E1A817B9BD0549E16C5F6A56E2377FBF42" : 0,
|
||||
"816D57F18EE93972A535858CB18F29A85BE91A39" : 0,
|
||||
"A1BF268530E217C860B34A81A1DA1B446006BF9E" : 0,
|
||||
"82DF43EF5CA016D15C41E0AF1AF686E9973475B7" : 0
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "8EE86D07-2AAF-47C3-91DF-0E46DBDAB128",
|
||||
@ -13,6 +15,7 @@
|
||||
"377491A212AA92C1503AD101C88ADDBD6FD62CF0" : "Delta\/External\/Roxas\/",
|
||||
"C14902E1A817B9BD0549E16C5F6A56E2377FBF42" : "Delta\/Cores\/SNESDeltaCore\/",
|
||||
"816D57F18EE93972A535858CB18F29A85BE91A39" : "Delta\/Cores\/DeltaCore\/",
|
||||
"A1BF268530E217C860B34A81A1DA1B446006BF9E" : "Delta\/",
|
||||
"82DF43EF5CA016D15C41E0AF1AF686E9973475B7" : "Delta\/Cores\/DeltaCore\/External\/ZipZap\/"
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "Delta",
|
||||
@ -34,6 +37,11 @@
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "82DF43EF5CA016D15C41E0AF1AF686E9973475B7"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:rileytestut\/Delta.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "A1BF268530E217C860B34A81A1DA1B446006BF9E"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:rileytestut\/SNESDeltaCore.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9059" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="wKV-3d-NIY">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="wKV-3d-NIY">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
|
||||
</dependencies>
|
||||
@ -79,7 +79,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tmn-gd-5UN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="556"/>
|
||||
<animations/>
|
||||
<connections>
|
||||
<segue destination="tpK-ou-yEA" kind="embed" id="cjU-nW-cHY"/>
|
||||
@ -239,12 +239,18 @@
|
||||
<objects>
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="wKV-3d-NIY" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wj9-1e-eev">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="M4r-sO-G4H">
|
||||
<rect key="frame" x="0.0" y="556" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</toolbar>
|
||||
<connections>
|
||||
<segue destination="jeE-WD-wXO" kind="relationship" relationship="rootViewController" id="JbW-Xm-9mu"/>
|
||||
</connections>
|
||||
|
||||
@ -13,10 +13,11 @@ import DeltaCore
|
||||
|
||||
class GamesCollectionViewController: UICollectionViewController
|
||||
{
|
||||
var gameTypeIdentifier: String! {
|
||||
var gameCollection: GameCollection! {
|
||||
didSet
|
||||
{
|
||||
self.dataSource.gameTypeIdentifiers = [self.gameTypeIdentifier]
|
||||
self.dataSource.supportedGameCollectionIdentifiers = [self.gameCollection.identifier]
|
||||
self.title = self.gameCollection.shortName
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,37 +7,95 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreData
|
||||
|
||||
import SNESDeltaCore
|
||||
|
||||
import Roxas
|
||||
|
||||
class GamesViewController: UIViewController
|
||||
{
|
||||
var pageViewController: UIPageViewController! = nil
|
||||
private var pageViewController: UIPageViewController!
|
||||
private var backgroundView: RSTBackgroundView!
|
||||
private var pageControl: UIPageControl!
|
||||
|
||||
private let fetchedResultsController: NSFetchedResultsController
|
||||
|
||||
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
|
||||
fatalError("initWithNibName: not implemented")
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder)
|
||||
{
|
||||
let fetchRequest = GameCollection.fetchRequest()
|
||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: GameCollectionAttributes.index.rawValue, ascending: true)]
|
||||
|
||||
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.sharedManager.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
|
||||
self.fetchedResultsController.delegate = self
|
||||
}
|
||||
|
||||
let supportedGameTypeIdentifiers = [kUTTypeSNESGame as String]
|
||||
|
||||
override func viewDidLoad()
|
||||
{
|
||||
super.viewDidLoad()
|
||||
|
||||
self.automaticallyAdjustsScrollViewInsets = false
|
||||
|
||||
self.backgroundView = RSTBackgroundView(frame: self.view.bounds)
|
||||
self.backgroundView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
|
||||
self.backgroundView.textLabel.text = NSLocalizedString("No Games", comment: "")
|
||||
self.backgroundView.detailTextLabel.text = NSLocalizedString("You can import games by pressing the + button in the top right.", comment: "")
|
||||
self.view.insertSubview(self.backgroundView, atIndex: 0)
|
||||
|
||||
self.pageViewController = self.childViewControllers.first as? UIPageViewController
|
||||
self.pageViewController.dataSource = self
|
||||
self.pageViewController.delegate = self
|
||||
self.pageViewController.view.hidden = true
|
||||
|
||||
let viewController = self.viewControllerForIndex(0)
|
||||
self.pageViewController.setViewControllers([viewController], direction: .Forward, animated: false, completion: nil)
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
self.pageControl = UIPageControl()
|
||||
self.pageControl.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.pageControl.hidesForSinglePage = false
|
||||
self.pageControl.numberOfPages = 3
|
||||
self.pageControl.currentPageIndicatorTintColor = UIColor.purpleColor()
|
||||
self.pageControl.pageIndicatorTintColor = UIColor.lightGrayColor()
|
||||
self.navigationController?.toolbar.addSubview(self.pageControl)
|
||||
|
||||
self.pageControl.centerXAnchor.constraintEqualToAnchor(self.navigationController?.toolbar.centerXAnchor, constant: 0).active = true
|
||||
self.pageControl.centerYAnchor.constraintEqualToAnchor(self.navigationController?.toolbar.centerYAnchor, constant: 0).active = true
|
||||
}
|
||||
|
||||
override func viewWillAppear(animated: Bool)
|
||||
{
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
if self.fetchedResultsController.fetchedObjects == nil
|
||||
{
|
||||
do
|
||||
{
|
||||
try self.fetchedResultsController.performFetch()
|
||||
}
|
||||
catch let error as NSError
|
||||
{
|
||||
print(error)
|
||||
}
|
||||
|
||||
self.updateSections()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews()
|
||||
{
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
let viewController = self.pageViewController.viewControllers?.first as! GamesCollectionViewController
|
||||
viewController.collectionView?.contentInset.top = self.topLayoutGuide.length
|
||||
if let viewControllers = self.pageViewController.viewControllers as? [GamesCollectionViewController]
|
||||
{
|
||||
for viewController in viewControllers
|
||||
{
|
||||
viewController.collectionView?.contentInset.top = self.topLayoutGuide.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
@ -57,20 +115,83 @@ class GamesViewController: UIViewController
|
||||
|
||||
private extension GamesViewController
|
||||
{
|
||||
func viewControllerForIndex(index: Int) -> GamesCollectionViewController
|
||||
func viewControllerForIndex(index: Int) -> GamesCollectionViewController?
|
||||
{
|
||||
var safeIndex = index % self.supportedGameTypeIdentifiers.count
|
||||
guard let pages = self.fetchedResultsController.sections?.first?.numberOfObjects where pages > 0 else { return nil }
|
||||
|
||||
// Return nil if only one section, and not asking for the 0th view controller
|
||||
guard !(pages == 1 && index != 0) else { return nil }
|
||||
|
||||
var safeIndex = index % pages
|
||||
if safeIndex < 0
|
||||
{
|
||||
safeIndex = self.supportedGameTypeIdentifiers.count + safeIndex
|
||||
safeIndex = pages + safeIndex
|
||||
}
|
||||
|
||||
|
||||
let indexPath = NSIndexPath(forRow: safeIndex, inSection: 0)
|
||||
|
||||
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("gamesCollectionViewController") as! GamesCollectionViewController
|
||||
viewController.gameTypeIdentifier = self.supportedGameTypeIdentifiers[safeIndex] as String
|
||||
viewController.gameCollection = self.fetchedResultsController.objectAtIndexPath(indexPath) as! GameCollection
|
||||
viewController.collectionView?.contentInset.top = self.topLayoutGuide.length
|
||||
|
||||
return viewController
|
||||
}
|
||||
|
||||
func updateSections()
|
||||
{
|
||||
let sections = self.fetchedResultsController.sections?.first?.numberOfObjects ?? 0
|
||||
self.pageControl.numberOfPages = sections
|
||||
|
||||
var resetPageViewController = false
|
||||
|
||||
if let viewController = pageViewController.viewControllers?.first as? GamesCollectionViewController, let gameCollection = viewController.gameCollection
|
||||
{
|
||||
if let index = self.fetchedResultsController.fetchedObjects?.indexOf({ $0 as! GameCollection == gameCollection })
|
||||
{
|
||||
self.pageControl.currentPage = index
|
||||
}
|
||||
else
|
||||
{
|
||||
resetPageViewController = true
|
||||
|
||||
self.pageControl.currentPage = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
self.navigationController?.setToolbarHidden(sections < 2, animated: self.view.window != nil)
|
||||
|
||||
if sections > 0
|
||||
{
|
||||
// Reset page view controller if currently hidden or current child should view controller no longer exists
|
||||
if self.pageViewController.view.hidden || resetPageViewController
|
||||
{
|
||||
if let viewController = self.viewControllerForIndex(0)
|
||||
{
|
||||
self.pageViewController.view.hidden = false
|
||||
self.backgroundView.hidden = true
|
||||
|
||||
self.pageViewController.setViewControllers([viewController], direction: .Forward, animated: false, completion: nil)
|
||||
|
||||
self.title = viewController.title
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.pageViewController.setViewControllers(self.pageViewController.viewControllers, direction: .Forward, animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.title = NSLocalizedString("Games", comment: "")
|
||||
|
||||
if !self.pageViewController.view.hidden
|
||||
{
|
||||
self.pageViewController.view.hidden = true
|
||||
self.backgroundView.hidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension GamesViewController: GamePickerControllerDelegate
|
||||
@ -85,15 +206,32 @@ extension GamesViewController: UIPageViewControllerDelegate, UIPageViewControlle
|
||||
{
|
||||
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
|
||||
{
|
||||
let index = self.supportedGameTypeIdentifiers.indexOf((viewController as! GamesCollectionViewController).gameTypeIdentifier)
|
||||
let viewController = self.viewControllerForIndex(index! - 1)
|
||||
let viewController = self.viewControllerForIndex(self.pageControl.currentPage - 1)
|
||||
return viewController
|
||||
}
|
||||
|
||||
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController?
|
||||
{
|
||||
let index = self.supportedGameTypeIdentifiers.indexOf((viewController as! GamesCollectionViewController).gameTypeIdentifier)
|
||||
let viewController = self.viewControllerForIndex(index! + 1)
|
||||
let viewController = self.viewControllerForIndex(self.pageControl.currentPage + 1)
|
||||
return viewController
|
||||
}
|
||||
|
||||
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
|
||||
{
|
||||
if let viewController = pageViewController.viewControllers?.first as? GamesCollectionViewController, let gameCollection = viewController.gameCollection
|
||||
{
|
||||
let index = self.fetchedResultsController.fetchedObjects?.indexOf({ $0 as! GameCollection == gameCollection }) ?? 0
|
||||
self.pageControl.currentPage = index
|
||||
}
|
||||
|
||||
self.title = pageViewController.viewControllers?.first?.title
|
||||
}
|
||||
}
|
||||
|
||||
extension GamesViewController: NSFetchedResultsControllerDelegate
|
||||
{
|
||||
func controllerDidChangeContent(controller: NSFetchedResultsController)
|
||||
{
|
||||
self.updateSections()
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,9 +11,12 @@ import CoreData
|
||||
|
||||
import SNESDeltaCore
|
||||
|
||||
import Roxas
|
||||
|
||||
class GameSelectionViewController: UICollectionViewController
|
||||
{
|
||||
private let dataSource = GameCollectionViewDataSource()
|
||||
private var backgroundView: RSTBackgroundView! = nil
|
||||
|
||||
required init?(coder aDecoder: NSCoder)
|
||||
{
|
||||
@ -21,7 +24,7 @@ class GameSelectionViewController: UICollectionViewController
|
||||
|
||||
self.title = NSLocalizedString("Games", comment: "")
|
||||
|
||||
self.dataSource.gameTypeIdentifiers = [kUTTypeSNESGame as String]
|
||||
self.dataSource.supportedGameCollectionIdentifiers = [kUTTypeSNESGame as String, kUTTypeGBAGame as String]
|
||||
self.dataSource.fetchedResultsController.delegate = self
|
||||
self.dataSource.cellConfigurationHandler = self.configureCell
|
||||
}
|
||||
@ -37,11 +40,18 @@ class GameSelectionViewController: UICollectionViewController
|
||||
{
|
||||
layout.maximumBoxArtSize = CGSize(width: 200, height: 200)
|
||||
}
|
||||
|
||||
self.backgroundView = RSTBackgroundView(frame: self.view.bounds)
|
||||
self.backgroundView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
|
||||
self.backgroundView.textLabel.text = NSLocalizedString("No Games", comment: "")
|
||||
self.backgroundView.detailTextLabel.text = NSLocalizedString("You can import games by pressing the + button in the top right.", comment: "")
|
||||
self.view.addSubview(self.backgroundView)
|
||||
}
|
||||
|
||||
override func viewWillAppear(animated: Bool)
|
||||
{
|
||||
self.dataSource.update()
|
||||
self.updateCollections()
|
||||
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
@ -83,6 +93,23 @@ class GameSelectionViewController: UICollectionViewController
|
||||
}
|
||||
}
|
||||
|
||||
private extension GameSelectionViewController
|
||||
{
|
||||
func updateCollections()
|
||||
{
|
||||
if self.dataSource.fetchedResultsController.sections?.count ?? 0 == 0
|
||||
{
|
||||
self.backgroundView.hidden = false
|
||||
self.collectionView?.hidden = true
|
||||
}
|
||||
else
|
||||
{
|
||||
self.backgroundView.hidden = true
|
||||
self.collectionView?.hidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - <GamePickerControllerDelegate> -
|
||||
extension GameSelectionViewController: GamePickerControllerDelegate
|
||||
{
|
||||
@ -97,6 +124,8 @@ extension GameSelectionViewController: NSFetchedResultsControllerDelegate
|
||||
func controllerDidChangeContent(controller: NSFetchedResultsController)
|
||||
{
|
||||
self.collectionView?.reloadData()
|
||||
|
||||
self.updateCollections()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
External/Roxas
vendored
2
External/Roxas
vendored
@ -1 +1 @@
|
||||
Subproject commit 9789612ecbdfd17a8c94b52f4872ec70d44cc4aa
|
||||
Subproject commit 12973b60eeddd6e5b3b398d5ec5b2dadd461810d
|
||||
Loading…
Reference in New Issue
Block a user