Adds ControllerSkinsViewController

Displays all controller skins that support provided Traits
This commit is contained in:
Riley Testut 2016-11-07 14:32:12 -08:00
parent 3a631cf5e6
commit 7664c72f12
11 changed files with 487 additions and 66 deletions

View File

@ -0,0 +1,60 @@
//
// LoadControllerSkinImageOperation.swift
// Delta
//
// Created by Riley Testut on 10/28/16.
// Copyright © 2016 Riley Testut. All rights reserved.
//
import UIKit
import DeltaCore
class ControllerSkinImageCacheKey: NSObject
{
let controllerSkin: ControllerSkin
let traits: DeltaCore.ControllerSkin.Traits
let size: DeltaCore.ControllerSkin.Size
override var hash: Int {
return self.controllerSkin.hashValue ^ self.traits.hashValue ^ self.size.hashValue
}
init(controllerSkin: ControllerSkin, traits: DeltaCore.ControllerSkin.Traits, size: DeltaCore.ControllerSkin.Size)
{
self.controllerSkin = controllerSkin
self.traits = traits
self.size = size
super.init()
}
override func isEqual(_ object: Any?) -> Bool
{
guard let object = object as? ControllerSkinImageCacheKey else { return false }
return self.controllerSkin == object.controllerSkin && self.traits == object.traits && self.size == object.size
}
}
class LoadControllerSkinImageOperation: LoadImageOperation<ControllerSkinImageCacheKey>
{
let controllerSkin: ControllerSkin
let traits: DeltaCore.ControllerSkin.Traits
let size: DeltaCore.ControllerSkin.Size
init(controllerSkin: ControllerSkin, traits: DeltaCore.ControllerSkin.Traits, size: DeltaCore.ControllerSkin.Size)
{
self.controllerSkin = controllerSkin
self.traits = traits
self.size = size
let cacheKey = ControllerSkinImageCacheKey(controllerSkin: controllerSkin, traits: traits, size: size)
super.init(cacheKey: cacheKey)
}
override func loadImage() -> UIImage?
{
let image = self.controllerSkin.image(for: self.traits, preferredSize: self.size)
return image
}
}

View File

@ -11,11 +11,9 @@ import ImageIO
import Roxas
public class LoadImageOperation: RSTOperation
class LoadImageOperation<CacheKeyType: AnyObject>: RSTOperation
{
public let URL: Foundation.URL
public var completionHandler: ((UIImage?) -> Void)? {
var completionHandler: ((UIImage?) -> Void)? {
didSet {
self.completionBlock = {
rst_dispatch_sync_on_main_thread() {
@ -25,49 +23,47 @@ public class LoadImageOperation: RSTOperation
}
}
public var imageCache: NSCache<NSURL, UIImage>? {
var imageCache: NSCache<CacheKeyType, UIImage>? {
didSet {
// Ensures if an image is cached, it will be returned immediately, to prevent temporary flash of placeholder image
self.isImmediate = self.imageCache?.object(forKey: self.URL as NSURL) != nil
self.isImmediate = self.imageCache?.object(forKey: self.cacheKey) != nil
}
}
fileprivate var image: UIImage?
private let cacheKey: CacheKeyType
private var image: UIImage?
public init(URL: Foundation.URL)
init(cacheKey: CacheKeyType)
{
self.URL = URL
self.cacheKey = cacheKey
super.init()
}
}
public extension LoadImageOperation
{
override public func main()
override func main()
{
guard !self.isCancelled else { return }
if let cachedImage = self.imageCache?.object(forKey: self.URL as NSURL)
if let cachedImage = self.imageCache?.object(forKey: self.cacheKey)
{
self.image = cachedImage
return
}
let options: NSDictionary = [kCGImageSourceShouldCache as NSString: true]
guard let loadedImage = self.loadImage() else { return }
if let imageSource = CGImageSourceCreateWithURL(self.URL as CFURL, options), let quartzImage = CGImageSourceCreateImageAtIndex(imageSource, 0, options)
{
let loadedImage = UIImage(cgImage: quartzImage)
// Force decompression of image
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1, height: 1), true, 1.0)
loadedImage.draw(at: CGPoint.zero)
UIGraphicsEndImageContext()
self.imageCache?.setObject(loadedImage, forKey: self.URL as NSURL)
self.image = loadedImage
}
// Force decompression of image
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1, height: 1), true, 1.0)
loadedImage.draw(at: CGPoint.zero)
UIGraphicsEndImageContext()
self.imageCache?.setObject(loadedImage, forKey: self.cacheKey)
self.image = loadedImage
}
func loadImage() -> UIImage?
{
return nil
}
}

View File

@ -0,0 +1,33 @@
//
// LoadImageURLOperation.swift
// Delta
//
// Created by Riley Testut on 10/28/16.
// Copyright © 2016 Riley Testut. All rights reserved.
//
import UIKit
import ImageIO
import Roxas
class LoadImageURLOperation: LoadImageOperation<NSURL>
{
public let url: URL
init(url: URL)
{
self.url = url
super.init(cacheKey: url as NSURL)
}
override func loadImage() -> UIImage?
{
let options: NSDictionary = [kCGImageSourceShouldCache as NSString: true]
guard let imageSource = CGImageSourceCreateWithURL(self.url as CFURL, options), let quartzImage = CGImageSourceCreateImageAtIndex(imageSource, 0, options) else { return nil }
let image = UIImage(cgImage: quartzImage)
return image
}
}

View File

@ -65,6 +65,15 @@ public class ControllerSkin: _ControllerSkin
let controllerSkin = self.isStandard ? DeltaCore.ControllerSkin.standardControllerSkin(for: self.gameType) : DeltaCore.ControllerSkin(fileURL: self.fileURL)
return controllerSkin
}()
public override func awakeFromFetch()
{
super.awakeFromFetch()
// Kinda hacky, but we initialize controllerSkin on fetch to ensure it is initialized on the correct thread
// We could solve this by wrapping controllerSkin.getter in performAndWait block, but this can lead to a deadlock
_ = self.controllerSkin
}
}
extension ControllerSkin: ControllerSkinProtocol

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
BF0418141D01E93400E85BCF /* GBADeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF0418131D01E93400E85BCF /* GBADeltaCore.framework */; };
BF0418151D01E93400E85BCF /* GBADeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF0418131D01E93400E85BCF /* GBADeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF04E6FE1DB8625C000F35D3 /* ControllerSkinsViewController.swift */; };
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */ = {isa = PBXBuildFile; fileRef = BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */; };
BF0CDDAD1C8155D200640168 /* LoadImageOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0CDDAC1C8155D200640168 /* LoadImageOperation.swift */; };
BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF107EC31BF413F000E0C32C /* GamesViewController.swift */; };
@ -39,6 +40,7 @@
BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF353FFE1C5DA3C500C1184C /* PausePresentationControllerContentView.xib */; };
BF3540021C5DA3D500C1184C /* PauseStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540011C5DA3D500C1184C /* PauseStoryboardSegue.swift */; };
BF3540081C5DAFAD00C1184C /* PauseTransitionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540071C5DAFAD00C1184C /* PauseTransitionCoordinator.swift */; };
BF4F562B1DC3C6AF00267E32 /* LoadImageURLOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4F562A1DC3C6AF00267E32 /* LoadImageURLOperation.swift */; };
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */; };
BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF5E7F451B9A652600AE44F8 /* Settings.storyboard */; };
BF6866171DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6866161DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift */; };
@ -51,6 +53,7 @@
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */; };
BF7AE81E1C2E984300B1B5BC /* GridCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE81A1C2E984300B1B5BC /* GridCollectionViewCell.swift */; };
BF7AE8241C2E984300B1B5BC /* GridCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE81D1C2E984300B1B5BC /* GridCollectionViewLayout.swift */; };
BF99A5971DC2F9C400468E9E /* ControllerSkinTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF99A5961DC2F9C400468E9E /* ControllerSkinTableViewCell.swift */; };
BF99C6941D0A9AA600BA92BC /* SNESDeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */; };
BF99C6951D0A9AA600BA92BC /* SNESDeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
BF9F4FCF1AAD7B87004C9500 /* DeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9F4FCE1AAD7B87004C9500 /* DeltaCore.framework */; };
@ -58,6 +61,7 @@
BFA0D1271D3AE1F600565894 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63BDE91D389EEB00FCB040 /* GameViewController.swift */; };
BFA2315C1CED10BE0011E35A /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA2315B1CED10BE0011E35A /* Action.swift */; };
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FEC1B8AA4FA00495943 /* Settings.swift */; };
BFACD5FD1DC3D2CE002D6DDC /* LoadControllerSkinImageOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF23C4941DC3CB2E00849B3E /* LoadControllerSkinImageOperation.swift */; };
BFBAA86A1D5A483900A29C1B /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBAA8691D5A483900A29C1B /* DatabaseManager.swift */; };
BFC853351DB039AD00E8C372 /* _ControllerSkin.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC853341DB039AD00E8C372 /* _ControllerSkin.swift */; };
BFC853371DB039B500E8C372 /* ControllerSkin.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC853361DB039B500E8C372 /* ControllerSkin.swift */; };
@ -106,6 +110,7 @@
BF02BCFE1D361BD1000892F2 /* NSFetchedResultsController+Conveniences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSFetchedResultsController+Conveniences.h"; sourceTree = "<group>"; };
BF02BCFF1D361BD1000892F2 /* NSFetchedResultsController+Conveniences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSFetchedResultsController+Conveniences.m"; sourceTree = "<group>"; };
BF0418131D01E93400E85BCF /* GBADeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBADeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BF04E6FE1DB8625C000F35D3 /* ControllerSkinsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControllerSkinsViewController.swift; path = "Controller Skins/ControllerSkinsViewController.swift"; sourceTree = "<group>"; };
BF090CF11B490D8300DCAB45 /* Delta-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Delta-Bridging-Header.h"; sourceTree = "<group>"; };
BF090CF21B490D8300DCAB45 /* UIDevice+Vibration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+Vibration.h"; sourceTree = "<group>"; };
BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+Vibration.m"; sourceTree = "<group>"; };
@ -118,6 +123,7 @@
BF13A7571D5D2FD9000BB055 /* EmulatorCore+Cheats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EmulatorCore+Cheats.swift"; sourceTree = "<group>"; };
BF172AEA1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Conveniences.swift"; sourceTree = "<group>"; };
BF1DAD5C1D9F576000E752A7 /* GameTypeControllerSkinsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameTypeControllerSkinsViewController.swift; path = "Controller Skins/GameTypeControllerSkinsViewController.swift"; sourceTree = "<group>"; };
BF23C4941DC3CB2E00849B3E /* LoadControllerSkinImageOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LoadControllerSkinImageOperation.swift; path = Components/LoadControllerSkinImageOperation.swift; sourceTree = "<group>"; };
BF27CC861BC9E3C600A20D89 /* Delta.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Delta.entitlements; sourceTree = "<group>"; };
BF27CC8A1BC9FE4D00A20D89 /* Pods.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pods.framework; path = "Pods/../build/Debug-appletvos/Pods.framework"; sourceTree = "<group>"; };
BF27CC941BCB7B7A00A20D89 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; };
@ -142,6 +148,7 @@
BF3540011C5DA3D500C1184C /* PauseStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseStoryboardSegue.swift; path = "Pause Menu/Segues/PauseStoryboardSegue.swift"; sourceTree = "<group>"; };
BF3540041C5DA70400C1184C /* SaveStatesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SaveStatesViewController.swift; path = "Pause Menu/Save States/SaveStatesViewController.swift"; sourceTree = "<group>"; };
BF3540071C5DAFAD00C1184C /* PauseTransitionCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseTransitionCoordinator.swift; path = "Pause Menu/Segues/PauseTransitionCoordinator.swift"; sourceTree = "<group>"; };
BF4F562A1DC3C6AF00267E32 /* LoadImageURLOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LoadImageURLOperation.swift; path = Components/LoadImageURLOperation.swift; sourceTree = "<group>"; };
BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
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>"; };
@ -155,6 +162,7 @@
BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Delta.swift"; sourceTree = "<group>"; };
BF7AE81A1C2E984300B1B5BC /* GridCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GridCollectionViewCell.swift; path = "Collection View/GridCollectionViewCell.swift"; sourceTree = "<group>"; };
BF7AE81D1C2E984300B1B5BC /* GridCollectionViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GridCollectionViewLayout.swift; path = "Collection View/GridCollectionViewLayout.swift"; sourceTree = "<group>"; };
BF99A5961DC2F9C400468E9E /* ControllerSkinTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControllerSkinTableViewCell.swift; path = "Controller Skins/ControllerSkinTableViewCell.swift"; sourceTree = "<group>"; };
BF9F4FCE1AAD7B87004C9500 /* DeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BFA2315B1CED10BE0011E35A /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Action.swift; path = Components/Action.swift; sourceTree = "<group>"; };
BFAA1FEC1B8AA4FA00495943 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
@ -241,6 +249,8 @@
isa = PBXGroup;
children = (
BF1DAD5C1D9F576000E752A7 /* GameTypeControllerSkinsViewController.swift */,
BF04E6FE1DB8625C000F35D3 /* ControllerSkinsViewController.swift */,
BF99A5961DC2F9C400468E9E /* ControllerSkinTableViewCell.swift */,
);
name = "Controller Skins";
sourceTree = "<group>";
@ -441,6 +451,8 @@
children = (
BFA2315B1CED10BE0011E35A /* Action.swift */,
BF0CDDAC1C8155D200640168 /* LoadImageOperation.swift */,
BF4F562A1DC3C6AF00267E32 /* LoadImageURLOperation.swift */,
BF23C4941DC3CB2E00849B3E /* LoadControllerSkinImageOperation.swift */,
);
name = Components;
sourceTree = "<group>";
@ -529,13 +541,13 @@
buildConfigurationList = BFFA71F61AAC406100EE9DD1 /* Build configuration list for PBXNativeTarget "Delta" */;
buildPhases = (
A5AEDE02D1134013AEC5BCB6 /* Check Pods Manifest.lock */,
BF28980A1DAAFB0F0023D8E9 /* mogenerator */,
BFFA71D31AAC406100EE9DD1 /* Sources */,
BFFA71D41AAC406100EE9DD1 /* Frameworks */,
BFFA71D51AAC406100EE9DD1 /* Resources */,
BF9F4FCC1AAD7AEE004C9500 /* Embed Frameworks */,
AA90DB8D72559A44728B98F0 /* Copy Pods Resources */,
AEE0EDDF2E4AAD91E135FE80 /* Embed Pods Frameworks */,
BF28980A1DAAFB0F0023D8E9 /* mogenerator */,
);
buildRules = (
);
@ -684,6 +696,7 @@
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */,
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
BF2898241DAAFD720023D8E9 /* _SaveState.swift in Sources */,
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */,
BF7AE81E1C2E984300B1B5BC /* GridCollectionViewCell.swift in Sources */,
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
BF1DAD5D1D9F576000E752A7 /* GameTypeControllerSkinsViewController.swift in Sources */,
@ -700,6 +713,7 @@
BFFC464C1D5998D600AF2CC6 /* CheatTableViewCell.swift in Sources */,
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */,
BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */,
BFACD5FD1DC3D2CE002D6DDC /* LoadControllerSkinImageOperation.swift in Sources */,
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */,
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */,
BF3540021C5DA3D500C1184C /* PauseStoryboardSegue.swift in Sources */,
@ -717,7 +731,9 @@
BF2898161DAAFC2A0023D8E9 /* Game.swift in Sources */,
BF1173501DA32CF600047DF8 /* ControllersSettingsViewController.swift in Sources */,
BFFC461E1D59823500AF2CC6 /* GamesPresentationController.swift in Sources */,
BF99A5971DC2F9C400468E9E /* ControllerSkinTableViewCell.swift in Sources */,
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */,
BF4F562B1DC3C6AF00267E32 /* LoadImageURLOperation.swift in Sources */,
BF2898231DAAFD720023D8E9 /* _GameCollection.swift in Sources */,
BF353FF21C5D7FB000C1184C /* PauseViewController.swift in Sources */,
BFDB28451BC9DA7B001D0C83 /* ImportController.swift in Sources */,

View File

@ -242,7 +242,7 @@ private extension SaveStatesViewController
if !ignoreOperations
{
let imageOperation = LoadImageOperation(URL: saveState.imageFileURL)
let imageOperation = LoadImageURLOperation(url: saveState.imageFileURL)
imageOperation.imageCache = self.imageCache
imageOperation.completionHandler = { image in

View File

@ -0,0 +1,26 @@
//
// ControllerSkinTableViewCell.swift
// Delta
//
// Created by Riley Testut on 10/27/16.
// Copyright © 2016 Riley Testut. All rights reserved.
//
import UIKit
class ControllerSkinTableViewCell: UITableViewCell
{
@IBOutlet var controllerSkinImageView: UIImageView!
@IBOutlet var activityIndicatorView: UIActivityIndicatorView!
override func awakeFromNib()
{
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
}

View File

@ -0,0 +1,199 @@
//
// ControllerSkinsViewController.swift
// Delta
//
// Created by Riley Testut on 10/19/16.
// Copyright © 2016 Riley Testut. All rights reserved.
//
import UIKit
import DeltaCore
import Roxas
extension ControllerSkinsViewController
{
enum Section: Int
{
case standard
case custom
}
}
class ControllerSkinsViewController: UITableViewController
{
var gameType: GameType! {
didSet {
self.updateDataSource()
}
}
var traits: DeltaCore.ControllerSkin.Traits! {
didSet {
self.updateDataSource()
}
}
fileprivate var dataSource: RSTFetchedResultsTableViewDataSource<ControllerSkin>!
fileprivate let imageOperationQueue = RSTOperationQueue()
fileprivate let imageCache = NSCache<ControllerSkinImageCacheKey, UIImage>()
}
extension ControllerSkinsViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool)
{
self.dataSource.fetchedResultsController.performFetchIfNeeded()
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
private extension ControllerSkinsViewController
{
//MARK: - Update
func updateDataSource()
{
guard let gameType = self.gameType, let traits = self.traits else { return }
let configuration = ControllerSkinConfigurations(traits: traits)
let fetchRequest: NSFetchRequest<ControllerSkin> = ControllerSkin.fetchRequest()
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.cellIdentifierHandler = { _ in RSTGenericCellIdentifier }
self.dataSource.cellConfigurationHandler = { [unowned self] (cell, indexPath) in
self.configure(cell as! ControllerSkinTableViewCell, for: indexPath)
}
}
//MARK: - Configure Cells
func configure(_ cell: ControllerSkinTableViewCell, for indexPath: IndexPath)
{
let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath)
cell.controllerSkinImageView.image = nil
cell.activityIndicatorView.startAnimating()
let size = UIScreen.main.defaultControllerSkinSize
let imageOperation = LoadControllerSkinImageOperation(controllerSkin: controllerSkin, traits: self.traits, size: size)
imageOperation.imageCache = self.imageCache
imageOperation.completionHandler = { image in
guard let image = image else { return }
if !imageOperation.isImmediate
{
UIView.transition(with: cell.controllerSkinImageView, duration: 0.2, options: .transitionCrossDissolve, animations: {
cell.controllerSkinImageView.image = image
}, completion: nil)
}
else
{
cell.controllerSkinImageView.image = image
}
cell.activityIndicatorView.stopAnimating()
}
// Ensure initially visible cells have loaded their image before they appear to prevent potential flickering from placeholder to thumbnail
if self.isAppearing
{
imageOperation.isImmediate = true
}
self.imageOperationQueue.addOperation(imageOperation, forKey: indexPath as NSCopying)
}
}
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))
return controllerSkin.name
}
}
extension ControllerSkinsViewController: UITableViewDataSourcePrefetching
{
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
{
for indexPath in indexPaths
{
let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath)
let size = UIScreen.main.defaultControllerSkinSize
let imageOperation = LoadControllerSkinImageOperation(controllerSkin: controllerSkin, traits: self.traits, size: size)
imageOperation.imageCache = self.imageCache
self.imageOperationQueue.addOperation(imageOperation, forKey: indexPath as NSCopying)
}
}
func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath])
{
for indexPath in indexPaths
{
let operation = self.imageOperationQueue[indexPath as NSCopying]
operation?.cancel()
}
}
}
extension ControllerSkinsViewController
{
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath)
guard let size = controllerSkin.aspectRatio(for: self.traits) else { return 150 }
let scale = (self.view.bounds.width / size.width)
let height = size.height * scale
return height
}
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
let operation = self.imageOperationQueue[indexPath as NSCopying]
operation?.cancel()
}
}

View File

@ -47,6 +47,25 @@ extension GameTypeControllerSkinsViewController
{
super.didReceiveMemoryWarning()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard let cell = sender as? UITableViewCell, let indexPath = self.tableView.indexPath(for: cell) else { return }
let controllerSkinsViewController = segue.destination as! ControllerSkinsViewController
controllerSkinsViewController.gameType = self.gameType
var traits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
let section = Section(rawValue: indexPath.section)!
switch section
{
case .portrait: traits.orientation = .portrait
case .landscape: traits.orientation = .landscape
}
controllerSkinsViewController.traits = traits
}
}
extension GameTypeControllerSkinsViewController
@ -70,6 +89,13 @@ extension GameTypeControllerSkinsViewController
let height = unwrappedImageSize.height * scale
return height
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
guard let cell = tableView.cellForRow(at: indexPath) else { return }
self.performSegue(withIdentifier: "showControllerSkins", sender: cell)
}
}
private extension GameTypeControllerSkinsViewController

View File

@ -1,8 +1,11 @@
<?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="ssH-mM-uG6">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="ssH-mM-uG6">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -18,21 +21,21 @@
<tableViewSection headerTitle="Inputs" id="c6K-sJ-0vW">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="tls-Hv-Rx2" detailTextLabel="vJP-Ie-a9H" style="IBUITableViewCellStyleValue1" id="jvV-ZB-Rq1">
<rect key="frame" x="0.0" y="119.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jvV-ZB-Rq1" id="AVi-6C-eIS">
<frame key="frameInset" width="342" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Player 1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="tls-Hv-Rx2">
<frame key="frameInset" minX="15" minY="12" width="56" height="19.5"/>
<rect key="frame" x="15" y="12" width="56" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Riley's iPhone" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="vJP-Ie-a9H">
<frame key="frameInset" minX="239.5" minY="12" width="100.5" height="19.5"/>
<rect key="frame" x="239.5" y="12" width="100.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -42,21 +45,21 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="e3u-x9-IEC" detailTextLabel="2OP-A1-VYo" style="IBUITableViewCellStyleValue1" id="1Fv-H5-0oH">
<rect key="frame" x="0.0" y="163.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="1Fv-H5-0oH" id="kFJ-zK-MLZ">
<frame key="frameInset" width="342" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Player 2" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e3u-x9-IEC">
<frame key="frameInset" minX="15" minY="12" width="58" height="19.5"/>
<rect key="frame" x="15" y="12" width="58" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="SteelSeries Stratus" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="2OP-A1-VYo">
<frame key="frameInset" minX="201.5" minY="12" width="138.5" height="19.5"/>
<rect key="frame" x="201.5" y="12" width="138.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -66,21 +69,21 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Cdn-11-xZe" detailTextLabel="wWc-NY-Bsd" style="IBUITableViewCellStyleValue1" id="EcC-Be-jV5">
<rect key="frame" x="0.0" y="207.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="EcC-Be-jV5" id="9ZS-um-scR">
<frame key="frameInset" width="342" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Player 3" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Cdn-11-xZe">
<frame key="frameInset" minX="15" minY="12" width="58.5" height="19.5"/>
<rect key="frame" x="15" y="12" width="58.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="MOGA Gamepad" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="wWc-NY-Bsd">
<frame key="frameInset" minX="218" minY="12" width="122" height="19.5"/>
<rect key="frame" x="218" y="12" width="122" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -90,21 +93,21 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Hls-3b-EaS" detailTextLabel="hNf-uc-PLR" style="IBUITableViewCellStyleValue1" id="hO9-Ov-vsA">
<rect key="frame" x="0.0" y="251.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="187.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hO9-Ov-vsA" id="MRi-re-XI7">
<frame key="frameInset" width="342" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Player 4" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Hls-3b-EaS">
<frame key="frameInset" minX="15" minY="12" width="59" height="19.5"/>
<rect key="frame" x="15" y="12" width="59" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Jayce's iPhone" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hNf-uc-PLR">
<frame key="frameInset" minX="232" minY="12" width="108" height="19.5"/>
<rect key="frame" x="232" y="12" width="108" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -118,14 +121,14 @@
<tableViewSection headerTitle="Controller Skins" id="Nch-k1-6pR">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="mBC-YU-BVK" style="IBUITableViewCellStyleDefault" id="ICf-ug-NwS">
<rect key="frame" x="0.0" y="351.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="287.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ICf-ug-NwS" id="7se-sE-x9e">
<frame key="frameInset" width="342" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Super Nintendo" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mBC-YU-BVK">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<rect key="frame" x="15" y="0.0" width="325" height="43.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -135,14 +138,14 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="MFD-lC-Vfk" style="IBUITableViewCellStyleDefault" id="4Sh-Mb-vqu">
<rect key="frame" x="0.0" y="395.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="331.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4Sh-Mb-vqu" id="cJG-Gr-n6q">
<frame key="frameInset" width="342" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Game Boy Advance" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="MFD-lC-Vfk">
<frame key="frameInset" minX="15" width="325" height="43.5"/>
<rect key="frame" x="15" y="0.0" width="325" height="43.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -186,21 +189,21 @@
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="VBO-V1-Wfu" detailTextLabel="tqn-1q-p53" style="IBUITableViewCellStyleValue1" id="lzU-uS-el2">
<rect key="frame" x="0.0" y="119.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="lzU-uS-el2" id="o56-OW-cxE">
<frame key="frameInset" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Controller Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="VBO-V1-Wfu">
<frame key="frameInset" minX="15" minY="12" width="118.5" height="19.5"/>
<rect key="frame" x="15" y="12" width="118.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Player 1" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="tqn-1q-p53">
<frame key="frameInset" minX="304" minY="12" width="56" height="19.5"/>
<rect key="frame" x="304" y="12" width="56" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -238,13 +241,15 @@
<tableViewSection headerTitle="Portrait" id="jGW-i7-nK1">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="8Vp-a7-RvI">
<rect key="frame" x="0.0" y="120" width="375" height="44"/>
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8Vp-a7-RvI" id="KCG-fx-fax">
<frame key="frameInset" width="375" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="5r7-OQ-i7w"/>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="5r7-OQ-i7w">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="5r7-OQ-i7w" firstAttribute="top" secondItem="KCG-fx-fax" secondAttribute="top" id="2uo-BN-g4M"/>
@ -259,13 +264,15 @@
<tableViewSection headerTitle="Landscape" id="PqP-JS-vGE">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="HaE-e5-fux">
<rect key="frame" x="0.0" y="221" width="375" height="44"/>
<rect key="frame" x="0.0" y="155.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="HaE-e5-fux" id="XwS-Kw-Fe6">
<frame key="frameInset" width="375" height="43"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="XY1-es-oZe"/>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="XY1-es-oZe">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="XY1-es-oZe" firstAttribute="top" secondItem="XwS-Kw-Fe6" secondAttribute="top" id="BLb-gp-vUV"/>
@ -287,12 +294,61 @@
<connections>
<outlet property="landscapeImageView" destination="XY1-es-oZe" id="d6S-ez-jh2"/>
<outlet property="portraitImageView" destination="5r7-OQ-i7w" id="C5r-uX-SlN"/>
<segue destination="pG9-hI-tRE" kind="show" identifier="showControllerSkins" id="kiq-86-5B7"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Nx1-Ly-oRu" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2220" y="1181.5592203898052"/>
</scene>
<!--Controller Skins-->
<scene sceneID="IN0-an-SWm">
<objects>
<tableViewController title="Controller Skins" id="pG9-hI-tRE" customClass="ControllerSkinsViewController" customModule="Delta" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="150" sectionHeaderHeight="18" sectionFooterHeight="18" id="WiB-mC-9xS">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="kK3-bl-qxv" customClass="ControllerSkinTableViewCell" customModule="Delta" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="150"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="kK3-bl-qxv" id="7Vt-Nl-Sfx">
<rect key="frame" x="0.0" y="0.0" width="375" height="149.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="o9T-qo-UoF">
<rect key="frame" x="177.5" y="65" width="20" height="20"/>
</activityIndicatorView>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zbw-fi-eau">
<rect key="frame" x="0.0" y="0.0" width="375" height="149.5"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="zbw-fi-eau" firstAttribute="top" secondItem="7Vt-Nl-Sfx" secondAttribute="top" id="1KW-et-nu2"/>
<constraint firstAttribute="trailing" secondItem="zbw-fi-eau" secondAttribute="trailing" id="51I-HE-J4C"/>
<constraint firstAttribute="bottom" secondItem="zbw-fi-eau" secondAttribute="bottom" id="ZpW-sc-XRY"/>
<constraint firstItem="o9T-qo-UoF" firstAttribute="centerX" secondItem="7Vt-Nl-Sfx" secondAttribute="centerX" id="rmp-c3-xsc"/>
<constraint firstItem="o9T-qo-UoF" firstAttribute="centerY" secondItem="7Vt-Nl-Sfx" secondAttribute="centerY" id="y0I-Bf-s60"/>
<constraint firstItem="zbw-fi-eau" firstAttribute="leading" secondItem="7Vt-Nl-Sfx" secondAttribute="leading" id="zQU-50-6Od"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="activityIndicatorView" destination="o9T-qo-UoF" id="dZl-54-Q22"/>
<outlet property="controllerSkinImageView" destination="zbw-fi-eau" id="VXC-1B-ZLE"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="pG9-hI-tRE" id="FkO-on-Ylv"/>
<outlet property="delegate" destination="pG9-hI-tRE" id="8NO-ha-J5E"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="54U-JB-wBG" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2976.8000000000002" y="1181.5592203898052"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="8qd-VB-Uy5">
<objects>

2
External/Roxas vendored

@ -1 +1 @@
Subproject commit e334730200712202feb470f1525c7eea30542146
Subproject commit 687755f0b3ad425e9f0ffb36b3310f24bf72ce02