Adds Save States action when previewing/long pressing games

This commit is contained in:
Riley Testut 2016-09-27 15:35:55 -07:00
parent 3b9d169367
commit f06fb72908
6 changed files with 178 additions and 28 deletions

View File

@ -32,6 +32,7 @@
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */; };
BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF5E7F451B9A652600AE44F8 /* Settings.storyboard */; };
BF65E8631CEE5C6A00CD3247 /* Cheat.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF65E8621CEE5C6A00CD3247 /* Cheat.swift */; };
BF696B801D9B2B02009639E0 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF696B7F1D9B2B02009639E0 /* Theme.swift */; };
BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; };
BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
BF762EAB1BC1B076002C8866 /* NSManagedObject+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF762EAA1BC1B076002C8866 /* NSManagedObject+Conveniences.swift */; };
@ -124,6 +125,7 @@
BF5E7F451B9A652600AE44F8 /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = "<group>"; };
BF63BDE91D389EEB00FCB040 /* GameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = "<group>"; };
BF65E8621CEE5C6A00CD3247 /* Cheat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cheat.swift; sourceTree = "<group>"; };
BF696B7F1D9B2B02009639E0 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Theme.swift; path = Theming/Theme.swift; sourceTree = "<group>"; };
BF6BB2451BB73FE800CCF94A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
BF70798B1B6B464B0019077C /* ZipZap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ZipZap.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BF762EAA1BC1B076002C8866 /* NSManagedObject+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Conveniences.swift"; sourceTree = "<group>"; };
@ -257,6 +259,14 @@
path = "Game Selection";
sourceTree = "<group>";
};
BF696B7E1D9B2AE6009639E0 /* Theming */ = {
isa = PBXGroup;
children = (
BF696B7F1D9B2B02009639E0 /* Theme.swift */,
);
name = Theming;
sourceTree = "<group>";
};
BF762EA91BC1B044002C8866 /* Extensions */ = {
isa = PBXGroup;
children = (
@ -394,6 +404,7 @@
BFFB709D1AF99ACA00DE56FE /* Emulation */,
BF7AE7FA1C2E851F00B1B5BC /* Pause Menu */,
BFAA1FEB1B8AA4E800495943 /* Settings */,
BF696B7E1D9B2AE6009639E0 /* Theming */,
BF090CEE1B490C1A00DCAB45 /* Extensions */,
BFFA71DA1AAC406100EE9DD1 /* Supporting Files */,
);
@ -614,6 +625,7 @@
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */,
BF353FF21C5D7FB000C1184C /* PauseViewController.swift in Sources */,
BFDB28451BC9DA7B001D0C83 /* GamePickerController.swift in Sources */,
BF696B801D9B2B02009639E0 /* Theme.swift in Sources */,
BF7AE8081C2E858400B1B5BC /* PauseMenuViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -21,7 +21,7 @@ class GameCollectionViewController: UICollectionViewController
}
}
var theme: GamesViewController.Theme = .light {
var theme: Theme = .light {
didSet {
self.collectionView?.reloadData()
}
@ -197,11 +197,15 @@ private extension GameCollectionViewController
{
let cancelAction = Action(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, action: nil)
let saveStatesAction = Action(title: NSLocalizedString("Save States", comment: ""), style: .default, action: { [unowned self] action in
self.viewSaveStates(for: game)
})
let deleteAction = Action(title: NSLocalizedString("Delete", comment: ""), style: .destructive, action: { [unowned self] action in
self.delete(game)
})
return [cancelAction, deleteAction]
return [cancelAction, saveStatesAction, deleteAction]
}
func delete(_ game: Game)
@ -222,6 +226,21 @@ private extension GameCollectionViewController
self.present(confirmationAlertController, animated: true, completion: nil)
}
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)
}
@objc func handleLongPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer)
{
guard gestureRecognizer.state == .began else { return }
@ -295,6 +314,27 @@ extension GameCollectionViewController: UIViewControllerPreviewingDelegate
}
}
//MARK: - SaveStatesViewControllerDelegate -
/// SaveStatesViewControllerDelegate
extension GameCollectionViewController: SaveStatesViewControllerDelegate
{
func saveStatesViewController(_ saveStatesViewController: SaveStatesViewController, updateSaveState saveState: SaveState)
{
}
func saveStatesViewController(_ saveStatesViewController: SaveStatesViewController, loadSaveState saveState: SaveStateProtocol)
{
self.activeSaveState = saveState
self.dismiss(animated: true) {
let indexPath = self.dataSource.fetchedResultsController.indexPath(forObject: saveStatesViewController.game)!
let cell = self.collectionView?.cellForItem(at: indexPath)
self.launchGame(withSender: cell, clearScreen: false)
}
}
}
//MARK: - UICollectionViewDelegate -
/// UICollectionViewDelegate
extension GameCollectionViewController

View File

@ -13,15 +13,6 @@ import DeltaCore
import Roxas
extension GamesViewController
{
enum Theme
{
case light
case dark
}
}
class GamesViewController: UIViewController
{
var theme: Theme = .light {

View File

@ -12,6 +12,21 @@ class SaveStatesCollectionHeaderView: UICollectionReusableView
{
let textLabel = UILabel()
fileprivate let vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .dark)))
var isTextLabelVibrancyEnabled = true {
didSet {
if self.isTextLabelVibrancyEnabled
{
self.vibrancyView.contentView.addSubview(self.textLabel)
}
else
{
self.addSubview(self.textLabel)
}
}
}
override init(frame: CGRect)
{
super.init(frame: frame)
@ -28,10 +43,9 @@ class SaveStatesCollectionHeaderView: UICollectionReusableView
private func initialize()
{
let vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .dark)))
vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
vibrancyView.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height)
self.addSubview(vibrancyView)
self.vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.vibrancyView.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height)
self.addSubview(self.vibrancyView)
self.textLabel.translatesAutoresizingMaskIntoConstraints = false
self.textLabel.textColor = UIColor.white
@ -41,10 +55,12 @@ class SaveStatesCollectionHeaderView: UICollectionReusableView
self.textLabel.font = UIFont(descriptor: fontDescriptor, size: 0.0)
self.textLabel.textAlignment = .center
vibrancyView.contentView.addSubview(self.textLabel)
self.vibrancyView.contentView.addSubview(self.textLabel)
// Auto Layout
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-20-[textLabel]-20-|", options: [], metrics: nil, views: ["textLabel": self.textLabel]))
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[textLabel]|", options: [], metrics: nil, views: ["textLabel": self.textLabel]))
self.textLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true
self.textLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
self.textLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
self.textLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
}

View File

@ -49,6 +49,18 @@ class SaveStatesViewController: UICollectionViewController
var mode = Mode.loading
var theme = Theme.dark {
didSet {
if self.isViewLoaded
{
self.updateTheme()
}
}
}
var showsDoneButton = false
fileprivate var vibrancyView: UIVisualEffectView!
fileprivate var backgroundView: RSTBackgroundView!
fileprivate var prototypeCell = GridCollectionViewCell()
@ -81,10 +93,10 @@ extension SaveStatesViewController
{
super.viewDidLoad()
let vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .dark)))
vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
vibrancyView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
self.view.insertSubview(vibrancyView, at: 0)
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
@ -92,7 +104,7 @@ extension SaveStatesViewController
self.backgroundView.textLabel.text = NSLocalizedString("No Save States", comment: "")
self.backgroundView.textLabel.textColor = UIColor.white
self.backgroundView.detailTextLabel.textColor = UIColor.white
vibrancyView.contentView.addSubview(self.backgroundView)
self.vibrancyView.contentView.addSubview(self.backgroundView)
let collectionViewLayout = self.collectionViewLayout as! GridCollectionViewLayout
let averageHorizontalInset = (collectionViewLayout.sectionInset.left + collectionViewLayout.sectionInset.right) / 2
@ -114,6 +126,12 @@ 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
@ -126,6 +144,7 @@ extension SaveStatesViewController
self.registerForPreviewing(with: self, sourceView: self.collectionView!)
self.updateBackgroundView()
self.updateTheme()
}
override func viewWillAppear(_ animated: Bool)
@ -177,6 +196,41 @@ private extension SaveStatesViewController
}
}
func updateTheme()
{
switch self.theme
{
case .light:
self.view.backgroundColor = UIColor.white
self.navigationController?.navigationBar.barStyle = .default
self.navigationController?.toolbar.barStyle = .default
self.vibrancyView.effect = nil
self.backgroundView.textLabel.textColor = UIColor.gray
self.backgroundView.detailTextLabel.textColor = UIColor.gray
case .dark:
self.view.backgroundColor = nil
self.navigationController?.navigationBar.barStyle = .blackTranslucent
self.navigationController?.toolbar.barStyle = .blackTranslucent
self.vibrancyView.effect = UIVibrancyEffect(blurEffect: UIBlurEffect(style: .dark))
self.backgroundView.textLabel.textColor = UIColor.white
self.backgroundView.detailTextLabel.textColor = UIColor.white
}
}
//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)
@ -186,8 +240,20 @@ private extension SaveStatesViewController
cell.imageView.backgroundColor = UIColor.white
cell.imageView.image = UIImage(named: "DeltaPlaceholder")
cell.isTextLabelVibrancyEnabled = true
cell.isImageViewVibrancyEnabled = true
switch self.theme
{
case .light:
cell.isTextLabelVibrancyEnabled = false
cell.isImageViewVibrancyEnabled = false
cell.textLabel.textColor = UIColor.gray
case .dark:
cell.isTextLabelVibrancyEnabled = true
cell.isImageViewVibrancyEnabled = true
cell.textLabel.textColor = UIColor.white
}
if !ignoreOperations
{
@ -218,7 +284,6 @@ private extension SaveStatesViewController
let dimensions = deltaCore.emulatorConfiguration.videoBufferInfo.outputDimensions
cell.maximumImageSize = CGSize(width: self.prototypeCellWidthConstraint.constant, height: (self.prototypeCellWidthConstraint.constant / dimensions.width) * dimensions.height)
cell.textLabel.textColor = UIColor.white
cell.textLabel.font = UIFont.preferredFont(forTextStyle: .subheadline)
let name = saveState.name ?? self.dateFormatter.string(from: saveState.modifiedDate)
@ -239,6 +304,17 @@ private extension SaveStatesViewController
}
headerView.textLabel.text = title
switch self.theme
{
case .light:
headerView.textLabel.textColor = UIColor.gray
headerView.isTextLabelVibrancyEnabled = false
case .dark:
headerView.textLabel.textColor = UIColor.white
headerView.isTextLabelVibrancyEnabled = true
}
}
//MARK: - Gestures -
@ -549,10 +625,10 @@ extension SaveStatesViewController: UIViewControllerPreviewingDelegate
{
guard
let indexPath = self.collectionView?.indexPathForItem(at: location),
let layoutAttributes = self.collectionViewLayout.layoutAttributesForItem(at: indexPath),
self.emulatorCoreSaveState != nil
let layoutAttributes = self.collectionViewLayout.layoutAttributesForItem(at: indexPath)
else { return nil }
guard self.emulatorCore == nil || (self.emulatorCore != nil && self.emulatorCoreSaveState != nil) else { return nil }
previewingContext.sourceRect = layoutAttributes.frame

15
Delta/Theming/Theme.swift Normal file
View File

@ -0,0 +1,15 @@
//
// Theme.swift
// Delta
//
// Created by Riley Testut on 9/27/16.
// Copyright © 2016 Riley Testut. All rights reserved.
//
import Foundation
enum Theme
{
case light
case dark
}