Updated UI for pagination between GameCollections

This commit is contained in:
Riley Testut 2015-11-24 11:53:36 -08:00
parent 4a2b5cd1dd
commit 925fb9454d
14 changed files with 323 additions and 75 deletions

View File

@ -11,15 +11,13 @@ import CoreData
class GameCollectionViewDataSource: NSObject class GameCollectionViewDataSource: NSObject
{ {
var gameTypeIdentifiers: [String] = [] { var supportedGameCollectionIdentifiers: [String]? {
didSet didSet
{ {
self.updateFetchedResultsController() self.updateFetchedResultsController()
} }
} }
var sectionTitles: [String] = []
var cellConfigurationHandler: ((GameCollectionViewCell, Game) -> Void)? var cellConfigurationHandler: ((GameCollectionViewCell, Game) -> Void)?
private(set) var fetchedResultsController: NSFetchedResultsController = NSFetchedResultsController() private(set) var fetchedResultsController: NSFetchedResultsController = NSFetchedResultsController()
@ -47,10 +45,13 @@ class GameCollectionViewDataSource: NSObject
var predicates: [NSPredicate] = [] var predicates: [NSPredicate] = []
for typeIdentifier in self.gameTypeIdentifiers if let identifiers = self.supportedGameCollectionIdentifiers
{ {
let predicate = NSPredicate(format: "%K == %@", GameAttributes.typeIdentifier.rawValue, typeIdentifier) for identifier in identifiers
predicates.append(predicate) {
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 if predicates.count > 0
@ -58,7 +59,7 @@ class GameCollectionViewDataSource: NSObject
fetchRequest.predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates) 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 = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.sharedManager.managedObjectContext, sectionNameKeyPath: GameAttributes.typeIdentifier.rawValue, cacheName: nil)
self.fetchedResultsController.delegate = previousDelegate self.fetchedResultsController.delegate = previousDelegate
@ -117,6 +118,4 @@ extension GameCollectionViewDataSource: UICollectionViewDelegate
let size = self.prototypeCell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) let size = self.prototypeCell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
return size return size
} }
} }

View File

@ -88,8 +88,9 @@ class DatabaseManager
self.validationManagedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) self.validationManagedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
self.validationManagedObjectContext.parentContext = self.managedObjectContext self.validationManagedObjectContext.parentContext = self.managedObjectContext
self.validationManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy self.validationManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("managedObjectContextDidSave:"), name: NSManagedObjectContextDidSaveNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("managedObjectContextDidSave:"), name: NSManagedObjectContextDidSaveNotification, object: nil)
} }
func startWithCompletion(completionBlock: ((performingMigration: Bool) -> Void)?) func startWithCompletion(completionBlock: ((performingMigration: Bool) -> Void)?)
@ -158,9 +159,9 @@ class DatabaseManager
game.identifier = identifier game.identifier = identifier
game.filename = filename game.filename = filename
if let pathExtension = URL.pathExtension, if let pathExtension = URL.pathExtension
gameCollection = GameCollection.gameSystemCollectionForPathExtension(pathExtension, inManagedObjectContext: managedObjectContext)
{ {
let gameCollection = GameCollection.gameSystemCollectionForPathExtension(pathExtension, inManagedObjectContext: managedObjectContext)
game.typeIdentifier = gameCollection.identifier game.typeIdentifier = gameCollection.identifier
game.gameCollections.insert(gameCollection) game.gameCollections.insert(gameCollection)
} }
@ -171,7 +172,19 @@ class DatabaseManager
do 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) 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 } 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()
}
} }
} }

View File

@ -12,6 +12,8 @@ import CoreData
import DeltaCore import DeltaCore
import SNESDeltaCore import SNESDeltaCore
public let kUTTypeGBAGame: CFStringRef = "com.rileytestut.delta.game.gba"
@objc(Game) @objc(Game)
class Game: NSManagedObject, GameType class Game: NSManagedObject, GameType
{ {
@ -19,12 +21,22 @@ class Game: NSManagedObject, GameType
let fileURL = DatabaseManager.gamesDirectoryURL.URLByAppendingPathComponent(self.filename) let fileURL = DatabaseManager.gamesDirectoryURL.URLByAppendingPathComponent(self.filename)
return fileURL 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 extension Game
{ {
class func supportedTypeIdentifiers() -> Set<String> class func supportedTypeIdentifiers() -> Set<String>
{ {
return [kUTTypeSNESGame as String] return [kUTTypeSNESGame as String, kUTTypeGBAGame as String]
} }
} }

View File

@ -14,18 +14,16 @@ import CoreData
enum GameCollectionAttributes: String enum GameCollectionAttributes: String
{ {
case name
case identifier case identifier
case shortName case index
case games case games
} }
extension GameCollection { extension GameCollection {
@NSManaged var name: String
@NSManaged var identifier: String @NSManaged var identifier: String
@NSManaged var shortName: String? @NSManaged var index: Int16
@NSManaged var games: Set<Game> @NSManaged var games: Set<Game>
} }

View File

@ -9,31 +9,54 @@
import Foundation import Foundation
import CoreData import CoreData
import DeltaCore
import SNESDeltaCore import SNESDeltaCore
@objc(GameCollection) @objc(GameCollection)
class GameCollection: NSManagedObject 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 identifier: String
let name: String let index: Int16
let shortName: String
switch pathExtension switch pathExtension ?? ""
{ {
case "smc": fallthrough case "smc": fallthrough
case "sfc": fallthrough case "sfc": fallthrough
case "fig": case "fig":
identifier = kUTTypeSNESGame as String identifier = kUTTypeSNESGame as String
name = "Super Nintendo Entertainment System" index = 1990
shortName = "SNES"
case "gba":
identifier = kUTTypeGBAGame as String
index = 2001
default:
default: return nil identifier = kUTTypeDeltaGame as String
index = Int16(INT16_MAX)
} }
let predicate = NSPredicate(format: "%K == %@", GameCollectionAttributes.identifier.rawValue, identifier) let predicate = NSPredicate(format: "%K == %@", GameCollectionAttributes.identifier.rawValue, identifier)
@ -43,10 +66,9 @@ class GameCollection: NSManagedObject
{ {
gameCollection = GameCollection.insertIntoManagedObjectContext(managedObjectContext) gameCollection = GameCollection.insertIntoManagedObjectContext(managedObjectContext)
gameCollection?.identifier = identifier gameCollection?.identifier = identifier
gameCollection?.name = name gameCollection?.index = index
gameCollection?.shortName = shortName
} }
return gameCollection return gameCollection!
} }
} }

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?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"> <entity name="Game" representedClassName="Game" syncable="YES">
<attribute name="artworkURL" optional="YES" attributeType="Transformable" syncable="YES"> <attribute name="artworkURL" optional="YES" attributeType="Transformable" syncable="YES">
<userInfo> <userInfo>
@ -23,8 +23,7 @@
</entity> </entity>
<entity name="GameCollection" representedClassName="GameCollection" syncable="YES"> <entity name="GameCollection" representedClassName="GameCollection" syncable="YES">
<attribute name="identifier" attributeType="String" syncable="YES"/> <attribute name="identifier" attributeType="String" syncable="YES"/>
<attribute name="name" attributeType="String" syncable="YES"/> <attribute name="index" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
<attribute name="shortName" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="games" toMany="YES" deletionRule="Nullify" destinationEntity="Game" inverseName="gameCollections" inverseEntity="Game" syncable="YES"/> <relationship name="games" toMany="YES" deletionRule="Nullify" destinationEntity="Game" inverseName="gameCollections" inverseEntity="Game" syncable="YES"/>
<uniquenessConstraints> <uniquenessConstraints>
<uniquenessConstraint> <uniquenessConstraint>
@ -33,7 +32,7 @@
</uniquenessConstraints> </uniquenessConstraints>
</entity> </entity>
<elements> <elements>
<element name="Game" positionX="-200" positionY="9" width="128" height="133"/> <element name="Game" positionX="-200" positionY="9" width="128" height="135"/>
<element name="GameCollection" positionX="-198" positionY="-207" width="128" height="103"/> <element name="GameCollection" positionX="-198" positionY="-207" width="128" height="90"/>
</elements> </elements>
</model> </model>

View File

@ -9,6 +9,8 @@
import UIKit import UIKit
import ObjectiveC import ObjectiveC
import DeltaCore
protocol GamePickerControllerDelegate protocol GamePickerControllerDelegate
{ {
func gamePickerController(gamePickerController: GamePickerController, didImportGames games: [Game]) func gamePickerController(gamePickerController: GamePickerController, didImportGames games: [Game])
@ -59,7 +61,7 @@ class GamePickerController: NSObject
let managedObjectContext = DatabaseManager.sharedManager.backgroundManagedObjectContext() let managedObjectContext = DatabaseManager.sharedManager.backgroundManagedObjectContext()
managedObjectContext.performBlock() { 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) self.importGamesAtURLs(gameURLs)
} }

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
AF0535CD7331785FA15E0864 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* Pods.framework */; }; AF0535CD7331785FA15E0864 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* Pods.framework */; };
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */ = {isa = PBXBuildFile; fileRef = BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */; }; 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 */; }; BF27CC8B1BC9FE4D00A20D89 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF27CC8A1BC9FE4D00A20D89 /* Pods.framework */; };
BF27CC8C1BC9FE5300A20D89 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* 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, ); }; }; 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 */; }; BF27CC911BCB156200A20D89 /* EmulationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF27CC901BCB156200A20D89 /* EmulationViewController.swift */; };
BF27CC951BCB7B7A00A20D89 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF27CC941BCB7B7A00A20D89 /* GameController.framework */; }; BF27CC951BCB7B7A00A20D89 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF27CC941BCB7B7A00A20D89 /* GameController.framework */; };
BF27CC971BCC890700A20D89 /* GamesCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */; }; 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 */; }; 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, ); }; }; 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 */; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
@ -204,7 +204,6 @@
BF4566E31BC09026007BFA1A /* Common */ = { BF4566E31BC09026007BFA1A /* Common */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BFC273151BE612CE00D22B05 /* Model */,
BFF1E55F1BE04BF6000E9EF6 /* Components */, BFF1E55F1BE04BF6000E9EF6 /* Components */,
BF9257571BD8244800B109DA /* Collection View */, BF9257571BD8244800B109DA /* Collection View */,
BF4566E41BC0902E007BFA1A /* Database */, BF4566E41BC0902E007BFA1A /* Database */,
@ -238,7 +237,7 @@
BF46894D1AAC469800A2586D /* Game Selection */ = { BF46894D1AAC469800A2586D /* Game Selection */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BF27CC981BCC8AE600A20D89 /* GamesViewController.swift */, BF107EC31BF413F000E0C32C /* GamesViewController.swift */,
BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */, BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */,
); );
path = "Game Selection"; path = "Game Selection";
@ -308,13 +307,6 @@
path = Settings; path = Settings;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
BFC273151BE612CE00D22B05 /* Model */ = {
isa = PBXGroup;
children = (
);
name = Model;
sourceTree = "<group>";
};
BFDB28431BC9D9D1001D0C83 /* Importing */ = { BFDB28431BC9D9D1001D0C83 /* Importing */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -632,7 +624,6 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
BF27CC991BCC8AE600A20D89 /* GamesViewController.swift in Sources */,
BFF4EA011BE1B2420056AAA4 /* GameCollectionViewLayoutAttributes.swift in Sources */, BFF4EA011BE1B2420056AAA4 /* GameCollectionViewLayoutAttributes.swift in Sources */,
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */, BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */,
BF50DC421BD851740024C720 /* GameCollectionViewCell.swift in Sources */, BF50DC421BD851740024C720 /* GameCollectionViewCell.swift in Sources */,
@ -650,6 +641,7 @@
BFA5342A1BDC6B520088F1BE /* GameCollectionViewLayout.swift in Sources */, BFA5342A1BDC6B520088F1BE /* GameCollectionViewLayout.swift in Sources */,
BF762E9E1BC19D31002C8866 /* DatabaseManager.swift in Sources */, BF762E9E1BC19D31002C8866 /* DatabaseManager.swift in Sources */,
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */, BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */,
BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */,
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */, BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */,
BFDB28451BC9DA7B001D0C83 /* GamePickerController.swift in Sources */, BFDB28451BC9DA7B001D0C83 /* GamePickerController.swift in Sources */,
BFDE393A1BC0CEDF003F72E8 /* Game+CoreDataProperties.swift in Sources */, BFDE393A1BC0CEDF003F72E8 /* Game+CoreDataProperties.swift in Sources */,

View File

@ -1,4 +1,5 @@
{ {
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "A1BF268530E217C860B34A81A1DA1B446006BF9E",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
}, },
@ -6,6 +7,7 @@
"377491A212AA92C1503AD101C88ADDBD6FD62CF0" : 0, "377491A212AA92C1503AD101C88ADDBD6FD62CF0" : 0,
"C14902E1A817B9BD0549E16C5F6A56E2377FBF42" : 0, "C14902E1A817B9BD0549E16C5F6A56E2377FBF42" : 0,
"816D57F18EE93972A535858CB18F29A85BE91A39" : 0, "816D57F18EE93972A535858CB18F29A85BE91A39" : 0,
"A1BF268530E217C860B34A81A1DA1B446006BF9E" : 0,
"82DF43EF5CA016D15C41E0AF1AF686E9973475B7" : 0 "82DF43EF5CA016D15C41E0AF1AF686E9973475B7" : 0
}, },
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "8EE86D07-2AAF-47C3-91DF-0E46DBDAB128", "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "8EE86D07-2AAF-47C3-91DF-0E46DBDAB128",
@ -13,6 +15,7 @@
"377491A212AA92C1503AD101C88ADDBD6FD62CF0" : "Delta\/External\/Roxas\/", "377491A212AA92C1503AD101C88ADDBD6FD62CF0" : "Delta\/External\/Roxas\/",
"C14902E1A817B9BD0549E16C5F6A56E2377FBF42" : "Delta\/Cores\/SNESDeltaCore\/", "C14902E1A817B9BD0549E16C5F6A56E2377FBF42" : "Delta\/Cores\/SNESDeltaCore\/",
"816D57F18EE93972A535858CB18F29A85BE91A39" : "Delta\/Cores\/DeltaCore\/", "816D57F18EE93972A535858CB18F29A85BE91A39" : "Delta\/Cores\/DeltaCore\/",
"A1BF268530E217C860B34A81A1DA1B446006BF9E" : "Delta\/",
"82DF43EF5CA016D15C41E0AF1AF686E9973475B7" : "Delta\/Cores\/DeltaCore\/External\/ZipZap\/" "82DF43EF5CA016D15C41E0AF1AF686E9973475B7" : "Delta\/Cores\/DeltaCore\/External\/ZipZap\/"
}, },
"DVTSourceControlWorkspaceBlueprintNameKey" : "Delta", "DVTSourceControlWorkspaceBlueprintNameKey" : "Delta",
@ -34,6 +37,11 @@
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "82DF43EF5CA016D15C41E0AF1AF686E9973475B7" "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "82DF43EF5CA016D15C41E0AF1AF686E9973475B7"
}, },
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:rileytestut\/Delta.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "A1BF268530E217C860B34A81A1DA1B446006BF9E"
},
{ {
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:rileytestut\/SNESDeltaCore.git", "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:rileytestut\/SNESDeltaCore.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?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> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
</dependencies> </dependencies>
@ -79,7 +79,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tmn-gd-5UN"> <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/> <animations/>
<connections> <connections>
<segue destination="tpK-ou-yEA" kind="embed" id="cjU-nW-cHY"/> <segue destination="tpK-ou-yEA" kind="embed" id="cjU-nW-cHY"/>
@ -239,12 +239,18 @@
<objects> <objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="wKV-3d-NIY" sceneMemberID="viewController"> <navigationController automaticallyAdjustsScrollViewInsets="NO" id="wKV-3d-NIY" sceneMemberID="viewController">
<toolbarItems/> <toolbarItems/>
<nil key="simulatedBottomBarMetrics"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wj9-1e-eev"> <navigationBar key="navigationBar" contentMode="scaleToFill" id="wj9-1e-eev">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/> <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<animations/> <animations/>
</navigationBar> </navigationBar>
<nil name="viewControllers"/> <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> <connections>
<segue destination="jeE-WD-wXO" kind="relationship" relationship="rootViewController" id="JbW-Xm-9mu"/> <segue destination="jeE-WD-wXO" kind="relationship" relationship="rootViewController" id="JbW-Xm-9mu"/>
</connections> </connections>

View File

@ -13,10 +13,11 @@ import DeltaCore
class GamesCollectionViewController: UICollectionViewController class GamesCollectionViewController: UICollectionViewController
{ {
var gameTypeIdentifier: String! { var gameCollection: GameCollection! {
didSet didSet
{ {
self.dataSource.gameTypeIdentifiers = [self.gameTypeIdentifier] self.dataSource.supportedGameCollectionIdentifiers = [self.gameCollection.identifier]
self.title = self.gameCollection.shortName
} }
} }

View File

@ -7,37 +7,95 @@
// //
import UIKit import UIKit
import CoreData
import SNESDeltaCore import SNESDeltaCore
import Roxas
class GamesViewController: UIViewController 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() override func viewDidLoad()
{ {
super.viewDidLoad() super.viewDidLoad()
self.automaticallyAdjustsScrollViewInsets = false 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 = self.childViewControllers.first as? UIPageViewController
self.pageViewController.dataSource = self self.pageViewController.dataSource = self
self.pageViewController.delegate = self self.pageViewController.delegate = self
self.pageViewController.view.hidden = true
let viewController = self.viewControllerForIndex(0) self.pageControl = UIPageControl()
self.pageViewController.setViewControllers([viewController], direction: .Forward, animated: false, completion: nil) self.pageControl.translatesAutoresizingMaskIntoConstraints = false
self.pageControl.hidesForSinglePage = false
// Do any additional setup after loading the view. 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() override func viewDidLayoutSubviews()
{ {
super.viewDidLayoutSubviews() super.viewDidLayoutSubviews()
let viewController = self.pageViewController.viewControllers?.first as! GamesCollectionViewController if let viewControllers = self.pageViewController.viewControllers as? [GamesCollectionViewController]
viewController.collectionView?.contentInset.top = self.topLayoutGuide.length {
for viewController in viewControllers
{
viewController.collectionView?.contentInset.top = self.topLayoutGuide.length
}
}
} }
override func didReceiveMemoryWarning() { override func didReceiveMemoryWarning() {
@ -57,20 +115,83 @@ class GamesViewController: UIViewController
private extension GamesViewController 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 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 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 viewController.collectionView?.contentInset.top = self.topLayoutGuide.length
return viewController 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 extension GamesViewController: GamePickerControllerDelegate
@ -85,15 +206,32 @@ extension GamesViewController: UIPageViewControllerDelegate, UIPageViewControlle
{ {
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
{ {
let index = self.supportedGameTypeIdentifiers.indexOf((viewController as! GamesCollectionViewController).gameTypeIdentifier) let viewController = self.viewControllerForIndex(self.pageControl.currentPage - 1)
let viewController = self.viewControllerForIndex(index! - 1)
return viewController return viewController
} }
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController?
{ {
let index = self.supportedGameTypeIdentifiers.indexOf((viewController as! GamesCollectionViewController).gameTypeIdentifier) let viewController = self.viewControllerForIndex(self.pageControl.currentPage + 1)
let viewController = self.viewControllerForIndex(index! + 1)
return viewController 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()
}
} }

View File

@ -11,9 +11,12 @@ import CoreData
import SNESDeltaCore import SNESDeltaCore
import Roxas
class GameSelectionViewController: UICollectionViewController class GameSelectionViewController: UICollectionViewController
{ {
private let dataSource = GameCollectionViewDataSource() private let dataSource = GameCollectionViewDataSource()
private var backgroundView: RSTBackgroundView! = nil
required init?(coder aDecoder: NSCoder) required init?(coder aDecoder: NSCoder)
{ {
@ -21,7 +24,7 @@ class GameSelectionViewController: UICollectionViewController
self.title = NSLocalizedString("Games", comment: "") 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.fetchedResultsController.delegate = self
self.dataSource.cellConfigurationHandler = self.configureCell self.dataSource.cellConfigurationHandler = self.configureCell
} }
@ -37,11 +40,18 @@ class GameSelectionViewController: UICollectionViewController
{ {
layout.maximumBoxArtSize = CGSize(width: 200, height: 200) 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) override func viewWillAppear(animated: Bool)
{ {
self.dataSource.update() self.dataSource.update()
self.updateCollections()
super.viewWillAppear(animated) 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> - // MARK: - <GamePickerControllerDelegate> -
extension GameSelectionViewController: GamePickerControllerDelegate extension GameSelectionViewController: GamePickerControllerDelegate
{ {
@ -97,6 +124,8 @@ extension GameSelectionViewController: NSFetchedResultsControllerDelegate
func controllerDidChangeContent(controller: NSFetchedResultsController) func controllerDidChangeContent(controller: NSFetchedResultsController)
{ {
self.collectionView?.reloadData() self.collectionView?.reloadData()
self.updateCollections()
} }
} }

2
External/Roxas vendored

@ -1 +1 @@
Subproject commit 9789612ecbdfd17a8c94b52f4872ec70d44cc4aa Subproject commit 12973b60eeddd6e5b3b398d5ec5b2dadd461810d