diff --git a/Delta/Database/OpenVGDB/GamesDatabaseBrowserViewController.swift b/Delta/Database/OpenVGDB/GamesDatabaseBrowserViewController.swift index 74aacec..1945403 100644 --- a/Delta/Database/OpenVGDB/GamesDatabaseBrowserViewController.swift +++ b/Delta/Database/OpenVGDB/GamesDatabaseBrowserViewController.swift @@ -39,7 +39,7 @@ class GamesDatabaseBrowserViewController: UITableViewController self.dataSource = RSTArrayTableViewDataSource(items: []) - let placeholderView = RSTBackgroundView() + let placeholderView = RSTPlaceholderView() placeholderView.textLabel.textColor = UIColor.lightText placeholderView.detailTextLabel.textColor = UIColor.lightText @@ -140,7 +140,7 @@ extension GamesDatabaseBrowserViewController func updatePlaceholderView() { - guard let placeholderView = self.dataSource.placeholderView as? RSTBackgroundView else { return } + guard let placeholderView = self.dataSource.placeholderView as? RSTPlaceholderView else { return } if self.dataSource.searchController.searchBar.text == "" { diff --git a/Delta/Emulation/GameViewController.swift b/Delta/Emulation/GameViewController.swift index 6990e9e..e329975 100644 --- a/Delta/Emulation/GameViewController.swift +++ b/Delta/Emulation/GameViewController.swift @@ -86,7 +86,7 @@ class GameViewController: DeltaCore.GameViewController fileprivate var sustainButtonsContentView: UIView! fileprivate var sustainButtonsBlurView: UIVisualEffectView! - fileprivate var sustainButtonsBackgroundView: RSTBackgroundView! + fileprivate var sustainButtonsBackgroundView: RSTPlaceholderView! required init() { @@ -171,7 +171,7 @@ extension GameViewController vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.sustainButtonsBlurView.contentView.addSubview(vibrancyView) - self.sustainButtonsBackgroundView = RSTBackgroundView(frame: CGRect(x: 0, y: 0, width: vibrancyView.contentView.bounds.width, height: vibrancyView.contentView.bounds.height)) + self.sustainButtonsBackgroundView = RSTPlaceholderView(frame: CGRect(x: 0, y: 0, width: vibrancyView.contentView.bounds.width, height: vibrancyView.contentView.bounds.height)) self.sustainButtonsBackgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.sustainButtonsBackgroundView.textLabel.text = NSLocalizedString("Select Buttons to Sustain", comment: "") self.sustainButtonsBackgroundView.textLabel.numberOfLines = 1 diff --git a/Delta/Game Selection/GameCollectionViewController.swift b/Delta/Game Selection/GameCollectionViewController.swift index b48c7c6..ebffe8c 100644 --- a/Delta/Game Selection/GameCollectionViewController.swift +++ b/Delta/Game Selection/GameCollectionViewController.swift @@ -44,7 +44,7 @@ class GameCollectionViewController: UICollectionViewController fileprivate var activeSaveState: SaveStateProtocol? - fileprivate var dataSource: RSTFetchedResultsCollectionViewDataSource! + fileprivate let dataSource = RSTFetchedResultsCollectionViewDataSource(fetchedResultsController: NSFetchedResultsController()) fileprivate let prototypeCell = GridCollectionViewCell() fileprivate var _performing3DTouchTransition = false @@ -61,6 +61,10 @@ extension GameCollectionViewController { super.viewDidLoad() + self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in + self.configure(cell as! GridCollectionViewCell, for: indexPath) + } + self.collectionView?.dataSource = self.dataSource self.collectionView?.delegate = self @@ -74,13 +78,6 @@ extension GameCollectionViewController self.collectionView?.addGestureRecognizer(longPressGestureRecognizer) } - override func viewWillAppear(_ animated: Bool) - { - self.dataSource.fetchedResultsController.performFetchIfNeeded() - - super.viewWillAppear(animated) - } - override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) @@ -148,8 +145,8 @@ extension GameCollectionViewController 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!) + let indexPath = self.collectionView!.indexPath(for: cell)! + let game = self.dataSource.item(at: indexPath) destinationViewController.game = game @@ -201,21 +198,18 @@ private extension GameCollectionViewController //MARK: - Update func updateDataSource() { - let fetchRequest = Game.rst_fetchRequest() as! NSFetchRequest + let fetchRequest: NSFetchRequest = Game.fetchRequest() fetchRequest.predicate = NSPredicate(format: "ANY %K == %@", #keyPath(Game.gameCollections), self.gameCollection) fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Game.name), ascending: true)] fetchRequest.returnsObjectsAsFaults = false - self.dataSource = RSTFetchedResultsCollectionViewDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) - self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in - self.configure(cell as! GridCollectionViewCell, for: indexPath) - } + self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil) } //MARK: - Configure Cells func configure(_ cell: GridCollectionViewCell, for indexPath: IndexPath, ignoreImageOperations: Bool = false) { - let game = self.dataSource.fetchedResultsController.object(at: indexPath) + let game = self.dataSource.item(at: indexPath) switch self.theme { @@ -409,7 +403,7 @@ private extension GameCollectionViewController guard let indexPath = self.collectionView?.indexPathForItem(at: gestureRecognizer.location(in: self.collectionView)) else { return } - let game = self.dataSource.fetchedResultsController.object(at: indexPath) + let game = self.dataSource.item(at: indexPath) let actions = self.actions(for: game) let alertController = UIAlertController(actions: actions) @@ -433,7 +427,7 @@ extension GameCollectionViewController: UIViewControllerPreviewingDelegate previewingContext.sourceRect = layoutAttributes.frame - let game = self.dataSource.fetchedResultsController.object(at: indexPath) + let game = self.dataSource.item(at: indexPath) let gameViewController = PreviewGameViewController() gameViewController.game = game @@ -508,7 +502,7 @@ extension GameCollectionViewController guard self.gameCollection.identifier != GameType.unknown.rawValue else { return } let cell = collectionView.cellForItem(at: indexPath) - let game = self.dataSource.fetchedResultsController.object(at: indexPath) + let game = self.dataSource.item(at: indexPath) if game.fileURL == self.activeEmulatorCore?.game.fileURL { diff --git a/Delta/Game Selection/GamesViewController.swift b/Delta/Game Selection/GamesViewController.swift index 30d3811..ccdecb4 100644 --- a/Delta/Game Selection/GamesViewController.swift +++ b/Delta/Game Selection/GamesViewController.swift @@ -35,7 +35,7 @@ class GamesViewController: UIViewController } fileprivate var pageViewController: UIPageViewController! - fileprivate var backgroundView: RSTBackgroundView! + fileprivate var placeholderView: RSTPlaceholderView! fileprivate var pageControl: UIPageControl! fileprivate let fetchedResultsController: NSFetchedResultsController @@ -67,11 +67,11 @@ extension GamesViewController { super.viewDidLoad() - 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.placeholderView = RSTPlaceholderView(frame: self.view.bounds) + self.placeholderView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.placeholderView.textLabel.text = NSLocalizedString("No Games", comment: "") + self.placeholderView.detailTextLabel.text = NSLocalizedString("You can import games by pressing the + button in the top right.", comment: "") + self.view.insertSubview(self.placeholderView, at: 0) self.pageControl = UIPageControl() self.pageControl.translatesAutoresizingMaskIntoConstraints = false @@ -237,7 +237,7 @@ private extension GamesViewController if let viewController = self.viewControllerForIndex(index) { self.pageViewController.view.setHidden(false, animated: animated) - self.backgroundView.setHidden(true, animated: animated) + self.placeholderView.setHidden(true, animated: animated) self.pageViewController.setViewControllers([viewController], direction: .forward, animated: false, completion: nil) @@ -255,7 +255,7 @@ private extension GamesViewController self.title = NSLocalizedString("Games", comment: "") self.pageViewController.view.setHidden(true, animated: animated) - self.backgroundView.setHidden(false, animated: animated) + self.placeholderView.setHidden(false, animated: animated) } } } diff --git a/Delta/Pause Menu/Cheats/CheatsViewController.swift b/Delta/Pause Menu/Cheats/CheatsViewController.swift index 9c03822..c42fea4 100644 --- a/Delta/Pause Menu/Cheats/CheatsViewController.swift +++ b/Delta/Pause Menu/Cheats/CheatsViewController.swift @@ -23,15 +23,13 @@ class CheatsViewController: UITableViewController { var game: Game! { didSet { - self.updateFetchedResultsController() + self.updateDataSource() } } weak var delegate: CheatsViewControllerDelegate? - fileprivate var backgroundView: RSTBackgroundView! - - fileprivate var fetchedResultsController: NSFetchedResultsController! + fileprivate let dataSource = RSTFetchedResultsTableViewDataSource(fetchedResultsController: NSFetchedResultsController()) } extension CheatsViewController @@ -43,33 +41,27 @@ extension CheatsViewController self.title = NSLocalizedString("Cheats", comment: "") let vibrancyEffect = UIVibrancyEffect(blurEffect: UIBlurEffect(style: .dark)) - let vibrancyView = UIVisualEffectView(effect: vibrancyEffect) - vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.tableView.backgroundView = vibrancyView - self.backgroundView = RSTBackgroundView(frame: CGRect(x: 0, y: 0, width: vibrancyView.bounds.width, height: vibrancyView.bounds.height)) - self.backgroundView.isHidden = false - self.backgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.backgroundView.textLabel.text = NSLocalizedString("No Cheats", comment: "") - self.backgroundView.textLabel.textColor = UIColor.white - self.backgroundView.detailTextLabel.text = NSLocalizedString("You can add a new cheat by pressing the + button in the top right.", comment: "") - self.backgroundView.detailTextLabel.textColor = UIColor.white - vibrancyView.contentView.addSubview(self.backgroundView) + let placeholderView = RSTPlaceholderView(frame: CGRect(x: 0, y: 0, width: vibrancyView.bounds.width, height: vibrancyView.bounds.height)) + placeholderView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + placeholderView.textLabel.text = NSLocalizedString("No Cheats", comment: "") + placeholderView.textLabel.textColor = UIColor.white + placeholderView.detailTextLabel.text = NSLocalizedString("You can add a new cheat by pressing the + button in the top right.", comment: "") + placeholderView.detailTextLabel.textColor = UIColor.white + vibrancyView.contentView.addSubview(placeholderView) + + self.dataSource.placeholderView = vibrancyView + self.dataSource.rowAnimation = .automatic + self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in + self.configure(cell, for: indexPath) + } + self.tableView.dataSource = self.dataSource self.tableView.separatorEffect = vibrancyEffect self.registerForPreviewing(with: self, sourceView: self.tableView) } - - override func viewWillAppear(_ animated: Bool) - { - self.fetchedResultsController.performFetchIfNeeded() - - self.updateBackgroundView() - - super.viewWillAppear(animated) - } override func didReceiveMemoryWarning() { @@ -90,29 +82,14 @@ private extension CheatsViewController //MARK: - Update - private extension CheatsViewController { - func updateFetchedResultsController() + func updateDataSource() { - let fetchRequest = Cheat.rst_fetchRequest() + let fetchRequest: NSFetchRequest = Cheat.fetchRequest() fetchRequest.returnsObjectsAsFaults = false fetchRequest.predicate = NSPredicate(format: "%K == %@", #keyPath(Cheat.game), self.game) fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Cheat.name), ascending: true)] - self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil) - self.fetchedResultsController.delegate = self - } - - func updateBackgroundView() - { - if let fetchedObjects = self.fetchedResultsController.fetchedObjects, fetchedObjects.count > 0 - { - self.tableView.separatorStyle = .singleLine - self.backgroundView.isHidden = true - } - else - { - self.tableView.separatorStyle = .none - self.backgroundView.isHidden = false - } + self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil) } } @@ -142,9 +119,9 @@ private extension CheatsViewController /// Convenience private extension CheatsViewController { - func configure(_ cell: UITableViewCell, forIndexPath indexPath: IndexPath) + func configure(_ cell: UITableViewCell, for indexPath: IndexPath) { - let cheat = self.fetchedResultsController.object(at: indexPath) as! Cheat + let cheat = self.dataSource.item(at: indexPath) cell.textLabel?.text = cheat.name cell.textLabel?.font = UIFont.boldSystemFont(ofSize: cell.textLabel!.font.pointSize) cell.textLabel?.textColor = UIColor.white @@ -162,35 +139,11 @@ private extension CheatsViewController } } -extension CheatsViewController -{ - // MARK: - Table view data source - - override func numberOfSections(in tableView: UITableView) -> Int - { - let numberOfSections = self.fetchedResultsController.sections!.count - return numberOfSections - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int - { - let section = self.fetchedResultsController.sections![section] - return section.numberOfObjects - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell - { - let cell = tableView.dequeueReusableCell(withIdentifier: RSTCellContentGenericCellIdentifier, for: indexPath) - self.configure(cell, forIndexPath: indexPath) - return cell - } -} - extension CheatsViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let cheat = self.fetchedResultsController.object(at: indexPath) as! Cheat + let cheat = self.dataSource.item(at: indexPath) let backgroundContext = DatabaseManager.shared.newBackgroundContext() backgroundContext.performAndWait { @@ -214,7 +167,7 @@ extension CheatsViewController override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { - let cheat = self.fetchedResultsController.object(at: indexPath) as! Cheat + let cheat = self.dataSource.item(at: indexPath) let deleteAction = UITableViewRowAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { (action, indexPath) in self.deleteCheat(cheat) @@ -244,7 +197,7 @@ extension CheatsViewController: UIViewControllerPreviewingDelegate let frame = self.tableView.rectForRow(at: indexPath) previewingContext.sourceRect = frame - let cheat = self.fetchedResultsController.object(at: indexPath) as! Cheat + let cheat = self.dataSource.item(at: indexPath) let editCheatViewController = self.makeEditCheatViewController(cheat: cheat) editCheatViewController.isPreviewing = true @@ -284,13 +237,3 @@ extension CheatsViewController: EditCheatViewControllerDelegate self.delegate?.cheatsViewController(self, deactivateCheat: cheat) } } - -//MARK: - - -extension CheatsViewController: NSFetchedResultsControllerDelegate -{ - func controllerDidChangeContent(_ controller: NSFetchedResultsController) - { - self.tableView.reloadData() - self.updateBackgroundView() - } -} diff --git a/Delta/Pause Menu/PauseItem.swift b/Delta/Pause Menu/PauseItem.swift index ddf49e4..e1c629b 100644 --- a/Delta/Pause Menu/PauseItem.swift +++ b/Delta/Pause Menu/PauseItem.swift @@ -8,7 +8,8 @@ import UIKit -struct PauseItem: Equatable +// Must be class for use with Objective-C generics :( +class PauseItem: Equatable { var image: UIImage var text: String diff --git a/Delta/Pause Menu/PauseMenuViewController.swift b/Delta/Pause Menu/PauseMenuViewController.swift index 01f236e..a887cb4 100644 --- a/Delta/Pause Menu/PauseMenuViewController.swift +++ b/Delta/Pause Menu/PauseMenuViewController.swift @@ -21,7 +21,7 @@ class PauseMenuViewController: UICollectionViewController fatalError("PauseViewController only supports up to 8 items (for my sanity when laying out on a landscape iPhone 4s") } - self.collectionView?.reloadData() + self.dataSource.items = self.items } } @@ -30,6 +30,8 @@ class PauseMenuViewController: UICollectionViewController get { return self.collectionView?.contentSize ?? CGSize.zero } } + fileprivate let dataSource = RSTArrayCollectionViewDataSource(items: []) + fileprivate var prototypeCell = GridCollectionViewCell() fileprivate var previousIndexPath: IndexPath? = nil } @@ -39,6 +41,11 @@ extension PauseMenuViewController override func viewDidLoad() { super.viewDidLoad() + + self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in + self.configure(cell as! GridCollectionViewCell, for: indexPath) + } + self.collectionView?.dataSource = self.dataSource let collectionViewLayout = self.collectionViewLayout as! GridCollectionViewLayout collectionViewLayout.itemWidth = 90 @@ -63,7 +70,7 @@ extension PauseMenuViewController private extension PauseMenuViewController { - func configureCollectionViewCell(_ cell: GridCollectionViewCell, forIndexPath indexPath: IndexPath) + func configure(_ cell: GridCollectionViewCell, for indexPath: IndexPath) { let pauseItem = self.items[(indexPath as NSIndexPath).item] @@ -95,27 +102,11 @@ private extension PauseMenuViewController func toggleSelectedStateForPauseItemAtIndexPath(_ indexPath: IndexPath) { - var pauseItem = self.items[(indexPath as NSIndexPath).item] + let pauseItem = self.items[indexPath.item] pauseItem.selected = !pauseItem.selected - self.items[(indexPath as NSIndexPath).item] = pauseItem let cell = self.collectionView!.cellForItem(at: indexPath) as! GridCollectionViewCell - self.configureCollectionViewCell(cell, forIndexPath: indexPath) - } -} - -extension PauseMenuViewController -{ - override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int - { - return self.items.count - } - - override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell - { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RSTCellContentGenericCellIdentifier, for: indexPath) as! GridCollectionViewCell - self.configureCollectionViewCell(cell, forIndexPath: indexPath) - return cell + self.configure(cell, for: indexPath) } } @@ -123,7 +114,7 @@ extension PauseMenuViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - self.configureCollectionViewCell(self.prototypeCell, forIndexPath: indexPath) + self.configure(self.prototypeCell, for: indexPath) let size = self.prototypeCell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize) return size @@ -148,7 +139,7 @@ extension PauseMenuViewController self.toggleSelectedStateForPauseItemAtIndexPath(indexPath) - let pauseItem = self.items[(indexPath as NSIndexPath).item] + let pauseItem = self.items[indexPath.item] pauseItem.action(pauseItem) } } diff --git a/Delta/Pause Menu/Save States/SaveStatesViewController.swift b/Delta/Pause Menu/Save States/SaveStatesViewController.swift index 60fbe19..3de34db 100644 --- a/Delta/Pause Menu/Save States/SaveStatesViewController.swift +++ b/Delta/Pause Menu/Save States/SaveStatesViewController.swift @@ -38,7 +38,7 @@ class SaveStatesViewController: UICollectionViewController { var game: Game! { didSet { - self.updateFetchedResultsController() + self.updateDataSource() } } @@ -59,13 +59,13 @@ class SaveStatesViewController: UICollectionViewController } fileprivate var vibrancyView: UIVisualEffectView! - fileprivate var backgroundView: RSTBackgroundView! + fileprivate var placeholderView: RSTPlaceholderView! fileprivate var prototypeCell = GridCollectionViewCell() fileprivate var prototypeCellWidthConstraint: NSLayoutConstraint! fileprivate var prototypeHeader = SaveStatesCollectionHeaderView() - fileprivate var fetchedResultsController: NSFetchedResultsController! + fileprivate let dataSource = RSTFetchedResultsCollectionViewDataSource(fetchedResultsController: NSFetchedResultsController()) fileprivate let imageOperationQueue = RSTOperationQueue() fileprivate let imageCache = NSCache() @@ -91,17 +91,20 @@ extension SaveStatesViewController super.viewDidLoad() self.vibrancyView = UIVisualEffectView(effect: nil) - self.vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.vibrancyView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height) - self.view.insertSubview(self.vibrancyView, at: 0) - self.backgroundView = RSTBackgroundView(frame: CGRect(x: 0, y: 0, width: vibrancyView.bounds.width, height: vibrancyView.bounds.height)) - self.backgroundView.isHidden = true - self.backgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.backgroundView.textLabel.text = NSLocalizedString("No Save States", comment: "") - self.backgroundView.textLabel.textColor = UIColor.white - self.backgroundView.detailTextLabel.textColor = UIColor.white - self.vibrancyView.contentView.addSubview(self.backgroundView) + self.placeholderView = RSTPlaceholderView(frame: CGRect(x: 0, y: 0, width: self.vibrancyView.bounds.width, height: self.vibrancyView.bounds.height)) + self.placeholderView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.placeholderView.textLabel.text = NSLocalizedString("No Save States", comment: "") + self.placeholderView.textLabel.textColor = UIColor.white + self.placeholderView.detailTextLabel.textColor = UIColor.white + self.vibrancyView.contentView.addSubview(self.placeholderView) + + self.dataSource.proxy = self + self.dataSource.placeholderView = self.vibrancyView + self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in + self.configure(cell as! GridCollectionViewCell, for: indexPath) + } + self.collectionView?.dataSource = self.dataSource let collectionViewLayout = self.collectionViewLayout as! GridCollectionViewLayout let averageHorizontalInset = (collectionViewLayout.sectionInset.left + collectionViewLayout.sectionInset.right) / 2 @@ -115,11 +118,11 @@ extension SaveStatesViewController { case .saving: self.title = NSLocalizedString("Save State", comment: "") - self.backgroundView.detailTextLabel.text = NSLocalizedString("You can create a new save state by pressing the + button in the top right.", comment: "") + placeholderView.detailTextLabel.text = NSLocalizedString("You can create a new save state by pressing the + button in the top right.", comment: "") case .loading: self.title = NSLocalizedString("Load State", comment: "") - self.backgroundView.detailTextLabel.text = NSLocalizedString("You can create a new save state by pressing the Save State option in the pause menu.", comment: "") + placeholderView.detailTextLabel.text = NSLocalizedString("You can create a new save state by pressing the Save State option in the pause menu.", comment: "") self.navigationItem.rightBarButtonItem = nil } @@ -137,19 +140,9 @@ extension SaveStatesViewController self.navigationController?.navigationBar.barStyle = .blackTranslucent self.navigationController?.toolbar.barStyle = .blackTranslucent - self.updateBackgroundView() self.updateTheme() } - override func viewWillAppear(_ animated: Bool) - { - self.fetchedResultsController.performFetchIfNeeded() - - self.updateBackgroundView() - - super.viewWillAppear(animated) - } - override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) @@ -167,27 +160,14 @@ private extension SaveStatesViewController { //MARK: - Update - - func updateFetchedResultsController() + func updateDataSource() { - let fetchRequest = SaveState.rst_fetchRequest() + let fetchRequest: NSFetchRequest = SaveState.fetchRequest() fetchRequest.returnsObjectsAsFaults = false fetchRequest.predicate = NSPredicate(format: "%K == %@", #keyPath(SaveState.game), self.game) fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(SaveState.type), ascending: true), NSSortDescriptor(key: #keyPath(SaveState.creationDate), ascending: true)] - self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(SaveState.type), cacheName: nil) - self.fetchedResultsController.delegate = self - } - - func updateBackgroundView() - { - if let fetchedObjects = self.fetchedResultsController.fetchedObjects, fetchedObjects.count > 0 - { - self.backgroundView.isHidden = true - } - else - { - self.backgroundView.isHidden = false - } + self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(SaveState.type), cacheName: nil) } func updateTheme() @@ -199,24 +179,24 @@ private extension SaveStatesViewController self.vibrancyView.effect = nil - self.backgroundView.textLabel.textColor = UIColor.gray - self.backgroundView.detailTextLabel.textColor = UIColor.gray + self.placeholderView.textLabel.textColor = UIColor.gray + self.placeholderView.detailTextLabel.textColor = UIColor.gray case .translucent: self.view.backgroundColor = nil self.vibrancyView.effect = UIVibrancyEffect(blurEffect: UIBlurEffect(style: .dark)) - self.backgroundView.textLabel.textColor = UIColor.white - self.backgroundView.detailTextLabel.textColor = UIColor.white + self.placeholderView.textLabel.textColor = UIColor.white + self.placeholderView.detailTextLabel.textColor = UIColor.white } } //MARK: - Configure Views - - func configureCollectionViewCell(_ cell: GridCollectionViewCell, forIndexPath indexPath: IndexPath, ignoreExpensiveOperations ignoreOperations: Bool = false) + func configure(_ cell: GridCollectionViewCell, for indexPath: IndexPath, ignoreExpensiveOperations ignoreOperations: Bool = false) { - let saveState = self.fetchedResultsController.object(at: indexPath) as! SaveState + let saveState = self.dataSource.item(at: indexPath) cell.imageView.backgroundColor = UIColor.white cell.imageView.image = UIImage(named: "DeltaPlaceholder") @@ -241,10 +221,12 @@ private extension SaveStatesViewController if let image = image { - cell.imageView.backgroundColor = nil - cell.imageView.image = image - - cell.isImageViewVibrancyEnabled = false + DispatchQueue.main.async { + cell.imageView.backgroundColor = nil + cell.imageView.image = image + + cell.isImageViewVibrancyEnabled = false + } } } @@ -268,7 +250,7 @@ private extension SaveStatesViewController cell.textLabel.text = name } - func configureCollectionViewHeaderView(_ headerView: SaveStatesCollectionHeaderView, forSection section: Int) + func configure(_ headerView: SaveStatesCollectionHeaderView, forSection section: Int) { let section = self.correctedSectionForSectionIndex(section) @@ -299,7 +281,7 @@ private extension SaveStatesViewController guard let indexPath = self.collectionView?.indexPathForItem(at: gestureRecognizer.location(in: self.collectionView)) else { return } - let saveState = self.fetchedResultsController.object(at: indexPath) as! SaveState + let saveState = self.dataSource.item(at: indexPath) guard let actions = self.actionsForSaveState(saveState) else { return } @@ -447,7 +429,7 @@ private extension SaveStatesViewController func correctedSectionForSectionIndex(_ section: Int) -> Section { - let sectionInfo = self.fetchedResultsController.sections![section] + let sectionInfo = self.dataSource.fetchedResultsController.sections![section] let sectionIndex = Int(sectionInfo.name)! let section = Section(rawValue: sectionIndex)! @@ -593,7 +575,7 @@ extension SaveStatesViewController: UIViewControllerPreviewingDelegate previewingContext.sourceRect = layoutAttributes.frame - let saveState = self.fetchedResultsController.object(at: indexPath) as! SaveState + let saveState = self.dataSource.item(at: indexPath) let actions = self.actionsForSaveState(saveState)?.previewActions ?? [] let previewImage = self.imageCache.object(forKey: saveState.imageFileURL as NSURL) ?? UIImage(contentsOfFile: saveState.imageFileURL.path) @@ -633,29 +615,10 @@ extension SaveStatesViewController: UIViewControllerPreviewingDelegate //MARK: - - extension SaveStatesViewController { - override func numberOfSections(in collectionView: UICollectionView) -> Int - { - let numberOfSections = self.fetchedResultsController.sections!.count - return numberOfSections - } - - override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int - { - let section = self.fetchedResultsController.sections![section] - return section.numberOfObjects - } - - override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell - { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RSTCellContentGenericCellIdentifier, for: indexPath) as! GridCollectionViewCell - self.configureCollectionViewCell(cell, forIndexPath: indexPath) - return cell - } - override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Header", for: indexPath) as! SaveStatesCollectionHeaderView - self.configureCollectionViewHeaderView(headerView, forSection: (indexPath as NSIndexPath).section) + self.configure(headerView, forSection: indexPath.section) return headerView } } @@ -665,7 +628,7 @@ extension SaveStatesViewController { override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - let saveState = self.fetchedResultsController.object(at: indexPath) as! SaveState + let saveState = self.dataSource.item(at: indexPath) switch self.mode { @@ -706,7 +669,7 @@ extension SaveStatesViewController: UICollectionViewDelegateFlowLayout func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // No need to load images from disk just to determine size, so we pass true for ignoreExpensiveOperations - self.configureCollectionViewCell(self.prototypeCell, forIndexPath: indexPath, ignoreExpensiveOperations: true) + self.configure(self.prototypeCell, for: indexPath, ignoreExpensiveOperations: true) let size = self.prototypeCell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize) return size @@ -714,19 +677,9 @@ extension SaveStatesViewController: UICollectionViewDelegateFlowLayout func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - self.configureCollectionViewHeaderView(self.prototypeHeader, forSection: section) + self.configure(self.prototypeHeader, forSection: section) let size = self.prototypeHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize) return size } } - -//MARK: - - -extension SaveStatesViewController: NSFetchedResultsControllerDelegate -{ - func controllerDidChangeContent(_ controller: NSFetchedResultsController) - { - self.collectionView?.reloadData() - self.updateBackgroundView() - } -} diff --git a/Delta/Settings/Controller Skins/ControllerSkinsViewController.swift b/Delta/Settings/Controller Skins/ControllerSkinsViewController.swift index 4d4a9b2..e6c8fa5 100644 --- a/Delta/Settings/Controller Skins/ControllerSkinsViewController.swift +++ b/Delta/Settings/Controller Skins/ControllerSkinsViewController.swift @@ -35,7 +35,7 @@ class ControllerSkinsViewController: UITableViewController } } - fileprivate var dataSource: RSTFetchedResultsTableViewDataSource! + fileprivate let dataSource = RSTFetchedResultsTableViewDataSource(fetchedResultsController: NSFetchedResultsController()) fileprivate let imageOperationQueue = RSTOperationQueue() @@ -47,13 +47,12 @@ extension ControllerSkinsViewController override func viewDidLoad() { super.viewDidLoad() - } - - override func viewWillAppear(_ animated: Bool) - { - self.dataSource.fetchedResultsController.performFetchIfNeeded() - super.viewWillAppear(animated) + self.dataSource.proxy = self + self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in + self.configure(cell as! ControllerSkinTableViewCell, for: indexPath) + } + self.tableView.dataSource = self.dataSource } override func didReceiveMemoryWarning() @@ -76,18 +75,13 @@ private extension ControllerSkinsViewController fetchRequest.predicate = NSPredicate(format: "%K == %@ AND (%K & %d) == %d", #keyPath(ControllerSkin.gameType), gameType.rawValue, #keyPath(ControllerSkin.supportedConfigurations), configuration.rawValue, configuration.rawValue) fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(ControllerSkin.isStandard), ascending: false), NSSortDescriptor(key: #keyPath(ControllerSkin.name), ascending: true)] - let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(ControllerSkin.name), cacheName: nil) - - self.dataSource = RSTFetchedResultsTableViewDataSource(fetchedResultsController: fetchedResultsController) - self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in - self.configure(cell as! ControllerSkinTableViewCell, for: indexPath) - } + self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(ControllerSkin.name), cacheName: nil) } //MARK: - Configure Cells func configure(_ cell: ControllerSkinTableViewCell, for indexPath: IndexPath) { - let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath) + let controllerSkin = self.dataSource.item(at: indexPath) cell.controllerSkinImageView.image = nil cell.activityIndicatorView.startAnimating() @@ -126,24 +120,9 @@ private extension ControllerSkinsViewController extension ControllerSkinsViewController { - override func numberOfSections(in tableView: UITableView) -> Int - { - return self.dataSource.numberOfSections(in: tableView) - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int - { - return self.dataSource.tableView(tableView, numberOfRowsInSection: section) - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell - { - return self.dataSource.tableView(tableView, cellForRowAt: indexPath) - } - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - let controllerSkin = self.dataSource.fetchedResultsController.object(at: IndexPath(row: 0, section: section)) + let controllerSkin = self.dataSource.item(at: IndexPath(row: 0, section: section)) return controllerSkin.name } } @@ -154,7 +133,7 @@ extension ControllerSkinsViewController: UITableViewDataSourcePrefetching { for indexPath in indexPaths { - let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath) + let controllerSkin = self.dataSource.item(at: indexPath) let size = UIScreen.main.defaultControllerSkinSize @@ -179,7 +158,7 @@ extension ControllerSkinsViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath) + let controllerSkin = self.dataSource.item(at: indexPath) Settings.setPreferredControllerSkin(controllerSkin, for: self.gameType, traits: self.traits) _ = self.navigationController?.popViewController(animated: true) @@ -187,7 +166,7 @@ extension ControllerSkinsViewController override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath) + let controllerSkin = self.dataSource.item(at: indexPath) guard let size = controllerSkin.aspectRatio(for: self.traits) else { return 150 } diff --git a/External/Roxas b/External/Roxas index 0057bde..9143d01 160000 --- a/External/Roxas +++ b/External/Roxas @@ -1 +1 @@ -Subproject commit 0057bde6337f90b5747eec1baf94a1360e78c23e +Subproject commit 9143d01afa25f07da8f1cdb5390b49f4efb1a75f