Adds support for iPhone X-optimized controller skins

This commit is contained in:
Riley Testut 2017-12-18 19:36:56 -06:00
parent 6836fb5bae
commit 18d6bd262a
13 changed files with 91 additions and 115 deletions

@ -1 +1 @@
Subproject commit 0102a815adf25da3841d4273c044cbb59261709b
Subproject commit 6658b7a7557278c9b846466a0599462c1aeb870b

@ -1 +1 @@
Subproject commit 7babfcf93a32916ad06989c9a63681acf7f07d50
Subproject commit 54d064d34a4d856fd34a49308f42f1aefac8eaad

@ -1 +1 @@
Subproject commit 9d714254ace7bd5d63805d434f4ccd1f2a947951
Subproject commit 9c295a2a287821544fec4b29d2b3f1205f965275

@ -1 +1 @@
Subproject commit a354c3700fc4576bbefb6a8324bcd7a121d9b934
Subproject commit a3f0547bc57c14b548105020136a9ead56f73470

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13528" 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="13771" 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="13526"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -193,7 +193,7 @@
<action selector="didFinishChangingControllerOpacityWith:" destination="eHi-aO-uGS" eventType="touchUpOutside" id="xBn-FJ-5S0"/>
</connections>
</slider>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="50%" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zaz-yD-CYG">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="50%" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zaz-yD-CYG">
<rect key="frame" x="16" y="11" width="46" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="ACD-qY-k0J"/>
@ -379,7 +379,7 @@
<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="scaleAspectFit" 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>
@ -402,7 +402,7 @@
<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="scaleAspectFit" 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>

View File

@ -65,12 +65,12 @@ class LoadControllerSkinImageOperation: RSTLoadOperation<UIImage, ControllerSkin
override func loadResult(completion: @escaping (UIImage?, Swift.Error?) -> Void)
{
guard self.controllerSkin.supports(self.traits) else {
guard let traits = self.controllerSkin.supportedTraits(for: self.traits) else {
completion(nil, Error.unsupportedTraits)
return
}
guard let image = self.controllerSkin.image(for: self.traits, preferredSize: self.size) else {
guard let image = self.controllerSkin.image(for: traits, preferredSize: self.size) else {
completion(nil, Error.doesNotExist)
return
}

View File

@ -14,37 +14,14 @@ extension ControllerSkinConfigurations
{
init(traits: DeltaCore.ControllerSkin.Traits)
{
switch traits.deviceType
switch (traits.displayType, traits.orientation)
{
case .iphone:
switch traits.orientation
{
case .portrait: self = .fullScreenPortrait
case .landscape: self = .fullScreenLandscape
}
case .ipad:
switch traits.displayMode
{
case .fullScreen:
switch traits.orientation
{
case .portrait: self = .fullScreenPortrait
case .landscape: self = .fullScreenLandscape
}
case .splitView:
switch traits.orientation
{
case .portrait: self = .splitViewPortrait
case .landscape: self = .splitViewLandscape
}
}
case (.standard, .portrait): self = .standardPortrait
case (.standard, .landscape): self = .standardLandscape
case (.edgeToEdge, .portrait): self = .edgeToEdgePortrait
case (.edgeToEdge, .landscape): self = .edgeToEdgeLandscape
case (.splitView, .portrait): self = .splitViewPortrait
case (.splitView, .landscape): self = .splitViewLandscape
}
}
}

View File

@ -11,11 +11,14 @@
typedef NS_OPTIONS(int16_t, ControllerSkinConfigurations)
{
ControllerSkinConfigurationFullScreenPortrait = 1 << 0,
ControllerSkinConfigurationFullScreenLandscape = 1 << 1,
ControllerSkinConfigurationStandardPortrait = 1 << 0,
ControllerSkinConfigurationStandardLandscape = 1 << 1,
ControllerSkinConfigurationSplitViewPortrait = 1 << 2,
ControllerSkinConfigurationSplitViewLandscape = 1 << 3,
ControllerSkinConfigurationEdgeToEdgePortrait = 1 << 4,
ControllerSkinConfigurationEdgeToEdgeLandscape = 1 << 5,
};
#endif /* ControllerSkinConfigurations_h */

View File

@ -440,9 +440,9 @@ private extension GameViewController
func updateControllerSkin()
{
guard let game = self.game, let system = System(gameType: game.type) else { return }
guard let game = self.game, let system = System(gameType: game.type), let window = self.view.window else { return }
let traits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
let traits = DeltaCore.ControllerSkin.Traits.defaults(for: window)
let controllerSkin = Settings.preferredControllerSkin(for: system, traits: traits)
self.controllerView.controllerSkin = controllerSkin
@ -846,9 +846,8 @@ private extension GameViewController
let system = notification.userInfo?[Settings.NotificationUserInfoKey.system] as? System,
let traits = notification.userInfo?[Settings.NotificationUserInfoKey.traits] as? DeltaCore.ControllerSkin.Traits
else { return }
let currentTraits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
if system.gameType == self.game?.type && traits == currentTraits
if system.gameType == self.game?.type && traits.orientation == self.controllerView.controllerSkinTraits?.orientation
{
self.updateControllerSkin()
}

View File

@ -20,54 +20,18 @@ extension ControllerSkin
var configurations = ControllerSkinConfigurations()
if UIDevice.current.userInterfaceIdiom == .pad
let device: DeltaCore.ControllerSkin.Device = (UIDevice.current.userInterfaceIdiom == .pad) ? .ipad : .iphone
let traitCollections: [(displayType: DeltaCore.ControllerSkin.DisplayType, orientation: DeltaCore.ControllerSkin.Orientation)] =
[(.standard, .portrait), (.standard, .landscape), (.edgeToEdge, .portrait), (.edgeToEdge, .landscape), (.splitView, .portrait), (.splitView, .landscape)]
for collection in traitCollections
{
var portraitTraits = DeltaCore.ControllerSkin.Traits(deviceType: .ipad, displayMode: .fullScreen, orientation: .portrait)
var landscapeTraits = portraitTraits
landscapeTraits.orientation = .landscape
if skin.supports(portraitTraits)
let traits = DeltaCore.ControllerSkin.Traits(device: device, displayType: collection.displayType, orientation: collection.orientation)
if skin.supports(traits)
{
configurations.formUnion(.fullScreenPortrait)
}
if skin.supports(landscapeTraits)
{
configurations.formUnion(.fullScreenLandscape)
}
portraitTraits.displayMode = .splitView
landscapeTraits.displayMode = .splitView
if skin.supports(portraitTraits)
{
configurations.formUnion(.splitViewPortrait)
}
if skin.supports(landscapeTraits)
{
configurations.formUnion(.splitViewLandscape)
}
}
else
{
let portraitTraits = DeltaCore.ControllerSkin.Traits(deviceType: .iphone, displayMode: .fullScreen, orientation: .portrait)
var landscapeTraits = portraitTraits
landscapeTraits.orientation = .landscape
if skin.supports(portraitTraits)
{
configurations.formUnion(.fullScreenPortrait)
}
if skin.supports(landscapeTraits)
{
configurations.formUnion(.fullScreenLandscape)
let configuration = ControllerSkinConfigurations(traits: traits)
configurations.formUnion(configuration)
}
}

View File

@ -100,7 +100,24 @@ private extension ControllerSkinsViewController
let configuration = ControllerSkinConfigurations(traits: traits)
let fetchRequest: NSFetchRequest<ControllerSkin> = ControllerSkin.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND (%K & %d) == %d", #keyPath(ControllerSkin.gameType), system.gameType.rawValue, #keyPath(ControllerSkin.supportedConfigurations), configuration.rawValue, configuration.rawValue)
if traits.device == .iphone && traits.displayType == .edgeToEdge
{
let fallbackConfiguration: ControllerSkinConfigurations = (traits.orientation == .landscape) ? .standardLandscape : .standardPortrait
// Allow selecting skins that only support standard display types as well.
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND ((%K & %d) != 0 OR (%K & %d) != 0)",
#keyPath(ControllerSkin.gameType), system.gameType.rawValue,
#keyPath(ControllerSkin.supportedConfigurations), configuration.rawValue,
#keyPath(ControllerSkin.supportedConfigurations), fallbackConfiguration.rawValue)
}
else
{
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND (%K & %d) != 0",
#keyPath(ControllerSkin.gameType), system.gameType.rawValue,
#keyPath(ControllerSkin.supportedConfigurations), configuration.rawValue)
}
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(ControllerSkin.isStandard), ascending: false), NSSortDescriptor(key: #keyPath(ControllerSkin.name), ascending: true)]
self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(ControllerSkin.name), cacheName: nil)
@ -130,11 +147,11 @@ extension ControllerSkinsViewController
{
let controllerSkin = self.dataSource.item(at: indexPath)
guard let size = controllerSkin.aspectRatio(for: self.traits) else { return 150 }
guard let traits = controllerSkin.supportedTraits(for: self.traits), let size = controllerSkin.aspectRatio(for: traits) else { return 150 }
let scale = (self.view.bounds.width / size.width)
let height = size.height * scale
let height = min(size.height * scale, self.view.bounds.height - self.topLayoutGuide.length - self.bottomLayoutGuide.length - 30)
return height
}

View File

@ -25,6 +25,8 @@ class SystemControllerSkinsViewController: UITableViewController
@IBOutlet private var portraitImageView: UIImageView!
@IBOutlet private var landscapeImageView: UIImageView!
private var _previousBoundsSize: CGSize?
}
extension SystemControllerSkinsViewController
@ -35,27 +37,31 @@ extension SystemControllerSkinsViewController
self.title = self.system.localizedShortName
}
override func viewWillAppear(_ animated: Bool)
{
self.updateControllerSkins()
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
if self.view.bounds.size != self._previousBoundsSize
{
self.updateControllerSkins()
self.tableView.reloadData()
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard let cell = sender as? UITableViewCell, let indexPath = self.tableView.indexPath(for: cell) else { return }
guard let cell = sender as? UITableViewCell, let indexPath = self.tableView.indexPath(for: cell), let window = self.view.window else { return }
let controllerSkinsViewController = segue.destination as! ControllerSkinsViewController
controllerSkinsViewController.system = self.system
var traits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
var traits = DeltaCore.ControllerSkin.Traits.defaults(for: window)
let section = Section(rawValue: indexPath.section)!
switch section
@ -86,7 +92,7 @@ extension SystemControllerSkinsViewController
let scale = (self.view.bounds.width / unwrappedImageSize.width)
let height = unwrappedImageSize.height * scale
let height = min(unwrappedImageSize.height * scale, self.view.bounds.height - self.topLayoutGuide.length - self.bottomLayoutGuide.length - 30)
return height
}
@ -102,8 +108,17 @@ private extension SystemControllerSkinsViewController
{
func updateControllerSkins()
{
let portraitTraits = DeltaCore.ControllerSkin.Traits(deviceType: .iphone, displayMode: DeltaCore.ControllerSkin.DisplayMode.fullScreen, orientation: .portrait)
let landscapeTraits = DeltaCore.ControllerSkin.Traits(deviceType: .iphone, displayMode: DeltaCore.ControllerSkin.DisplayMode.fullScreen, orientation: .landscape)
guard let window = self.view.window else { return }
self._previousBoundsSize = self.view.bounds.size
let defaultTraits = DeltaCore.ControllerSkin.Traits.defaults(for: window)
var portraitTraits = defaultTraits
portraitTraits.orientation = .portrait
var landscapeTraits = defaultTraits
landscapeTraits.orientation = .landscape
let portraitControllerSkin = Settings.preferredControllerSkin(for: self.system, traits: portraitTraits)
let landscapeControllerSkin = Settings.preferredControllerSkin(for: self.system, traits: landscapeTraits)

View File

@ -145,15 +145,16 @@ private extension Settings
case .landscape: orientation = "landscape"
}
let displayMode: String
let displayType: String
switch traits.displayMode
switch traits.displayType
{
case .fullScreen: displayMode = "fullscreen"
case .splitView: displayMode = "splitview"
case .standard: displayType = "standard"
case .edgeToEdge: displayType = "standard" // In this context, standard and edge-to-edge skins are treated the same.
case .splitView: displayType = "splitview"
}
let key = systemName + "-" + orientation + "-" + displayMode + "-controller"
let key = systemName + "-" + orientation + "-" + displayType + "-controller"
return key
}
}