Adds ability to search for games from GamesViewController

This commit is contained in:
Riley Testut 2017-10-16 13:03:00 -07:00
parent 5709320415
commit 52c39dbc4d
5 changed files with 120 additions and 42 deletions

View File

@ -21,11 +21,11 @@ extension UIViewControllerContextTransitioning
/// UIViews
var sourceView: UIView {
return self.sourceViewController.view
return self.view(forKey: .from) ?? self.sourceViewController.view
}
var destinationView: UIView {
return self.destinationViewController.view
return self.view(forKey: .to) ?? self.destinationViewController.view
}

View File

@ -17,9 +17,9 @@ import SDWebImage
class GameCollectionViewController: UICollectionViewController
{
var gameCollection: GameCollection! {
var gameCollection: GameCollection? {
didSet {
self.title = self.gameCollection.shortName
self.title = self.gameCollection?.shortName
self.updateDataSource()
}
}
@ -41,11 +41,12 @@ class GameCollectionViewController: UICollectionViewController
}
}
internal let dataSource: RSTFetchedResultsCollectionViewPrefetchingDataSource<Game, UIImage>
weak var activeEmulatorCore: EmulatorCore?
private var activeSaveState: SaveStateProtocol?
private let dataSource: RSTFetchedResultsCollectionViewPrefetchingDataSource<Game, UIImage>
private let prototypeCell = GridCollectionViewCell()
private var _performing3DTouchTransition = false
@ -215,7 +216,12 @@ private extension GameCollectionViewController
func updateDataSource()
{
let fetchRequest: NSFetchRequest<Game> = Game.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "ANY %K == %@", #keyPath(Game.gameCollections), self.gameCollection)
if let gameCollection = self.gameCollection
{
fetchRequest.predicate = NSPredicate(format: "ANY %K == %@", #keyPath(Game.gameCollections), gameCollection)
}
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Game.name), ascending: true)]
fetchRequest.returnsObjectsAsFaults = false
@ -424,7 +430,7 @@ extension GameCollectionViewController: UIViewControllerPreviewingDelegate
{
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?
{
guard self.gameCollection.identifier != GameType.unknown.rawValue else { return nil }
guard self.gameCollection?.identifier != GameType.unknown.rawValue else { return nil }
guard
let collectionView = self.collectionView,
@ -598,7 +604,7 @@ extension GameCollectionViewController
{
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
guard self.gameCollection.identifier != GameType.unknown.rawValue else { return }
guard self.gameCollection?.identifier != GameType.unknown.rawValue else { return }
let cell = collectionView.cellForItem(at: indexPath)
let game = self.dataSource.item(at: indexPath)

View File

@ -35,12 +35,18 @@ class GamesViewController: UIViewController
}
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
private var pageViewController: UIPageViewController!
private var placeholderView: RSTPlaceholderView!
private var pageControl: UIPageControl!
private let fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>
private var searchController: RSTSearchController?
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
fatalError("initWithNibName: not implemented")
}
@ -88,6 +94,11 @@ extension GamesViewController
self.navigationController?.navigationBar.barStyle = .blackTranslucent
self.navigationController?.toolbar.barStyle = .blackTranslucent
if #available(iOS 11.0, *)
{
self.prepareSearchController()
}
self.updateTheme()
}
@ -153,6 +164,48 @@ extension GamesViewController
/// UI
private extension GamesViewController
{
@available(iOS 11.0, *)
func prepareSearchController()
{
let searchResultsController = self.storyboard?.instantiateViewController(withIdentifier: "gameCollectionViewController") as! GameCollectionViewController
searchResultsController.gameCollection = nil
searchResultsController.theme = self.theme
searchResultsController.activeEmulatorCore = self.activeEmulatorCore
let placeholderView = RSTPlaceholderView()
placeholderView.textLabel.text = NSLocalizedString("No Games Found", comment: "")
placeholderView.detailTextLabel.text = NSLocalizedString("Please make sure the name is correct, or try searching for another game.", comment: "")
switch self.theme
{
case .opaque: searchResultsController.dataSource.placeholderView = placeholderView
case .translucent:
let vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .dark)))
vibrancyView.contentView.addSubview(placeholderView, pinningEdgesWith: .zero)
searchResultsController.dataSource.placeholderView = vibrancyView
}
self.searchController = RSTSearchController(searchResultsController: searchResultsController)
self.searchController?.searchableKeyPaths = [#keyPath(Game.name)]
self.searchController?.searchHandler = { [weak searchController, weak searchResultsController] (searchValue, _) in
if searchController?.searchBar.text?.isEmpty == false
{
self.pageViewController.view.isHidden = true
}
else
{
self.pageViewController.view.isHidden = false
}
searchResultsController?.dataSource.predicate = searchValue.predicate
return nil
}
self.navigationItem.searchController = self.searchController
self.navigationItem.hidesSearchBarWhenScrolling = false
self.definesPresentationContext = true
}
func updateTheme()
{
switch self.theme
@ -190,7 +243,7 @@ private extension GamesViewController
let indexPath = IndexPath(row: safeIndex, section: 0)
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "gameCollectionViewController") as! GameCollectionViewController
viewController.gameCollection = self.fetchedResultsController.object(at: indexPath) as! GameCollection
viewController.gameCollection = self.fetchedResultsController.object(at: indexPath) as? GameCollection
viewController.theme = self.theme
viewController.activeEmulatorCore = self.activeEmulatorCore
@ -402,6 +455,21 @@ extension GamesViewController: UIPageViewControllerDataSource, UIPageViewControl
}
}
extension GamesViewController: UISearchResultsUpdating
{
func updateSearchResults(for searchController: UISearchController)
{
if searchController.searchBar.text?.isEmpty == false
{
self.pageViewController.view.isHidden = true
}
else
{
self.pageViewController.view.isHidden = false
}
}
}
//MARK: - NSFetchedResultsControllerDelegate -
/// NSFetchedResultsControllerDelegate
extension GamesViewController: NSFetchedResultsControllerDelegate

View File

@ -85,48 +85,51 @@ extension GamesStoryboardSegue: UIViewControllerAnimatedTransitioning
snapshotView.alpha = 1.0
transitionContext.containerView.addSubview(snapshotView)
// Ensures navigation controller toolbar (if visible) has been added to view heirachy, allowing us to add constraints
transitionContext.containerView.layoutIfNeeded()
// We add extra padding around the existing navigation bar and toolbar so they never appear to be detached from the edges of the screen during the overshooting of the spring animation
var topPaddingToolbar: UIToolbar? = nil
var bottomPaddingToolbar: UIToolbar? = nil
if let navigationController = transitionContext.destinationViewController as? UINavigationController
{
let padding: CGFloat = 44
// Must be wrapped in no-animation block to prevent iOS 11 search bar from not appearing.
UIView.performWithoutAnimation {
// Ensures navigation controller toolbar (if visible) has been added to view heirachy, allowing us to add constraints
transitionContext.containerView.layoutIfNeeded()
if !navigationController.isNavigationBarHidden
if let navigationController = transitionContext.destinationViewController as? UINavigationController
{
let topToolbar = UIToolbar(frame: CGRect.zero)
topToolbar.translatesAutoresizingMaskIntoConstraints = false
topToolbar.barStyle = navigationController.toolbar.barStyle
transitionContext.destinationView.insertSubview(topToolbar, belowSubview: navigationController.navigationBar)
let padding: CGFloat = 44
topToolbar.bottomAnchor.constraint(equalTo: navigationController.navigationBar.bottomAnchor).isActive = true
topToolbar.centerXAnchor.constraint(equalTo: navigationController.navigationBar.centerXAnchor).isActive = true
topToolbar.widthAnchor.constraint(equalTo: navigationController.navigationBar.widthAnchor, constant: padding * 2).isActive = true
topToolbar.heightAnchor.constraint(equalTo: navigationController.navigationBar.heightAnchor, constant: padding).isActive = true
if !navigationController.isNavigationBarHidden
{
let topToolbar = UIToolbar(frame: CGRect.zero)
topToolbar.translatesAutoresizingMaskIntoConstraints = false
topToolbar.barStyle = navigationController.toolbar.barStyle
transitionContext.destinationView.insertSubview(topToolbar, at: 1)
topToolbar.topAnchor.constraint(equalTo: navigationController.navigationBar.topAnchor, constant: -padding).isActive = true
topToolbar.bottomAnchor.constraint(equalTo: navigationController.topViewController!.topLayoutGuide.bottomAnchor).isActive = true
topToolbar.leftAnchor.constraint(equalTo: navigationController.navigationBar.leftAnchor, constant: -padding).isActive = true
topToolbar.rightAnchor.constraint(equalTo: navigationController.navigationBar.rightAnchor, constant: padding).isActive = true
topPaddingToolbar = topToolbar
}
topPaddingToolbar = topToolbar
}
if !navigationController.isToolbarHidden
{
let bottomToolbar = UIToolbar(frame: CGRect.zero)
bottomToolbar.translatesAutoresizingMaskIntoConstraints = false
bottomToolbar.barStyle = navigationController.toolbar.barStyle
transitionContext.destinationView.insertSubview(bottomToolbar, belowSubview: navigationController.navigationBar)
bottomToolbar.topAnchor.constraint(equalTo: navigationController.toolbar.topAnchor).isActive = true
bottomToolbar.centerXAnchor.constraint(equalTo: navigationController.toolbar.centerXAnchor).isActive = true
bottomToolbar.widthAnchor.constraint(equalTo: navigationController.toolbar.widthAnchor, constant: padding * 2).isActive = true
bottomToolbar.heightAnchor.constraint(equalTo: navigationController.toolbar.heightAnchor, constant: padding).isActive = true
bottomPaddingToolbar = bottomToolbar
if !navigationController.isToolbarHidden
{
let bottomToolbar = UIToolbar(frame: CGRect.zero)
bottomToolbar.translatesAutoresizingMaskIntoConstraints = false
bottomToolbar.barStyle = navigationController.toolbar.barStyle
transitionContext.destinationView.insertSubview(bottomToolbar, belowSubview: navigationController.navigationBar)
bottomToolbar.topAnchor.constraint(equalTo: navigationController.toolbar.topAnchor).isActive = true
bottomToolbar.bottomAnchor.constraint(equalTo: navigationController.toolbar.bottomAnchor, constant: padding).isActive = true
bottomToolbar.leftAnchor.constraint(equalTo: navigationController.toolbar.leftAnchor, constant: -padding).isActive = true
bottomToolbar.rightAnchor.constraint(equalTo: navigationController.toolbar.rightAnchor, constant: padding).isActive = true
bottomPaddingToolbar = bottomToolbar
}
}
}
self.animator.addAnimations {
snapshotView.alpha = 0.0
transitionContext.destinationView.transform = CGAffineTransform.identity
@ -163,3 +166,4 @@ extension GamesStoryboardSegue: UIViewControllerAnimatedTransitioning
self.animator.startAnimation()
}
}

2
External/Roxas vendored

@ -1 +1 @@
Subproject commit 7434aef0372aca1d0b12cc4b8a6a37df034aae7c
Subproject commit 192682bb389830944d257946d870e1d50ae4c42b