Adds support for dark theme when presenting SaveStatesViewController via 3D Touch/Long Press

This commit is contained in:
Riley Testut 2016-09-30 19:09:08 -07:00
parent 9f0a376946
commit b80dbd4e26
6 changed files with 174 additions and 62 deletions

View File

@ -58,6 +58,7 @@
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 */; };
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */; };
BFE704F51CEA426E0058BAC8 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22506DA00971C4300AF90A35 /* Pods.framework */; };
BFEC732D1AAECC4A00650035 /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; };
BFEC732E1AAECC4A00650035 /* Roxas.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@ -146,6 +147,7 @@
BFDB28441BC9DA7B001D0C83 /* GamePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamePickerController.swift; sourceTree = "<group>"; };
BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = "<group>"; };
BFDE39391BC0CEDF003F72E8 /* Game.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Game.swift; sourceTree = "<group>"; };
BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SaveStatesStoryboardSegue.swift; path = Segues/SaveStatesStoryboardSegue.swift; sourceTree = "<group>"; };
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; };
BFFA71DB1AAC406100EE9DD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -436,6 +438,7 @@
BFFC461D1D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift */,
BFFC461C1D59823500AF2CC6 /* GamesStoryboardSegue.swift */,
BFFC461B1D59823500AF2CC6 /* GamesPresentationController.swift */,
BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */,
);
name = Segues;
sourceTree = "<group>";
@ -595,6 +598,7 @@
BF353FF91C5D870B00C1184C /* PauseItem.swift in Sources */,
BFBAA86A1D5A483900A29C1B /* DatabaseManager.swift in Sources */,
BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */,
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */,
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
BF7AE81E1C2E984300B1B5BC /* GridCollectionViewCell.swift in Sources */,
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11191" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="yhz-fF-D91">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="16A320" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="yhz-fF-D91">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11156"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -80,6 +80,7 @@
</collectionView>
<connections>
<segue destination="X2o-q6-XD5" kind="unwind" identifier="unwindFromGames" unwindAction="unwindFromGamesViewControllerWith:" id="k8C-Xn-maU"/>
<segue destination="MPk-bF-nkj" kind="presentation" identifier="showSaveStates" customClass="SaveStatesStoryboardSegue" customModule="Delta" customModuleProvider="target" id="1Xp-2J-0cq"/>
</connections>
</collectionViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bW1-t8-idm" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -129,7 +130,7 @@
<!--Navigation Controller-->
<scene sceneID="zJI-sC-1sm">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="wKV-3d-NIY" sceneMemberID="viewController">
<navigationController storyboardIdentifier="gamesNavigationController" automaticallyAdjustsScrollViewInsets="NO" id="wKV-3d-NIY" sceneMemberID="viewController">
<toolbarItems/>
<nil key="simulatedBottomBarMetrics"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wj9-1e-eev">
@ -157,6 +158,36 @@
</objects>
<point key="canvasLocation" x="-491" y="1431"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="nR0-Va-AI1">
<objects>
<navigationController storyboardIdentifier="saveStatesNavigationController" automaticallyAdjustsScrollViewInsets="NO" id="MPk-bF-nkj" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="twH-3X-6DV">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="Eae-Qk-9MI" kind="relationship" relationship="rootViewController" id="1Jh-Zf-ntp"/>
<segue destination="WQV-Du-4IA" kind="unwind" identifier="unwindFromSaveStates" customClass="SaveStatesStoryboardUnwindSegue" customModule="Delta" customModuleProvider="target" unwindAction="unwindFromSaveStatesViewController:" id="dwO-iv-XDr"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="htj-tq-2KP" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="WQV-Du-4IA" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="2562" y="1718"/>
</scene>
<!--saveStatesViewController-->
<scene sceneID="f1R-Kb-FOU">
<objects>
<viewControllerPlaceholder storyboardName="PauseMenu" referencedIdentifier="saveStatesViewController" id="Eae-Qk-9MI" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="MoJ-ol-Cdh"/>
</viewControllerPlaceholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="eln-PZ-00u" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3319" y="1717"/>
</scene>
</scenes>
<resources>
<image name="Settings_Button" width="22" height="22"/>

View File

@ -97,44 +97,60 @@ extension GameCollectionViewController
{
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard let identifier = segue.identifier, identifier == "unwindFromGames" else { return }
guard let identifier = segue.identifier 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
if let saveState = self.activeSaveState
switch identifier
{
// Must be synchronous or else there will be a flash of black
destinationViewController.emulatorCore?.start()
destinationViewController.emulatorCore?.pause()
case "showSaveStates":
let game = sender as! Game
do
let saveStatesViewController = (segue.destination as! UINavigationController).topViewController as! SaveStatesViewController
saveStatesViewController.delegate = self
saveStatesViewController.game = game
saveStatesViewController.mode = .loading
saveStatesViewController.theme = self.theme
case "unwindFromGames":
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
if let saveState = self.activeSaveState
{
try destinationViewController.emulatorCore?.load(saveState)
}
catch EmulatorCore.SaveStateError.doesNotExist
{
print("Save State does not exist.")
}
catch
{
print(error)
// Must be synchronous or else there will be a flash of black
destinationViewController.emulatorCore?.start()
destinationViewController.emulatorCore?.pause()
do
{
try destinationViewController.emulatorCore?.load(saveState)
}
catch EmulatorCore.SaveStateError.doesNotExist
{
print("Save State does not exist.")
}
catch
{
print(error)
}
destinationViewController.emulatorCore?.resume()
}
destinationViewController.emulatorCore?.resume()
self.activeSaveState = nil
if _performing3DTouchTransition
{
_destination3DTouchTransitionViewController = destinationViewController
}
default: break
}
self.activeSaveState = nil
if _performing3DTouchTransition
{
_destination3DTouchTransitionViewController = destinationViewController
}
}
}
@ -228,17 +244,7 @@ private extension GameCollectionViewController
func viewSaveStates(for game: Game)
{
let storyboard = UIStoryboard(name: "PauseMenu", bundle: nil)
let saveStatesViewController = storyboard.instantiateViewController(withIdentifier: "saveStatesViewController") as! SaveStatesViewController
saveStatesViewController.delegate = self
saveStatesViewController.game = game
saveStatesViewController.mode = .loading
saveStatesViewController.theme = .light
saveStatesViewController.showsDoneButton = true
let navigationController = UINavigationController(rootViewController: saveStatesViewController)
self.present(navigationController, animated: true, completion: nil)
self.performSegue(withIdentifier: "showSaveStates", sender: game)
}
@objc func handleLongPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer)

View File

@ -126,6 +126,10 @@ extension GamesViewController
@IBAction private func unwindFromSettingsViewController(_ segue: UIStoryboardSegue)
{
}
@IBAction private func unwindFromSaveStatesViewController(_ segue: UIStoryboardSegue)
{
}
}
// MARK: - UI -

View File

@ -0,0 +1,82 @@
//
// SaveStatesStoryboardSegue.swift
// Delta
//
// Created by Riley Testut on 9/28/16.
// Copyright © 2016 Riley Testut. All rights reserved.
//
import UIKit
class SaveStatesStoryboardSegue: UIStoryboardSegue
{
private var destinationNavigationController: UINavigationController?
override func perform()
{
super.perform()
self.destinationNavigationController = self.destination as? UINavigationController
guard let saveStatesViewController = self.destinationNavigationController?.topViewController as? SaveStatesViewController else { return }
// Ensures saveStatesViewController doesn't later remove our Done button
saveStatesViewController.loadViewIfNeeded()
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(SaveStatesStoryboardSegue.handleDoneButton))
saveStatesViewController.navigationItem.rightBarButtonItem = doneButton
guard saveStatesViewController.theme == .dark else { return }
let sourceView = self.source.navigationController!.view!
let maskView = UIView(frame: CGRect(x: 0, y: 0, width: sourceView.bounds.width, height: sourceView.bounds.height))
maskView.backgroundColor = UIColor.white
sourceView.mask = maskView
self.destination.transitionCoordinator?.animate(alongsideTransition: { (context) in
maskView.frame.size.height = 0
}, completion: { (context) in
sourceView.mask = nil
})
}
@objc private func handleDoneButton()
{
self.destinationNavigationController?.performSegue(withIdentifier: "unwindFromSaveStates", sender: nil)
}
}
class SaveStatesStoryboardUnwindSegue: UIStoryboardSegue
{
override func perform()
{
super.perform()
guard let saveStatesViewController = (self.source as? UINavigationController)?.topViewController as? SaveStatesViewController, saveStatesViewController.theme == .dark else { return }
let destinationView = self.destination.navigationController!.view!
let maskView = UIView(frame: CGRect(x: 0, y: 0, width: destinationView.bounds.width, height: 0))
maskView.backgroundColor = UIColor.white
destinationView.mask = maskView
// Need to add a dummy view to view hierarchy + animate it to ensure UIViewPropertyAnimator actually runs the animations 🙄
let dummyView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
dummyView.backgroundColor = UIColor.clear
self.source.view?.window?.insertSubview(dummyView, at: 0)
// Apparently UIViewControllerTransitionCoordinator doesn't run its additional animations with same timing curve as the transition animation, so we use our own spring animation
let animator = UIViewPropertyAnimator(duration: 0, timingParameters: UISpringTimingParameters())
animator.addAnimations {
maskView.frame.size.height = destinationView.bounds.height
dummyView.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
}
animator.addCompletion { (position) in
destinationView.mask = nil
dummyView.removeFromSuperview()
}
animator.startAnimation()
}
}

View File

@ -58,8 +58,6 @@ class SaveStatesViewController: UICollectionViewController
}
}
var showsDoneButton = false
fileprivate var vibrancyView: UIVisualEffectView!
fileprivate var backgroundView: RSTBackgroundView!
@ -126,12 +124,6 @@ extension SaveStatesViewController
self.navigationItem.rightBarButtonItem = nil
}
if self.showsDoneButton
{
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(SaveStatesViewController.handleDoneButton))
self.navigationItem.rightBarButtonItem = doneButton
}
// Manually update prototype cell properties
self.prototypeCellWidthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionViewLayout.itemWidth)
self.prototypeCellWidthConstraint.isActive = true
@ -224,13 +216,6 @@ private extension SaveStatesViewController
}
}
//MARK: - Navigation -
@objc func handleDoneButton()
{
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
//MARK: - Configure Views -
func configureCollectionViewCell(_ cell: GridCollectionViewCell, forIndexPath indexPath: IndexPath, ignoreExpensiveOperations ignoreOperations: Bool = false)