diff --git a/Common/Collection View/GameCollectionViewDataSource.swift b/Common/Collection View/GameCollectionViewDataSource.swift deleted file mode 100644 index 2670a03..0000000 --- a/Common/Collection View/GameCollectionViewDataSource.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// GameCollectionViewDataSource.swift -// Delta -// -// Created by Riley Testut on 10/30/15. -// Copyright © 2015 Riley Testut. All rights reserved. -// - -import UIKit -import CoreData - -class GameCollectionViewDataSource: NSObject -{ - var supportedGameCollectionIdentifiers: [String]? { - didSet - { - self.updateFetchedResultsController() - } - } - - var cellConfigurationHandler: ((GridCollectionViewCell, Game) -> Void)? - - private(set) var fetchedResultsController: NSFetchedResultsController = NSFetchedResultsController() - - private var prototypeCell = GridCollectionViewCell() - - private var _registeredCollectionViewCells = false - - // MARK: - Update - - - func update() - { - do - { - try self.fetchedResultsController.performFetch() - } - catch let error as NSError - { - print(error) - } - } - - private func updateFetchedResultsController() - { - let previousDelegate = self.fetchedResultsController.delegate - - let fetchRequest = Game.rst_fetchRequest() - - var predicates: [NSPredicate] = [] - - if let identifiers = self.supportedGameCollectionIdentifiers - { - for identifier in identifiers - { - let predicate = NSPredicate(format: "SUBQUERY(%K, $x, $x.%K == %@).@count > 0", Game.Attributes.gameCollections.rawValue, GameCollection.Attributes.identifier.rawValue, identifier) - predicates.append(predicate) - } - } - - if predicates.count > 0 - { - fetchRequest.predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates) - } - - fetchRequest.sortDescriptors = [NSSortDescriptor(key: Game.Attributes.type.rawValue, ascending: true), NSSortDescriptor(key: Game.Attributes.name.rawValue, ascending: true)] - - self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: Game.Attributes.type.rawValue, cacheName: nil) - self.fetchedResultsController.delegate = previousDelegate - - self.update() - } - - // MARK: - Collection View - - - private func configureCell(_ cell: GridCollectionViewCell, forIndexPath indexPath: IndexPath) - { - let game = self.fetchedResultsController.object(at: indexPath) as! Game - - if let handler = self.cellConfigurationHandler - { - handler(cell, game) - } - } -} - -extension GameCollectionViewDataSource: UICollectionViewDataSource -{ - func numberOfSections(in collectionView: UICollectionView) -> Int - { - return self.fetchedResultsController.sections?.count ?? 0 - } - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int - { - let count = self.fetchedResultsController.sections?[section].numberOfObjects ?? 0 - return count - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell - { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "GameCell", for: indexPath) as! GridCollectionViewCell - - self.configureCell(cell, forIndexPath: indexPath) - - return cell - } -} - -extension GameCollectionViewDataSource: UICollectionViewDelegate -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize - { - let collectionViewLayout = collectionView.collectionViewLayout as! GridCollectionViewLayout - - let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionViewLayout.itemWidth) - widthConstraint.isActive = true - - self.configureCell(self.prototypeCell, forIndexPath: indexPath) - - let size = self.prototypeCell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize) - - widthConstraint.isActive = false - - return size - } -} diff --git a/Common/Extensions/NSFetchedResultsController+Conveniences.h b/Common/Extensions/NSFetchedResultsController+Conveniences.h index 6e5f33e..7c33439 100644 --- a/Common/Extensions/NSFetchedResultsController+Conveniences.h +++ b/Common/Extensions/NSFetchedResultsController+Conveniences.h @@ -10,6 +10,6 @@ @interface NSFetchedResultsController (Conveniences) -- (void)performFetchIfNeeded; +- (BOOL)performFetchIfNeeded; @end diff --git a/Common/Extensions/NSFetchedResultsController+Conveniences.m b/Common/Extensions/NSFetchedResultsController+Conveniences.m index d9982dd..1c022a6 100644 --- a/Common/Extensions/NSFetchedResultsController+Conveniences.m +++ b/Common/Extensions/NSFetchedResultsController+Conveniences.m @@ -12,20 +12,21 @@ @implementation NSFetchedResultsController (Conveniences) -// Needs to be implemented in Objective-C due to current limitation of Swift: -// Extension of a generic Objective-C class cannot access the class's generic parameters at runtime -- (void)performFetchIfNeeded +// Needs to be implemented in Objective-C, because it crashes the Swift compiler :( +- (BOOL)performFetchIfNeeded { - if (self.fetchedObjects != nil) + if (self.sections != nil) { - return; + return NO; } - + NSError *error = nil; if (![self performFetch:&error]) { ELog(error); } + + return YES; } @end diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index 23f7444..e4031ff 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - BF02BD001D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m in Sources */ = {isa = PBXBuildFile; fileRef = BF02BCFF1D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m */; }; BF0418141D01E93400E85BCF /* GBADeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF0418131D01E93400E85BCF /* GBADeltaCore.framework */; }; BF0418151D01E93400E85BCF /* GBADeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF0418131D01E93400E85BCF /* GBADeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */ = {isa = PBXBuildFile; fileRef = BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */; }; @@ -18,7 +17,6 @@ BF172AEB1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF172AEA1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift */; }; BF1FB1861C5EE643007E2494 /* SaveState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1FB1831C5EE643007E2494 /* SaveState.swift */; }; BF27CC8E1BC9FEA200A20D89 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF6BB2451BB73FE800CCF94A /* Assets.xcassets */; }; - BF27CC971BCC890700A20D89 /* GamesCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */; }; BF2B98E61C97E32F00F6D57D /* SaveStatesCollectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF2B98E51C97E32F00F6D57D /* SaveStatesCollectionHeaderView.swift */; }; BF31878B1D489AAA00BD020D /* CheatValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF31878A1D489AAA00BD020D /* CheatValidator.swift */; }; BF34FA071CF0F510006624C7 /* EditCheatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF34FA061CF0F510006624C7 /* EditCheatViewController.swift */; }; @@ -50,13 +48,14 @@ BFA2315C1CED10BE0011E35A /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA2315B1CED10BE0011E35A /* Action.swift */; }; BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FEC1B8AA4FA00495943 /* Settings.swift */; }; BFAA1FF41B8AD7F900495943 /* ControllersSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FF31B8AD7F900495943 /* ControllersSettingsViewController.swift */; }; - BFB141181BE46934004FBF46 /* GameCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFB141171BE46934004FBF46 /* GameCollectionViewDataSource.swift */; }; BFBAA86A1D5A483900A29C1B /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBAA8691D5A483900A29C1B /* DatabaseManager.swift */; }; BFC2731A1BE6152200D22B05 /* GameCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC273171BE6152200D22B05 /* GameCollection.swift */; }; 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 */; }; + BFDD04EF1D5E27DB002D450E /* NSFetchedResultsController+Conveniences.m in Sources */ = {isa = PBXBuildFile; fileRef = BF02BCFF1D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m */; }; + BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */; }; BFDE393C1BC0CEDF003F72E8 /* Game.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDE39391BC0CEDF003F72E8 /* Game.swift */; }; BFE704F51CEA426E0058BAC8 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* Pods.framework */; }; BFEC732D1AAECC4A00650035 /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; }; @@ -108,7 +107,6 @@ BF27CC861BC9E3C600A20D89 /* Delta.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Delta.entitlements; sourceTree = ""; }; BF27CC8A1BC9FE4D00A20D89 /* Pods.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pods.framework; path = "Pods/../build/Debug-appletvos/Pods.framework"; sourceTree = ""; }; 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 = ""; }; BF2B98E51C97E32F00F6D57D /* SaveStatesCollectionHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SaveStatesCollectionHeaderView.swift; path = "Pause Menu/Save States/SaveStatesCollectionHeaderView.swift"; sourceTree = ""; }; BF31878A1D489AAA00BD020D /* CheatValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatValidator.swift; path = "Pause Menu/Cheats/CheatValidator.swift"; sourceTree = ""; }; BF34FA061CF0F510006624C7 /* EditCheatViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EditCheatViewController.swift; path = "Pause Menu/Cheats/EditCheatViewController.swift"; sourceTree = ""; }; @@ -138,13 +136,13 @@ BFA2315B1CED10BE0011E35A /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Action.swift; path = Components/Action.swift; sourceTree = ""; }; BFAA1FEC1B8AA4FA00495943 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; BFAA1FF31B8AD7F900495943 /* ControllersSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControllersSettingsViewController.swift; sourceTree = ""; }; - BFB141171BE46934004FBF46 /* GameCollectionViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameCollectionViewDataSource.swift; path = "Collection View/GameCollectionViewDataSource.swift"; sourceTree = ""; }; BFBAA8691D5A483900A29C1B /* DatabaseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseManager.swift; sourceTree = ""; }; BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SNESDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BFC273171BE6152200D22B05 /* GameCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollection.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 = ""; }; + BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = ""; }; BFDE39391BC0CEDF003F72E8 /* Game.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Game.swift; sourceTree = ""; }; BFEC732C1AAECC4A00650035 /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BFFA71D71AAC406100EE9DD1 /* Delta.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Delta.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -253,7 +251,7 @@ isa = PBXGroup; children = ( BF107EC31BF413F000E0C32C /* GamesViewController.swift */, - BF27CC961BCC890700A20D89 /* GamesCollectionViewController.swift */, + BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */, BFFC461A1D59820F00AF2CC6 /* Segues */, ); path = "Game Selection"; @@ -299,7 +297,6 @@ children = ( BF7AE81A1C2E984300B1B5BC /* GridCollectionViewCell.swift */, BF7AE81D1C2E984300B1B5BC /* GridCollectionViewLayout.swift */, - BFB141171BE46934004FBF46 /* GameCollectionViewDataSource.swift */, ); name = "Collection View"; sourceTree = ""; @@ -581,13 +578,12 @@ BFA0D1271D3AE1F600565894 /* GameViewController.swift in Sources */, BF13A7581D5D2FD9000BB055 /* EmulatorCore+Cheats.swift in Sources */, BF31878B1D489AAA00BD020D /* CheatValidator.swift in Sources */, - BFB141181BE46934004FBF46 /* GameCollectionViewDataSource.swift in Sources */, BFFC46201D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift in Sources */, BFA2315C1CED10BE0011E35A /* Action.swift in Sources */, BFAA1FF41B8AD7F900495943 /* ControllersSettingsViewController.swift in Sources */, BF353FF91C5D870B00C1184C /* PauseItem.swift in Sources */, - BF27CC971BCC890700A20D89 /* GamesCollectionViewController.swift in Sources */, BFBAA86A1D5A483900A29C1B /* DatabaseManager.swift in Sources */, + BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */, BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */, BF7AE81E1C2E984300B1B5BC /* GridCollectionViewCell.swift in Sources */, BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */, @@ -601,7 +597,6 @@ BF762EAB1BC1B076002C8866 /* NSManagedObject+Conveniences.swift in Sources */, BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */, BF353FFF1C5DA3C500C1184C /* PausePresentationController.swift in Sources */, - BF02BD001D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m in Sources */, BFFC464C1D5998D600AF2CC6 /* CheatTableViewCell.swift in Sources */, BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */, BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */, @@ -613,6 +608,7 @@ BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */, BF172AEB1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift in Sources */, BF13A7561D5D29B0000BB055 /* PreviewGameViewController.swift in Sources */, + BFDD04EF1D5E27DB002D450E /* NSFetchedResultsController+Conveniences.m in Sources */, BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */, BFFC461E1D59823500AF2CC6 /* GamesPresentationController.swift in Sources */, BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */, diff --git a/Delta/Base.lproj/Main.storyboard b/Delta/Base.lproj/Main.storyboard index c56c871..bcf2a7e 100644 --- a/Delta/Base.lproj/Main.storyboard +++ b/Delta/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -20,7 +20,7 @@ - + @@ -49,10 +49,10 @@ - + - + @@ -64,16 +64,13 @@ - - + + - - - @@ -81,6 +78,9 @@ + + + diff --git a/Delta/Game Selection/GameCollectionViewController.swift b/Delta/Game Selection/GameCollectionViewController.swift new file mode 100644 index 0000000..836ba9c --- /dev/null +++ b/Delta/Game Selection/GameCollectionViewController.swift @@ -0,0 +1,152 @@ +// +// GameCollectionViewController.swift +// Delta +// +// Created by Riley Testut on 8/12/16. +// Copyright © 2016 Riley Testut. All rights reserved. +// + +import UIKit + +import Roxas + +class GameCollectionViewController: UICollectionViewController +{ + var gameCollection: GameCollection! { + didSet { + self.title = self.gameCollection.shortName + self.updateDataSource() + } + } + + var theme: GamesViewController.Theme = .light { + didSet { + self.collectionView?.reloadData() + } + } + + private var dataSource: RSTFetchedResultsCollectionViewDataSource! + private let prototypeCell = GridCollectionViewCell() +} + +//MARK: - UIViewController - +/// UIViewController +extension GameCollectionViewController +{ + override func viewDidLoad() + { + super.viewDidLoad() + + self.collectionView?.dataSource = self.dataSource + self.collectionView?.delegate = self + + let layout = self.collectionViewLayout as! GridCollectionViewLayout + layout.itemWidth = 90 + } + + override func viewWillAppear(_ animated: Bool) + { + self.dataSource.fetchedResultsController.performFetchIfNeeded() + + super.viewWillAppear(animated) + } + + override func didReceiveMemoryWarning() + { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } +} + +//MARK: - Segues - +/// Segues +extension GameCollectionViewController +{ + override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) + { + guard let identifier = segue.identifier, identifier == "unwindFromGames" else { return } + + let destinationViewController = segue.destination as! GameViewController + let cell = sender as! UICollectionViewCell + + let indexPath = self.collectionView?.indexPath(for: cell) + let game = self.dataSource.fetchedResultsController.object(at: indexPath!) + + destinationViewController.game = game + } +} + +//MARK: - Configure Cells - +/// Configure Cells +private extension GameCollectionViewController +{ + func updateDataSource() + { + let fetchRequest = Game.rst_fetchRequest() as! NSFetchRequest + fetchRequest.predicate = NSPredicate(format: "ANY %K == %@", #keyPath(Game.gameCollections), self.gameCollection) + fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Game.name), ascending: true)] + + self.dataSource = RSTFetchedResultsCollectionViewDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) + self.dataSource.cellIdentifierHandler = { _ in RSTGenericCellIdentifier } + self.dataSource.cellConfigurationHandler = { [unowned self] (cell, indexPath) in + self.configure(cell as! GridCollectionViewCell, for: indexPath) + } + } +} + +//MARK: - Configure Cells - +/// Configure Cells +private extension GameCollectionViewController +{ + func configure(_ cell: GridCollectionViewCell, for indexPath: IndexPath) + { + let game = self.dataSource.fetchedResultsController.object(at: indexPath) + + cell.maximumImageSize = CGSize(width: 90, height: 90) + cell.textLabel.text = game.name + cell.imageView.image = UIImage(named: "BoxArt") + + switch self.theme + { + case .light: + cell.textLabel.textColor = UIColor.darkText + cell.isTextLabelVibrancyEnabled = false + cell.isImageViewVibrancyEnabled = false + + case .dark: + cell.textLabel.textColor = UIColor.white + cell.isTextLabelVibrancyEnabled = true + cell.isImageViewVibrancyEnabled = true + } + } +} + +//MARK: - UICollectionViewDelegate - +/// UICollectionViewDelegate +extension GameCollectionViewController +{ + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) + { + let cell = collectionView.cellForItem(at: indexPath) + self.performSegue(withIdentifier: "unwindFromGames", sender: cell) + } +} + +//MARK: - UICollectionViewDelegateFlowLayout - +/// UICollectionViewDelegateFlowLayout +extension GameCollectionViewController: UICollectionViewDelegateFlowLayout +{ + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize + { + let collectionViewLayout = collectionView.collectionViewLayout as! GridCollectionViewLayout + + let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionViewLayout.itemWidth) + widthConstraint.isActive = true + defer { widthConstraint.isActive = false } + + self.configure(self.prototypeCell, for: indexPath) + + let size = self.prototypeCell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize) + return size + } +} diff --git a/Delta/Game Selection/GamesCollectionViewController.swift b/Delta/Game Selection/GamesCollectionViewController.swift deleted file mode 100644 index 6cc8552..0000000 --- a/Delta/Game Selection/GamesCollectionViewController.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// GamesCollectionViewController.swift -// Delta -// -// Created by Riley Testut on 10/12/15. -// Copyright © 2015 Riley Testut. All rights reserved. -// - -import UIKit -import CoreData - -import DeltaCore - -class GamesCollectionViewController: UICollectionViewController -{ - var theme: GamesViewController.Theme = .light { - didSet { - self.collectionView?.reloadData() - } - } - - weak var segueHandler: UIViewController? - - var gameCollection: GameCollection! { - didSet - { - self.dataSource.supportedGameCollectionIdentifiers = [self.gameCollection.identifier] - self.title = self.gameCollection.shortName - } - } - - let dataSource = GameCollectionViewDataSource() - - required init?(coder aDecoder: NSCoder) - { - super.init(coder: aDecoder) - - self.dataSource.fetchedResultsController.delegate = self - self.dataSource.cellConfigurationHandler = { [unowned self] (cell, game) in - self.configureCell(cell, game: game) - } - } - - override func viewDidLoad() - { - super.viewDidLoad() - - self.collectionView?.dataSource = self.dataSource - self.collectionView?.delegate = self.dataSource - - if let layout = self.collectionViewLayout as? GridCollectionViewLayout - { - layout.itemWidth = 90 - } - } - - override func viewWillAppear(_ animated: Bool) - { - self.dataSource.update() - - super.viewWillAppear(animated) - } - - override func didReceiveMemoryWarning() - { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. - } - - // MARK: - Navigation - - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) - { - self.segueHandler?.prepare(for: segue, sender: sender) - } - - // MARK: - Collection View - - - private func configureCell(_ cell: GridCollectionViewCell, game: Game) - { - cell.maximumImageSize = CGSize(width: 90, height: 90) - cell.textLabel.text = game.name - cell.imageView.image = UIImage(named: "BoxArt") - - switch self.theme - { - case .light: - cell.textLabel.textColor = UIColor.darkText - cell.isTextLabelVibrancyEnabled = false - cell.isImageViewVibrancyEnabled = false - - case .dark: - cell.textLabel.textColor = UIColor.white - cell.isTextLabelVibrancyEnabled = true - cell.isImageViewVibrancyEnabled = true - } - } -} - -extension GamesCollectionViewController: NSFetchedResultsControllerDelegate -{ - func controllerDidChangeContent(_ controller: NSFetchedResultsController) - { - self.collectionView?.reloadData() - } -} diff --git a/Delta/Game Selection/GamesViewController.swift b/Delta/Game Selection/GamesViewController.swift index 0f22a4d..eb9d7c3 100644 --- a/Delta/Game Selection/GamesViewController.swift +++ b/Delta/Game Selection/GamesViewController.swift @@ -43,37 +43,37 @@ class GamesViewController: UIViewController required init?(coder aDecoder: NSCoder) { let fetchRequest = GameCollection.rst_fetchRequest() - fetchRequest.sortDescriptors = [NSSortDescriptor(key: GameCollection.Attributes.index.rawValue, ascending: true)] + fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(GameCollection.index), ascending: true)] self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil) super.init(coder: aDecoder) self.fetchedResultsController.delegate = self + + self.automaticallyAdjustsScrollViewInsets = false } - +} + +//MARK: - UIViewController - +/// UIViewController +extension GamesViewController +{ 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, at: 0) - self.pageViewController = self.childViewControllers.first as? UIPageViewController - self.pageViewController.dataSource = self - self.pageViewController.delegate = self - self.pageViewController.view.isHidden = true - self.pageControl = UIPageControl() self.pageControl.translatesAutoresizingMaskIntoConstraints = false self.pageControl.hidesForSinglePage = false self.pageControl.numberOfPages = 3 - self.pageControl.currentPageIndicatorTintColor = UIColor.purple + self.pageControl.currentPageIndicatorTintColor = UIColor.deltaPurpleColor() self.pageControl.pageIndicatorTintColor = UIColor.lightGray self.navigationController?.toolbar.addSubview(self.pageControl) @@ -85,17 +85,8 @@ class GamesViewController: UIViewController { super.viewWillAppear(animated) - if self.fetchedResultsController.fetchedObjects == nil + if self.fetchedResultsController.performFetchIfNeeded() { - do - { - try self.fetchedResultsController.performFetch() - } - catch let error as NSError - { - print(error) - } - self.updateSections() } } @@ -104,7 +95,7 @@ class GamesViewController: UIViewController { super.viewDidLayoutSubviews() - if let viewControllers = self.pageViewController.viewControllers as? [GamesCollectionViewController] + if let viewControllers = self.pageViewController.viewControllers as? [GameCollectionViewController] { for viewController in viewControllers { @@ -113,7 +104,8 @@ class GamesViewController: UIViewController } } - override func didReceiveMemoryWarning() { + override func didReceiveMemoryWarning() + { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @@ -126,14 +118,12 @@ extension GamesViewController // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) { - guard let sourceViewController = segue.source as? GamesCollectionViewController else { return } - guard let destinationViewController = segue.destination as? GameViewController else { return } - guard let cell = sender as? UICollectionViewCell else { return } + guard let identifier = segue.identifier, identifier == "embedPageViewController" else { return } - let indexPath = sourceViewController.collectionView?.indexPath(for: cell) - let game = sourceViewController.dataSource.fetchedResultsController.object(at: indexPath!) as! Game - - destinationViewController.game = game + self.pageViewController = segue.destination as! UIPageViewController + self.pageViewController.dataSource = self + self.pageViewController.delegate = self + self.pageViewController.view.isHidden = true } @IBAction private func unwindFromSettingsViewController(_ segue: UIStoryboardSegue) @@ -160,9 +150,12 @@ private extension GamesViewController self.navigationController?.toolbar.barStyle = .blackTranslucent } - if let collectionViewController = self.pageViewController.viewControllers?.first as? UICollectionViewController + if let viewControllers = self.pageViewController.viewControllers as? [GameCollectionViewController] { - collectionViewController.collectionView?.reloadData() + for collectionViewController in viewControllers + { + collectionViewController.theme = self.theme + } } } } @@ -170,7 +163,7 @@ private extension GamesViewController // MARK: - Helper Methods - private extension GamesViewController { - func viewControllerForIndex(_ index: Int) -> GamesCollectionViewController? + func viewControllerForIndex(_ index: Int) -> GameCollectionViewController? { guard let pages = self.fetchedResultsController.sections?.first?.numberOfObjects, pages > 0 else { return nil } @@ -185,10 +178,8 @@ private extension GamesViewController let indexPath = IndexPath(row: safeIndex, section: 0) - let viewController = self.storyboard?.instantiateViewController(withIdentifier: "gamesCollectionViewController") as! GamesCollectionViewController + let viewController = self.storyboard?.instantiateViewController(withIdentifier: "gameCollectionViewController") as! GameCollectionViewController viewController.gameCollection = self.fetchedResultsController.object(at: indexPath) as! GameCollection - viewController.collectionView?.contentInset.top = self.topLayoutGuide.length - viewController.segueHandler = self viewController.theme = self.theme return viewController @@ -201,7 +192,7 @@ private extension GamesViewController var resetPageViewController = false - if let viewController = pageViewController.viewControllers?.first as? GamesCollectionViewController, let gameCollection = viewController.gameCollection + if let viewController = pageViewController.viewControllers?.first as? GameCollectionViewController, let gameCollection = viewController.gameCollection { if let index = self.fetchedResultsController.fetchedObjects?.index(where: { $0 as! GameCollection == gameCollection }) { @@ -252,7 +243,7 @@ private extension GamesViewController } //MARK: - Importing - -// Importing +/// Importing extension GamesViewController: GamePickerControllerDelegate { @IBAction private func importFiles() @@ -270,7 +261,7 @@ extension GamesViewController: GamePickerControllerDelegate } //MARK: - UIPageViewController - -// UIPageViewController +/// UIPageViewController extension GamesViewController: UIPageViewControllerDataSource, UIPageViewControllerDelegate { //MARK: - UIPageViewControllerDataSource @@ -287,9 +278,19 @@ extension GamesViewController: UIPageViewControllerDataSource, UIPageViewControl } //MARK: - UIPageViewControllerDelegate + func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) + { + guard let viewControllers = pendingViewControllers as? [GameCollectionViewController] else { return } + + for viewController in viewControllers + { + viewController.collectionView?.contentInset.top = self.topLayoutGuide.length + } + } + func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { - if let viewController = pageViewController.viewControllers?.first as? GamesCollectionViewController, let gameCollection = viewController.gameCollection + if let viewController = pageViewController.viewControllers?.first as? GameCollectionViewController, let gameCollection = viewController.gameCollection { let index = self.fetchedResultsController.fetchedObjects?.index(where: { $0 as! GameCollection == gameCollection }) ?? 0 self.pageControl.currentPage = index @@ -300,7 +301,7 @@ extension GamesViewController: UIPageViewControllerDataSource, UIPageViewControl } //MARK: - NSFetchedResultsControllerDelegate - -// NSFetchedResultsControllerDelegate +/// NSFetchedResultsControllerDelegate extension GamesViewController: NSFetchedResultsControllerDelegate { func controllerDidChangeContent(_ controller: NSFetchedResultsController) diff --git a/External/Roxas b/External/Roxas index f9aa36c..f0661f7 160000 --- a/External/Roxas +++ b/External/Roxas @@ -1 +1 @@ -Subproject commit f9aa36cc59b228bf8182044da017f39b79b7475a +Subproject commit f0661f78b095212ed2f564a4bbf1c1f6c9c50384