Merge branch 'feature/iphone_x' into develop

This commit is contained in:
Riley Testut 2017-12-19 01:55:22 -06:00
commit d30f4db894
17 changed files with 149 additions and 148 deletions

@ -1 +1 @@
Subproject commit d7213260852683ea5a3f6c2274733bbd65d2ec92
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>
@ -200,7 +200,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"/>
@ -387,7 +387,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>
@ -410,7 +410,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

@ -23,22 +23,52 @@ class GridCollectionViewLayout: UICollectionViewFlowLayout
// If only one row, distribute the items equally horizontally
var usesEqualHorizontalSpacingDistributionForSingleRow = false
private var contentInset: UIEdgeInsets {
guard let collectionView = self.collectionView else { return .zero }
var contentInset = collectionView.contentInset
if #available(iOS 11, *)
{
contentInset.left += collectionView.safeAreaInsets.left
contentInset.right += collectionView.safeAreaInsets.right
}
return contentInset
}
private var contentWidth: CGFloat {
guard let collectionView = self.collectionView else { return 0.0 }
let contentWidth = collectionView.bounds.width - (self.contentInset.left + self.contentInset.right)
return contentWidth
}
private var maximumItemsPerRow: Int {
let maximumItemsPerRow = Int(floor((self.contentWidth - self.minimumInteritemSpacing) / (self.itemWidth + self.minimumInteritemSpacing)))
return maximumItemsPerRow
}
private var interitemSpacing: CGFloat {
let interitemSpacing = (self.contentWidth - CGFloat(self.maximumItemsPerRow) * self.itemWidth) / CGFloat(self.maximumItemsPerRow + 1)
return interitemSpacing
}
override var estimatedItemSize: CGSize {
didSet {
fatalError("GridCollectionViewLayout does not support self-sizing cells.")
}
}
override func prepare()
{
super.prepare()
self.sectionInset.left = self.interitemSpacing + self.contentInset.left
self.sectionInset.right = self.interitemSpacing + self.contentInset.right
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
guard let collectionView = self.collectionView else { return nil }
let maximumItemsPerRow = floor((collectionView.bounds.width - self.minimumInteritemSpacing) / (self.itemWidth + self.minimumInteritemSpacing))
let interitemSpacing = (collectionView.bounds.width - maximumItemsPerRow * self.itemWidth) / (maximumItemsPerRow + 1)
self.sectionInset.left = interitemSpacing
self.sectionInset.right = interitemSpacing
let layoutAttributes = super.layoutAttributesForElements(in: rect)?.map({ $0.copy() }) as! [UICollectionViewLayoutAttributes]
var minimumY: CGFloat? = nil
@ -58,7 +88,7 @@ class GridCollectionViewLayout: UICollectionViewFlowLayout
if abs(attributes.frame.minX - self.sectionInset.left) > 1
{
attributes.frame.origin.x = previousLayoutAttributes.frame.maxX + interitemSpacing
attributes.frame.origin.x = previousLayoutAttributes.frame.maxX + self.interitemSpacing
}
}
@ -70,7 +100,7 @@ class GridCollectionViewLayout: UICollectionViewFlowLayout
{
isSingleRow = false
self.alignLayoutAttributes(tempLayoutAttributes, toMinimumY: minY)
self.align(tempLayoutAttributes, toMinimumY: minY)
// Reset tempLayoutAttributes
tempLayoutAttributes.removeAll()
@ -97,15 +127,15 @@ class GridCollectionViewLayout: UICollectionViewFlowLayout
// Handle the remaining tempLayoutAttributes
if let minimumY = minimumY
{
self.alignLayoutAttributes(tempLayoutAttributes, toMinimumY: minimumY)
self.align(tempLayoutAttributes, toMinimumY: minimumY)
if isSingleRow && self.usesEqualHorizontalSpacingDistributionForSingleRow
{
let spacing = (collectionView.bounds.width - (self.itemWidth * CGFloat(tempLayoutAttributes.count))) / (CGFloat(tempLayoutAttributes.count) + 1.0)
let spacing = (self.contentWidth - (self.itemWidth * CGFloat(tempLayoutAttributes.count))) / (CGFloat(tempLayoutAttributes.count) + 1.0)
for (index, layoutAttributes) in tempLayoutAttributes.enumerated()
{
layoutAttributes.frame.origin.x = spacing + (spacing + self.itemWidth) * CGFloat(index)
layoutAttributes.frame.origin.x = spacing + (spacing + self.itemWidth) * CGFloat(index) + self.contentInset.left
}
}
}
@ -117,7 +147,7 @@ class GridCollectionViewLayout: UICollectionViewFlowLayout
private extension GridCollectionViewLayout
{
func alignLayoutAttributes(_ layoutAttributes: [UICollectionViewLayoutAttributes], toMinimumY minimumY: CGFloat)
func align(_ layoutAttributes: [UICollectionViewLayoutAttributes], toMinimumY minimumY: CGFloat)
{
for attributes in layoutAttributes
{

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

@ -192,6 +192,8 @@ extension GameViewController
let gameViewContainerView = self.gameView.superview!
self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity
self.sustainButtonsContentView = UIView(frame: CGRect(x: 0, y: 0, width: self.gameView.bounds.width, height: self.gameView.bounds.height))
self.sustainButtonsContentView.translatesAutoresizingMaskIntoConstraints = false
self.sustainButtonsContentView.isHidden = true
@ -438,21 +440,12 @@ 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
if controllerSkin?.isTranslucent(for: traits) ?? false
{
self.controllerView.alpha = Settings.translucentControllerSkinOpacity
}
else
{
self.controllerView.alpha = 1.0
}
}
}
@ -853,21 +846,13 @@ 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()
}
case .translucentControllerSkinOpacity:
if let traits = self.controllerView.controllerSkinTraits
{
if self.controllerView.controllerSkin?.isTranslucent(for: traits) ?? false
{
self.controllerView.alpha = Settings.translucentControllerSkinOpacity
}
}
case .translucentControllerSkinOpacity: self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity
}
}
}

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

@ -23,6 +23,10 @@ class LaunchViewController: UIViewController
return self.gameViewController?.prefersStatusBarHidden ?? false
}
override func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController? {
return self.gameViewController
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)

View File

@ -33,7 +33,7 @@ class PausePresentationController: UIPresentationController
{
guard let containerView = self.containerView else { return super.frameOfPresentedViewInContainerView }
let frame: CGRect
var frame: CGRect
let contentHeight = self.presentedViewController.preferredContentSize.height
if contentHeight == 0
@ -44,6 +44,11 @@ class PausePresentationController: UIPresentationController
else
{
frame = CGRect(x: 0, y: containerView.bounds.height - contentHeight, width: containerView.bounds.width, height: containerView.bounds.height)
if #available(iOS 11.0, *)
{
frame.origin.y -= containerView.safeAreaInsets.bottom
}
}
return frame

View File

@ -101,7 +101,7 @@ extension SaveStatesViewController
// Use dimensions that allow two cells to fill the screen horizontally with padding in portrait mode
// We'll keep the same size for landscape orientation, which will allow more to fit
collectionViewLayout.itemWidth = (portraitScreenWidth - (averageHorizontalInset * 3)) / 2
collectionViewLayout.itemWidth = floor((portraitScreenWidth - (averageHorizontalInset * 3)) / 2)
switch self.mode
{

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
}
}