diff --git a/Delta/Base.lproj/Main.storyboard b/Delta/Base.lproj/Main.storyboard
index 8512ccb..604d526 100644
--- a/Delta/Base.lproj/Main.storyboard
+++ b/Delta/Base.lproj/Main.storyboard
@@ -103,6 +103,9 @@
+
+
+
@@ -153,7 +156,7 @@
-
+
diff --git a/Delta/Base.lproj/PauseMenu.storyboard b/Delta/Base.lproj/PauseMenu.storyboard
index 7795544..0ab5e34 100644
--- a/Delta/Base.lproj/PauseMenu.storyboard
+++ b/Delta/Base.lproj/PauseMenu.storyboard
@@ -1,8 +1,10 @@
-
+
-
+
+
+
@@ -14,23 +16,20 @@
-
+
-
-
+
-
-
+
-
@@ -98,9 +97,9 @@
-
+
-
+
@@ -109,12 +108,11 @@
-
+
-
@@ -125,7 +123,7 @@
-
+
@@ -147,9 +145,9 @@
-
+
-
+
@@ -158,17 +156,16 @@
-
+
-
-
+
@@ -194,19 +191,19 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -232,21 +229,20 @@
-
+
-
+
-
+
-
+
-
@@ -268,14 +264,13 @@
-
+
-
+
-
@@ -297,15 +292,14 @@
-
+
-
+
-
-
+
diff --git a/Delta/Emulation/GameViewController.swift b/Delta/Emulation/GameViewController.swift
index 32b5ca4..1c3b332 100644
--- a/Delta/Emulation/GameViewController.swift
+++ b/Delta/Emulation/GameViewController.swift
@@ -12,6 +12,7 @@ import DeltaCore
class GameViewController: DeltaCore.GameViewController
{
+ /// Assumed to be Delta.Game instance
override var game: GameProtocol? {
didSet {
guard let emulatorCore = self.emulatorCore else { return }
@@ -22,6 +23,10 @@ class GameViewController: DeltaCore.GameViewController
// If non-nil, will override the default preview action items returned in previewActionItems()
var overridePreviewActionItems: [UIPreviewActionItem]?
+ //MARK: - Private Properties -
+ private var pauseViewController: PauseViewController?
+ private var pausingGameController: GameController?
+
required init()
{
super.init()
@@ -94,6 +99,39 @@ extension GameViewController
}
return [launchGameAction]
}
+
+ override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?)
+ {
+ guard let identifier = segue.identifier where identifier == "pause" else { return }
+
+ guard let gameController = sender as? GameController else {
+ fatalError("sender for pauseSegue must be the game controller that pressed the Menu button")
+ }
+
+ self.pausingGameController = gameController
+
+ let pauseViewController = segue.destinationViewController as! PauseViewController
+ pauseViewController.pauseText = (self.game as? Game)?.name ?? NSLocalizedString("Delta", comment: "")
+ pauseViewController.emulatorCore = self.emulatorCore
+ self.pauseViewController = pauseViewController
+ }
+
+ @IBAction private func unwindFromPauseViewController(_ segue: UIStoryboardSegue)
+ {
+ self.pauseViewController = nil
+ self.pausingGameController = nil
+
+ if self.resumeEmulation()
+ {
+ // Temporarily disable audioManager to prevent delayed audio bug when using 3D Touch Peek & Pop
+ self.emulatorCore?.audioManager.enabled = false
+
+ // Re-enable after delay
+ DispatchQueue.main.after(when: .now() + 0.1) {
+ self.emulatorCore?.audioManager.enabled = true
+ }
+ }
+ }
}
//MARK: Controllers -
@@ -141,13 +179,11 @@ extension GameViewController: GameViewControllerDelegate
{
self.pauseEmulation()
- let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
- alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: { (action) in
- self.resumeEmulation()
- }))
- alertController.addAction(UIAlertAction(title: NSLocalizedString("Stop Emulation", comment: ""), style: .destructive, handler: { (action) in
- self.dismiss(animated: true)
- }))
- self.present(alertController, animated: true)
+ self.performSegue(withIdentifier: "pause", sender: gameController)
+ }
+
+ func gameViewControllerShouldResumeEmulation(gameViewController: DeltaCore.GameViewController) -> Bool
+ {
+ return self.pauseViewController == nil
}
}
diff --git a/Delta/Pause Menu/PauseViewController.swift b/Delta/Pause Menu/PauseViewController.swift
index a12a25e..3685d7c 100644
--- a/Delta/Pause Menu/PauseViewController.swift
+++ b/Delta/Pause Menu/PauseViewController.swift
@@ -8,18 +8,31 @@
import UIKit
-class PauseViewController: UIViewController, PauseInfoProvidable
+import DeltaCore
+
+class PauseViewController: UIViewController, PauseInfoProviding
{
+ var emulatorCore: EmulatorCore? {
+ didSet {
+ self.updatePauseItems()
+ }
+ }
+
+ var pauseItems: [PauseItem] {
+ return [self.saveStateItem, self.loadStateItem, self.cheatCodesItem, self.sustainButtonsItem, self.fastForwardItem].flatMap { $0 }
+ }
+
/// Pause Items
- var items = [PauseItem]()
+ private(set) var saveStateItem: PauseItem?
+ private(set) var loadStateItem: PauseItem?
+ private(set) var cheatCodesItem: PauseItem?
+ private(set) var sustainButtonsItem: PauseItem?
+ private(set) var fastForwardItem: PauseItem?
- ///
- var pauseText: String? = nil
+ /// PauseInfoProviding
+ var pauseText: String?
- private weak var saveStatesViewControllerDelegate: SaveStatesViewControllerDelegate?
- private var saveStatesViewControllerMode = SaveStatesViewController.Mode.saving
-
- private weak var cheatsViewControllerDelegate: CheatsViewControllerDelegate?
+ private var pauseNavigationController: UINavigationController!
/// UIViewController
override var preferredContentSize: CGSize {
@@ -39,22 +52,10 @@ class PauseViewController: UIViewController, PauseInfoProvidable
override var navigationController: UINavigationController? {
return self.pauseNavigationController
}
-
- private var pauseNavigationController: UINavigationController!
}
extension PauseViewController
{
- override func viewDidLoad()
- {
- super.viewDidLoad()
- }
-
- override func didReceiveMemoryWarning()
- {
- super.didReceiveMemoryWarning()
- }
-
override func preferredStatusBarStyle() -> UIStatusBarStyle
{
return .lightContent
@@ -68,69 +69,49 @@ extension PauseViewController
self.pauseNavigationController.navigationBar.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.pauseNavigationController.navigationBar.bounds.height)
}
- override func targetViewController(forAction action: Selector, sender: AnyObject?) -> UIViewController? {
+ override func targetViewController(forAction action: Selector, sender: AnyObject?) -> UIViewController?
+ {
return self.pauseNavigationController
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?)
{
- switch segue.identifier ?? ""
+ guard let identifier = segue.identifier else { return }
+
+ switch identifier
{
case "embedNavigationController":
self.pauseNavigationController = segue.destinationViewController as! UINavigationController
- self.pauseNavigationController.delegate = self
self.pauseNavigationController.navigationBar.tintColor = UIColor.deltaLightPurpleColor()
self.pauseNavigationController.view.backgroundColor = UIColor.clear()
let pauseMenuViewController = self.pauseNavigationController.topViewController as! PauseMenuViewController
- pauseMenuViewController.items = self.items
+ pauseMenuViewController.items = self.pauseItems
// Keep navigation bar outside the UIVisualEffectView's
self.view.addSubview(self.pauseNavigationController.navigationBar)
-
- case "saveStates":
- let saveStatesViewController = segue.destinationViewController as! SaveStatesViewController
- saveStatesViewController.delegate = self.saveStatesViewControllerDelegate
- saveStatesViewController.mode = self.saveStatesViewControllerMode
-
- case "cheats":
- let cheatsViewController = segue.destinationViewController as! CheatsViewController
- cheatsViewController.delegate = self.cheatsViewControllerDelegate
-
+
default: break
}
}
}
-extension PauseViewController
+private extension PauseViewController
{
- func dismiss()
+ func updatePauseItems()
{
- self.performSegue(withIdentifier: "unwindFromPauseMenu", sender: self)
- }
-
- func presentSaveStateViewControllerWithMode(_ mode: SaveStatesViewController.Mode, delegate: SaveStatesViewControllerDelegate)
- {
- self.saveStatesViewControllerMode = mode
- self.saveStatesViewControllerDelegate = delegate
+ self.saveStateItem = nil
+ self.loadStateItem = nil
+ self.cheatCodesItem = nil
+ self.sustainButtonsItem = nil
+ self.fastForwardItem = nil
- self.performSegue(withIdentifier: "saveStates", sender: self)
- }
-
- func presentCheatsViewController(delegate: CheatsViewControllerDelegate)
- {
- self.cheatsViewControllerDelegate = delegate
+ guard self.emulatorCore != nil else { return }
- self.performSegue(withIdentifier: "cheats", sender: self)
- }
-}
-
-extension PauseViewController: UINavigationControllerDelegate
-{
- func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
- {
- let transitionCoordinator = PauseTransitionCoordinator(presentationController: self.presentationController!)
- transitionCoordinator.presenting = (operation == .push)
- return transitionCoordinator
+ self.saveStateItem = PauseItem(image: UIImage(named: "SaveSaveState")!, text: NSLocalizedString("Save State", comment: ""), action: { _ in })
+ self.loadStateItem = PauseItem(image: UIImage(named: "LoadSaveState")!, text: NSLocalizedString("Load State", comment: ""), action: { _ in })
+ self.cheatCodesItem = PauseItem(image: UIImage(named: "SmallPause")!, text: NSLocalizedString("Cheat Codes", comment: ""), action: { _ in })
+ self.sustainButtonsItem = PauseItem(image: UIImage(named: "SmallPause")!, text: NSLocalizedString("Sustain Buttons", comment: ""), action: { _ in })
+ self.fastForwardItem = PauseItem(image: UIImage(named: "FastForward")!, text: NSLocalizedString("Fast Forward", comment: ""), action: { _ in })
}
}
diff --git a/Delta/Pause Menu/Presentation Controller/PausePresentationController.swift b/Delta/Pause Menu/Presentation Controller/PausePresentationController.swift
index 5ebb2bd..cf20162 100644
--- a/Delta/Pause Menu/Presentation Controller/PausePresentationController.swift
+++ b/Delta/Pause Menu/Presentation Controller/PausePresentationController.swift
@@ -10,7 +10,7 @@ import UIKit
import Roxas
-protocol PauseInfoProvidable
+protocol PauseInfoProviding
{
var pauseText: String? { get }
}
@@ -57,11 +57,11 @@ class PausePresentationController: UIPresentationController
override func presentationTransitionWillBegin()
{
- if let provider = self.presentedViewController as? PauseInfoProvidable
+ if let provider = self.presentedViewController as? PauseInfoProviding
{
self.pauseLabel.text = provider.pauseText
}
- else if let navigationController = self.presentedViewController as? UINavigationController, provider = navigationController.topViewController as? PauseInfoProvidable
+ else if let navigationController = self.presentedViewController as? UINavigationController, provider = navigationController.topViewController as? PauseInfoProviding
{
self.pauseLabel.text = provider.pauseText
}
@@ -160,7 +160,10 @@ class PausePresentationController: UIPresentationController
self.presentedView()?.setNeedsLayout()
self.presentedView()?.layoutIfNeeded()
- self.presentedView()?.frame = self.frameOfPresentedViewInContainerView()
+ if self.presentingViewController.transitionCoordinator() == nil
+ {
+ self.presentedView()?.frame = self.frameOfPresentedViewInContainerView()
+ }
// Unhide pauseIconImageView so its height is involved with layout calculations
self.pauseIconImageView.isHidden = false
diff --git a/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift b/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift
index ecc64c0..ffc2bf3 100644
--- a/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift
+++ b/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift
@@ -10,10 +10,14 @@ import UIKit
class PauseStoryboardSegue: UIStoryboardSegue
{
+ private let animator: UIViewPropertyAnimator
private let presentationController: PausePresentationController
override init(identifier: String?, source: UIViewController, destination: UIViewController)
{
+ let timingParameters = UISpringTimingParameters(mass: 3.0, stiffness: 750, damping: 65, initialVelocity: CGVector(dx: 0, dy: 0))
+ self.animator = UIViewPropertyAnimator(duration: 0, timingParameters: timingParameters)
+
self.presentationController = PausePresentationController(presentedViewController: destination, presenting: source)
super.init(identifier: identifier, source: source, destination: destination)
@@ -25,6 +29,11 @@ class PauseStoryboardSegue: UIStoryboardSegue
self.destinationViewController.modalPresentationStyle = .custom
self.destinationViewController.modalPresentationCapturesStatusBarAppearance = true
+ // We need to force layout of destinationViewController.view _before_ animateTransition(using:)
+ // Otherwise, we'll get "Unable to simultaneously satisfy constraints" errors
+ self.destinationViewController.view.frame = self.sourceViewController.view.frame
+ self.destinationViewController.view.layoutIfNeeded()
+
super.perform()
}
}
@@ -51,29 +60,26 @@ extension PauseStoryboardSegue: UIViewControllerAnimatedTransitioning
{
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
{
- return 0.65
+ return self.animator.duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
{
- let destinationViewController = transitionContext.viewController(forKey: UITransitionContextToViewControllerKey)!
+ let presentedView = transitionContext.view(forKey: UITransitionContextToViewKey)!
+ let presentedViewController = transitionContext.viewController(forKey: UITransitionContextToViewControllerKey)!
- destinationViewController.view.frame = transitionContext.finalFrame(for: destinationViewController)
- destinationViewController.view.frame.origin.y = transitionContext.containerView().bounds.height
- transitionContext.containerView().addSubview(destinationViewController.view)
+ presentedView.frame = transitionContext.finalFrame(for: presentedViewController)
+ presentedView.frame.origin.y = transitionContext.containerView().bounds.height
+ transitionContext.containerView().addSubview(presentedView)
- UIView.animate(withDuration: self.transitionDuration(using: transitionContext), delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: [], animations: {
-
- // Calling layoutIfNeeded before the animation block for some reason prevents the blur from fading in
- // Additionally, if it's animated, it looks weird
- // So we need to wrap it in a no-animation block, inside an animation block. Blech.
- UIView.performWithoutAnimation({
- destinationViewController.view.layoutIfNeeded()
- })
-
- destinationViewController.view.frame = self.presentationController.frameOfPresentedViewInContainerView()
- }, completion: { finished in
- transitionContext.completeTransition(finished)
- })
+ self.animator.addAnimations { [unowned self] in
+ presentedView.frame = self.presentationController.frameOfPresentedViewInContainerView()
+ }
+
+ self.animator.addCompletion { position in
+ transitionContext.completeTransition(position == .end)
+ }
+
+ self.animator.startAnimation()
}
}