Adds support for iPhone X-optimized controller skins
This commit is contained in:
parent
6836fb5bae
commit
18d6bd262a
@ -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
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user