Adds support for 3D Touch app icon game shortcuts
This commit is contained in:
parent
2e36b8125e
commit
a9c3e85df8
@ -1 +1 @@
|
|||||||
Subproject commit 6658b7a7557278c9b846466a0599462c1aeb870b
|
Subproject commit 4947d10713ba31017e40df275f40a315cf0da897
|
||||||
@ -49,6 +49,8 @@
|
|||||||
BF4828841F9027B600028B97 /* Delta.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = BF4828811F9027B600028B97 /* Delta.xcdatamodeld */; };
|
BF4828841F9027B600028B97 /* Delta.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = BF4828811F9027B600028B97 /* Delta.xcdatamodeld */; };
|
||||||
BF4828861F9028F500028B97 /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4828851F9028F500028B97 /* System.swift */; };
|
BF4828861F9028F500028B97 /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4828851F9028F500028B97 /* System.swift */; };
|
||||||
BF4828881F90290F00028B97 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4828871F90290F00028B97 /* Action.swift */; };
|
BF4828881F90290F00028B97 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4828871F90290F00028B97 /* Action.swift */; };
|
||||||
|
BF525EE81FF5F370004AA849 /* DeepLinkController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF525EE71FF5F370004AA849 /* DeepLinkController.swift */; };
|
||||||
|
BF525EEA1FF6CD12004AA849 /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF525EE91FF6CD12004AA849 /* DeepLink.swift */; };
|
||||||
BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942611E09BBB10051894B /* LoadControllerSkinImageOperation.swift */; };
|
BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942611E09BBB10051894B /* LoadControllerSkinImageOperation.swift */; };
|
||||||
BF5942661E09BBB10051894B /* LoadImageURLOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942631E09BBB10051894B /* LoadImageURLOperation.swift */; };
|
BF5942661E09BBB10051894B /* LoadImageURLOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942631E09BBB10051894B /* LoadImageURLOperation.swift */; };
|
||||||
BF59426A1E09BBD00051894B /* GridCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942681E09BBD00051894B /* GridCollectionViewCell.swift */; };
|
BF59426A1E09BBD00051894B /* GridCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942681E09BBD00051894B /* GridCollectionViewCell.swift */; };
|
||||||
@ -85,6 +87,8 @@
|
|||||||
BF6EE5EB1F7C5F8F0051AD6C /* GameControllerInputMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6EE5EA1F7C5F8F0051AD6C /* GameControllerInputMapping.swift */; };
|
BF6EE5EB1F7C5F8F0051AD6C /* GameControllerInputMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6EE5EA1F7C5F8F0051AD6C /* GameControllerInputMapping.swift */; };
|
||||||
BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; };
|
BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; };
|
||||||
BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
BF71CF871FE90006001F1613 /* AppIconShortcutsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF71CF861FE90006001F1613 /* AppIconShortcutsViewController.swift */; };
|
||||||
|
BF71CF8A1FE904B1001F1613 /* GameTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF71CF891FE904B1001F1613 /* GameTableViewCell.xib */; };
|
||||||
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */; };
|
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */; };
|
||||||
BF7AE8081C2E858400B1B5BC /* GridMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8041C2E858400B1B5BC /* GridMenuViewController.swift */; };
|
BF7AE8081C2E858400B1B5BC /* GridMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8041C2E858400B1B5BC /* GridMenuViewController.swift */; };
|
||||||
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */; };
|
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */; };
|
||||||
@ -115,7 +119,7 @@
|
|||||||
BFF0742D1E9DC17500ACDF4A /* GBCDeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
BFF0742D1E9DC17500ACDF4A /* GBCDeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
BFF6452E1F7CC5060056533E /* GameControllerInputMappingTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6B82A41F7CC2A300042BFB /* GameControllerInputMappingTransformer.swift */; };
|
BFF6452E1F7CC5060056533E /* GameControllerInputMappingTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6B82A41F7CC2A300042BFB /* GameControllerInputMappingTransformer.swift */; };
|
||||||
BFF93AA01E0FB036005EC865 /* InputStreamOutputWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */; };
|
BFF93AA01E0FB036005EC865 /* InputStreamOutputWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */; };
|
||||||
BFFA4C091E8A24D600D87934 /* GameMetadataTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA4C081E8A24D600D87934 /* GameMetadataTableViewCell.swift */; };
|
BFFA4C091E8A24D600D87934 /* GameTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA4C081E8A24D600D87934 /* GameTableViewCell.swift */; };
|
||||||
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */; };
|
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */; };
|
||||||
BFFA71E21AAC406100EE9DD1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFFA71E01AAC406100EE9DD1 /* Main.storyboard */; };
|
BFFA71E21AAC406100EE9DD1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFFA71E01AAC406100EE9DD1 /* Main.storyboard */; };
|
||||||
BFFC461E1D59823500AF2CC6 /* GamesPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFC461B1D59823500AF2CC6 /* GamesPresentationController.swift */; };
|
BFFC461E1D59823500AF2CC6 /* GamesPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFC461B1D59823500AF2CC6 /* GamesPresentationController.swift */; };
|
||||||
@ -180,6 +184,8 @@
|
|||||||
BF4828831F9027B600028B97 /* Delta.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Delta.xcdatamodel; sourceTree = "<group>"; };
|
BF4828831F9027B600028B97 /* Delta.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Delta.xcdatamodel; sourceTree = "<group>"; };
|
||||||
BF4828851F9028F500028B97 /* System.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = System.swift; sourceTree = "<group>"; };
|
BF4828851F9028F500028B97 /* System.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = System.swift; sourceTree = "<group>"; };
|
||||||
BF4828871F90290F00028B97 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = "<group>"; };
|
BF4828871F90290F00028B97 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = "<group>"; };
|
||||||
|
BF525EE71FF5F370004AA849 /* DeepLinkController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkController.swift; sourceTree = "<group>"; };
|
||||||
|
BF525EE91FF6CD12004AA849 /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = "<group>"; };
|
||||||
BF5942611E09BBB10051894B /* LoadControllerSkinImageOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadControllerSkinImageOperation.swift; sourceTree = "<group>"; };
|
BF5942611E09BBB10051894B /* LoadControllerSkinImageOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadControllerSkinImageOperation.swift; sourceTree = "<group>"; };
|
||||||
BF5942631E09BBB10051894B /* LoadImageURLOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadImageURLOperation.swift; sourceTree = "<group>"; };
|
BF5942631E09BBB10051894B /* LoadImageURLOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadImageURLOperation.swift; sourceTree = "<group>"; };
|
||||||
BF5942681E09BBD00051894B /* GridCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridCollectionViewCell.swift; sourceTree = "<group>"; };
|
BF5942681E09BBD00051894B /* GridCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||||
@ -221,6 +227,8 @@
|
|||||||
BF6EE5E81F7C5F860051AD6C /* _GameControllerInputMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _GameControllerInputMapping.swift; sourceTree = "<group>"; };
|
BF6EE5E81F7C5F860051AD6C /* _GameControllerInputMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _GameControllerInputMapping.swift; sourceTree = "<group>"; };
|
||||||
BF6EE5EA1F7C5F8F0051AD6C /* GameControllerInputMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameControllerInputMapping.swift; sourceTree = "<group>"; };
|
BF6EE5EA1F7C5F8F0051AD6C /* GameControllerInputMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameControllerInputMapping.swift; sourceTree = "<group>"; };
|
||||||
BF70798B1B6B464B0019077C /* ZipZap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ZipZap.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
BF70798B1B6B464B0019077C /* ZipZap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ZipZap.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
BF71CF861FE90006001F1613 /* AppIconShortcutsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconShortcutsViewController.swift; sourceTree = "<group>"; };
|
||||||
|
BF71CF891FE904B1001F1613 /* GameTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = GameTableViewCell.xib; sourceTree = "<group>"; };
|
||||||
BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILabel+FontSize.swift"; sourceTree = "<group>"; };
|
BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILabel+FontSize.swift"; sourceTree = "<group>"; };
|
||||||
BF7AE8041C2E858400B1B5BC /* GridMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridMenuViewController.swift; sourceTree = "<group>"; };
|
BF7AE8041C2E858400B1B5BC /* GridMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridMenuViewController.swift; sourceTree = "<group>"; };
|
||||||
BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Delta.swift"; sourceTree = "<group>"; };
|
BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Delta.swift"; sourceTree = "<group>"; };
|
||||||
@ -243,7 +251,7 @@
|
|||||||
BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveStateMigrationPolicy.swift; sourceTree = "<group>"; };
|
BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveStateMigrationPolicy.swift; sourceTree = "<group>"; };
|
||||||
BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBCDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBCDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputStreamOutputWriter.swift; sourceTree = "<group>"; };
|
BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputStreamOutputWriter.swift; sourceTree = "<group>"; };
|
||||||
BFFA4C081E8A24D600D87934 /* GameMetadataTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameMetadataTableViewCell.swift; sourceTree = "<group>"; };
|
BFFA4C081E8A24D600D87934 /* GameTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
BFFA71D71AAC406100EE9DD1 /* Delta.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Delta.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
BFFA71D71AAC406100EE9DD1 /* Delta.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Delta.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
BFFA71DB1AAC406100EE9DD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
BFFA71DB1AAC406100EE9DD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
@ -343,12 +351,22 @@
|
|||||||
path = "Game Selection";
|
path = "Game Selection";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
BF525EE61FF5F355004AA849 /* Deep Linking */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
BF525EE91FF6CD12004AA849 /* DeepLink.swift */,
|
||||||
|
BF525EE71FF5F370004AA849 /* DeepLinkController.swift */,
|
||||||
|
);
|
||||||
|
path = "Deep Linking";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
BF5942571E09BB5D0051894B /* Components */ = {
|
BF5942571E09BB5D0051894B /* Components */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
BF4828871F90290F00028B97 /* Action.swift */,
|
BF4828871F90290F00028B97 /* Action.swift */,
|
||||||
BFE0229C1F5B56840052D888 /* Popover Menu */,
|
BFE0229C1F5B56840052D888 /* Popover Menu */,
|
||||||
BF5942671E09BBB70051894B /* Collection View */,
|
BF5942671E09BBB70051894B /* Collection View */,
|
||||||
|
BF71CF881FE90471001F1613 /* Table View */,
|
||||||
BF5942601E09BBA80051894B /* Loading */,
|
BF5942601E09BBA80051894B /* Loading */,
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Components;
|
||||||
@ -467,6 +485,23 @@
|
|||||||
path = "Import Options";
|
path = "Import Options";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
BF71CF851FE8FFF1001F1613 /* App Icon Shortcuts */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
BF71CF861FE90006001F1613 /* AppIconShortcutsViewController.swift */,
|
||||||
|
);
|
||||||
|
path = "App Icon Shortcuts";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
BF71CF881FE90471001F1613 /* Table View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
BFFA4C081E8A24D600D87934 /* GameTableViewCell.swift */,
|
||||||
|
BF71CF891FE904B1001F1613 /* GameTableViewCell.xib */,
|
||||||
|
);
|
||||||
|
path = "Table View";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
BF7AE7FA1C2E851F00B1B5BC /* Pause Menu */ = {
|
BF7AE7FA1C2E851F00B1B5BC /* Pause Menu */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -506,7 +541,6 @@
|
|||||||
BF59426E1E09BC5D0051894B /* GamesDatabase.swift */,
|
BF59426E1E09BC5D0051894B /* GamesDatabase.swift */,
|
||||||
BF95E2761E4977BF0030E7AD /* GameMetadata.swift */,
|
BF95E2761E4977BF0030E7AD /* GameMetadata.swift */,
|
||||||
BF95E2781E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift */,
|
BF95E2781E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift */,
|
||||||
BFFA4C081E8A24D600D87934 /* GameMetadataTableViewCell.swift */,
|
|
||||||
);
|
);
|
||||||
path = OpenVGDB;
|
path = OpenVGDB;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -534,6 +568,7 @@
|
|||||||
BFAA1FEC1B8AA4FA00495943 /* Settings.swift */,
|
BFAA1FEC1B8AA4FA00495943 /* Settings.swift */,
|
||||||
BF5E7F451B9A652600AE44F8 /* Settings.storyboard */,
|
BF5E7F451B9A652600AE44F8 /* Settings.storyboard */,
|
||||||
BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */,
|
BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */,
|
||||||
|
BF71CF851FE8FFF1001F1613 /* App Icon Shortcuts */,
|
||||||
BF11734E1DA32CEC00047DF8 /* Controllers */,
|
BF11734E1DA32CEC00047DF8 /* Controllers */,
|
||||||
BF1DAD5B1D9F574900E752A7 /* Controller Skins */,
|
BF1DAD5B1D9F574900E752A7 /* Controller Skins */,
|
||||||
);
|
);
|
||||||
@ -620,6 +655,7 @@
|
|||||||
BF59426C1E09BC450051894B /* Database */,
|
BF59426C1E09BC450051894B /* Database */,
|
||||||
BF59428C1E09BCE50051894B /* Importing */,
|
BF59428C1E09BCE50051894B /* Importing */,
|
||||||
BF930FFB1EB6D6EC00E8DBA0 /* Systems */,
|
BF930FFB1EB6D6EC00E8DBA0 /* Systems */,
|
||||||
|
BF525EE61FF5F355004AA849 /* Deep Linking */,
|
||||||
BF5942571E09BB5D0051894B /* Components */,
|
BF5942571E09BB5D0051894B /* Components */,
|
||||||
BF696B7E1D9B2AE6009639E0 /* Theming */,
|
BF696B7E1D9B2AE6009639E0 /* Theming */,
|
||||||
BF090CEE1B490C1A00DCAB45 /* Extensions */,
|
BF090CEE1B490C1A00DCAB45 /* Extensions */,
|
||||||
@ -759,6 +795,7 @@
|
|||||||
BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */,
|
BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */,
|
||||||
BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */,
|
BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */,
|
||||||
BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */,
|
BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */,
|
||||||
|
BF71CF8A1FE904B1001F1613 /* GameTableViewCell.xib in Resources */,
|
||||||
BFFC46461D59861000AF2CC6 /* LaunchScreen.storyboard in Resources */,
|
BFFC46461D59861000AF2CC6 /* LaunchScreen.storyboard in Resources */,
|
||||||
BF353FF61C5D837600C1184C /* PauseMenu.storyboard in Resources */,
|
BF353FF61C5D837600C1184C /* PauseMenu.storyboard in Resources */,
|
||||||
BF27CC8E1BC9FEA200A20D89 /* Assets.xcassets in Resources */,
|
BF27CC8E1BC9FEA200A20D89 /* Assets.xcassets in Resources */,
|
||||||
@ -855,6 +892,7 @@
|
|||||||
BF59427C1E09BC830051894B /* Cheat.swift in Sources */,
|
BF59427C1E09BC830051894B /* Cheat.swift in Sources */,
|
||||||
BFBAB2E31EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift in Sources */,
|
BFBAB2E31EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift in Sources */,
|
||||||
BF3540081C5DAFAD00C1184C /* PauseTransitionCoordinator.swift in Sources */,
|
BF3540081C5DAFAD00C1184C /* PauseTransitionCoordinator.swift in Sources */,
|
||||||
|
BF525EEA1FF6CD12004AA849 /* DeepLink.swift in Sources */,
|
||||||
BF59427E1E09BC830051894B /* Game.swift in Sources */,
|
BF59427E1E09BC830051894B /* Game.swift in Sources */,
|
||||||
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */,
|
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */,
|
||||||
BFA0D1271D3AE1F600565894 /* GameViewController.swift in Sources */,
|
BFA0D1271D3AE1F600565894 /* GameViewController.swift in Sources */,
|
||||||
@ -875,15 +913,17 @@
|
|||||||
BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */,
|
BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */,
|
||||||
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */,
|
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */,
|
||||||
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
|
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
|
||||||
|
BF525EE81FF5F370004AA849 /* DeepLinkController.swift in Sources */,
|
||||||
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */,
|
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */,
|
||||||
BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */,
|
BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */,
|
||||||
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */,
|
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */,
|
||||||
BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */,
|
BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */,
|
||||||
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
|
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
|
||||||
|
BF71CF871FE90006001F1613 /* AppIconShortcutsViewController.swift in Sources */,
|
||||||
BF1DAD5D1D9F576000E752A7 /* SystemControllerSkinsViewController.swift in Sources */,
|
BF1DAD5D1D9F576000E752A7 /* SystemControllerSkinsViewController.swift in Sources */,
|
||||||
BFE022A01F5B57FF0052D888 /* PopoverMenuButton.swift in Sources */,
|
BFE022A01F5B57FF0052D888 /* PopoverMenuButton.swift in Sources */,
|
||||||
BF6BF31C1EB821A0008E83CD /* GamesDatabaseImportOption.swift in Sources */,
|
BF6BF31C1EB821A0008E83CD /* GamesDatabaseImportOption.swift in Sources */,
|
||||||
BFFA4C091E8A24D600D87934 /* GameMetadataTableViewCell.swift in Sources */,
|
BFFA4C091E8A24D600D87934 /* GameTableViewCell.swift in Sources */,
|
||||||
BFFC46231D5984A000AF2CC6 /* LaunchViewController.swift in Sources */,
|
BFFC46231D5984A000AF2CC6 /* LaunchViewController.swift in Sources */,
|
||||||
BF8DDD241F4F6C880088A21B /* InputCalloutView.swift in Sources */,
|
BF8DDD241F4F6C880088A21B /* InputCalloutView.swift in Sources */,
|
||||||
BF5942701E09BC5D0051894B /* GamesDatabase.swift in Sources */,
|
BF5942701E09BC5D0051894B /* GamesDatabase.swift in Sources */,
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import Crashlytics
|
|||||||
class AppDelegate: UIResponder, UIApplicationDelegate
|
class AppDelegate: UIResponder, UIApplicationDelegate
|
||||||
{
|
{
|
||||||
var window: UIWindow?
|
var window: UIWindow?
|
||||||
|
|
||||||
|
private let deepLinkController = DeepLinkController()
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
|
||||||
{
|
{
|
||||||
@ -35,12 +37,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
|
|
||||||
DatabaseManager.shared.loadPersistentStores { (description, error) in
|
DatabaseManager.shared.loadPersistentStores { (description, error) in
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controllers
|
// Controllers
|
||||||
ExternalGameControllerManager.shared.startMonitoring()
|
ExternalGameControllerManager.shared.startMonitoring()
|
||||||
|
|
||||||
|
// Deep Links
|
||||||
|
if let shortcut = launchOptions?[.shortcutItem] as? UIApplicationShortcutItem
|
||||||
|
{
|
||||||
|
self.deepLinkController.handle(.shortcut(shortcut))
|
||||||
|
|
||||||
|
// false = we handled the deep link, so no need to call delegate method separately.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -78,8 +88,6 @@ extension AppDelegate
|
|||||||
func configureAppearance()
|
func configureAppearance()
|
||||||
{
|
{
|
||||||
self.window?.tintColor = UIColor.deltaPurple
|
self.window?.tintColor = UIColor.deltaPurple
|
||||||
|
|
||||||
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes[NSAttributedStringKey.foregroundColor.rawValue] = UIColor.white
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,15 +100,20 @@ extension AppDelegate
|
|||||||
|
|
||||||
@discardableResult private func openURL(_ url: URL) -> Bool
|
@discardableResult private func openURL(_ url: URL) -> Bool
|
||||||
{
|
{
|
||||||
guard url.isFileURL else { return false }
|
if url.isFileURL
|
||||||
|
|
||||||
if GameType(fileExtension: url.pathExtension) != nil || url.pathExtension.lowercased() == "zip"
|
|
||||||
{
|
{
|
||||||
return self.importGame(at: url)
|
if GameType(fileExtension: url.pathExtension) != nil || url.pathExtension.lowercased() == "zip"
|
||||||
|
{
|
||||||
|
return self.importGame(at: url)
|
||||||
|
}
|
||||||
|
else if url.pathExtension.lowercased() == "deltaskin"
|
||||||
|
{
|
||||||
|
return self.importControllerSkin(at: url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if url.pathExtension.lowercased() == "deltaskin"
|
else
|
||||||
{
|
{
|
||||||
return self.importControllerSkin(at: url)
|
return self.deepLinkController.handle(.url(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@ -145,3 +158,12 @@ extension AppDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension AppDelegate
|
||||||
|
{
|
||||||
|
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void)
|
||||||
|
{
|
||||||
|
let result = self.deepLinkController.handle(.shortcut(shortcutItem))
|
||||||
|
completionHandler(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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="6bq-zy-UZU">
|
<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="6bq-zy-UZU">
|
||||||
<device id="retina4_7" orientation="portrait">
|
<device id="retina4_7" orientation="portrait">
|
||||||
<adaptation id="fullscreen"/>
|
<adaptation id="fullscreen"/>
|
||||||
</device>
|
</device>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13526"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
@ -18,52 +17,6 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<prototypes>
|
|
||||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="4cJ-4B-Kgt" customClass="GameMetadataTableViewCell" customModule="Delta" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="28" width="375" height="97"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4cJ-4B-Kgt" id="7ze-s0-mpI">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="96.5"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<subviews>
|
|
||||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DSH-Hk-snb" userLabel="Selected Background View">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="97.5"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
|
||||||
</view>
|
|
||||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="BoxArt" translatesAutoresizingMaskIntoConstraints="NO" id="tNY-2F-llo">
|
|
||||||
<rect key="frame" x="15" y="8" width="80" height="80"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" secondItem="tNY-2F-llo" secondAttribute="height" multiplier="1:1" id="f4E-bV-L96"/>
|
|
||||||
</constraints>
|
|
||||||
</imageView>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Super Mario World" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DND-Fv-FyB">
|
|
||||||
<rect key="frame" x="110" y="38.5" width="250" height="20.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="DND-Fv-FyB" firstAttribute="leading" secondItem="tNY-2F-llo" secondAttribute="trailing" constant="15" id="71e-t3-7Av"/>
|
|
||||||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="DND-Fv-FyB" secondAttribute="bottom" constant="1" id="9No-RE-0xx"/>
|
|
||||||
<constraint firstItem="DND-Fv-FyB" firstAttribute="top" relation="greaterThanOrEqual" secondItem="7ze-s0-mpI" secondAttribute="top" constant="1" id="F9q-6H-sqC"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="DND-Fv-FyB" secondAttribute="trailing" constant="15" id="KFv-7n-LrD"/>
|
|
||||||
<constraint firstItem="DND-Fv-FyB" firstAttribute="centerY" secondItem="7ze-s0-mpI" secondAttribute="centerY" id="YBX-t4-jkR"/>
|
|
||||||
<constraint firstItem="tNY-2F-llo" firstAttribute="top" secondItem="7ze-s0-mpI" secondAttribute="top" constant="8" id="bYX-gA-QvB"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="tNY-2F-llo" secondAttribute="bottom" constant="8" id="fxr-wr-I6X"/>
|
|
||||||
<constraint firstItem="tNY-2F-llo" firstAttribute="leading" secondItem="7ze-s0-mpI" secondAttribute="leading" constant="15" id="hX2-Gr-Bnz"/>
|
|
||||||
</constraints>
|
|
||||||
</tableViewCellContentView>
|
|
||||||
<connections>
|
|
||||||
<outlet property="artworkImageView" destination="tNY-2F-llo" id="GqY-jv-rso"/>
|
|
||||||
<outlet property="artworkImageViewLeadingConstraint" destination="hX2-Gr-Bnz" id="be8-dr-c8K"/>
|
|
||||||
<outlet property="artworkImageViewTrailingConstraint" destination="71e-t3-7Av" id="y62-KO-y1r"/>
|
|
||||||
<outlet property="nameLabel" destination="DND-Fv-FyB" id="LhN-cA-8Hy"/>
|
|
||||||
<outlet property="selectedBackgroundView" destination="DSH-Hk-snb" id="hLY-4k-VxU"/>
|
|
||||||
</connections>
|
|
||||||
</tableViewCell>
|
|
||||||
</prototypes>
|
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="SB6-jW-dhZ" id="2aq-ZA-84E"/>
|
<outlet property="dataSource" destination="SB6-jW-dhZ" id="2aq-ZA-84E"/>
|
||||||
<outlet property="delegate" destination="SB6-jW-dhZ" id="WgY-cp-m7K"/>
|
<outlet property="delegate" destination="SB6-jW-dhZ" id="WgY-cp-m7K"/>
|
||||||
@ -101,7 +54,4 @@
|
|||||||
<point key="canvasLocation" x="1854" y="1002"/>
|
<point key="canvasLocation" x="1854" y="1002"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
|
||||||
<image name="BoxArt" width="100" height="100"/>
|
|
||||||
</resources>
|
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@ -100,7 +100,7 @@
|
|||||||
<inset key="sectionInset" minX="0.0" minY="20" maxX="0.0" maxY="20"/>
|
<inset key="sectionInset" minX="0.0" minY="20" maxX="0.0" maxY="20"/>
|
||||||
</collectionViewFlowLayout>
|
</collectionViewFlowLayout>
|
||||||
<cells>
|
<cells>
|
||||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" misplaced="YES" reuseIdentifier="Cell" id="6XS-Ne-nGZ" customClass="GridCollectionViewCell" customModule="Delta" customModuleProvider="target">
|
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="Cell" id="6XS-Ne-nGZ" customClass="GridCollectionViewCell" customModule="Delta" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="20" width="60" height="80"/>
|
<rect key="frame" x="0.0" y="20" width="60" height="80"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<label key="tableFooterView" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Delta 0.6.0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Str-BY-agW">
|
<label key="tableFooterView" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Delta 0.6.0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Str-BY-agW">
|
||||||
<rect key="frame" x="0.0" y="573" width="375" height="44"/>
|
<rect key="frame" x="0.0" y="673" width="375" height="44"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="textColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
@ -222,6 +222,30 @@
|
|||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
</cells>
|
</cells>
|
||||||
</tableViewSection>
|
</tableViewSection>
|
||||||
|
<tableViewSection headerTitle="3D Touch" id="fdp-8c-oOc">
|
||||||
|
<cells>
|
||||||
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="c5i-qG-ir9" style="IBUITableViewCellStyleDefault" id="SSL-t4-QZj">
|
||||||
|
<rect key="frame" x="0.0" y="611" width="375" height="44"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="SSL-t4-QZj" id="hQB-Iy-bzy">
|
||||||
|
<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="App Icon Shortcuts" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="c5i-qG-ir9">
|
||||||
|
<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"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
<connections>
|
||||||
|
<segue destination="yXS-6u-1AN" kind="show" id="b79-OK-isV"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewCell>
|
||||||
|
</cells>
|
||||||
|
</tableViewSection>
|
||||||
</sections>
|
</sections>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="eHi-aO-uGS" id="rsh-0y-8Ex"/>
|
<outlet property="dataSource" destination="eHi-aO-uGS" id="rsh-0y-8Ex"/>
|
||||||
@ -441,6 +465,51 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="2220" y="1181.5592203898052"/>
|
<point key="canvasLocation" x="2220" y="1181.5592203898052"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
<!--App Icon Shortcuts-->
|
||||||
|
<scene sceneID="e9N-fv-yuQ">
|
||||||
|
<objects>
|
||||||
|
<tableViewController id="yXS-6u-1AN" customClass="AppIconShortcutsViewController" customModule="Delta" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="97" sectionHeaderHeight="18" sectionFooterHeight="18" id="BGy-Nh-8Yd">
|
||||||
|
<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" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="SwitchCell" rowHeight="44" id="Syl-dC-eKZ" customClass="SwitchTableViewCell">
|
||||||
|
<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" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Syl-dC-eKZ" id="lw6-ca-UzI">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4bh-Lf-zgk">
|
||||||
|
<rect key="frame" x="310" y="6" width="51" height="31"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="switchGameShortcutsModeWith:" destination="yXS-6u-1AN" eventType="valueChanged" id="bX8-gd-h4g"/>
|
||||||
|
</connections>
|
||||||
|
</switch>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="4bh-Lf-zgk" firstAttribute="trailing" secondItem="lw6-ca-UzI" secondAttribute="trailingMargin" id="N1l-8j-xNY"/>
|
||||||
|
<constraint firstItem="4bh-Lf-zgk" firstAttribute="centerY" secondItem="lw6-ca-UzI" secondAttribute="centerY" id="bTA-Ci-3mD"/>
|
||||||
|
</constraints>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
<connections>
|
||||||
|
<outlet property="switchView" destination="4bh-Lf-zgk" id="lL9-4t-5VN"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewCell>
|
||||||
|
</prototypes>
|
||||||
|
<connections>
|
||||||
|
<outlet property="dataSource" destination="yXS-6u-1AN" id="gUb-Iy-f9K"/>
|
||||||
|
<outlet property="delegate" destination="yXS-6u-1AN" id="UM5-nl-szw"/>
|
||||||
|
</connections>
|
||||||
|
</tableView>
|
||||||
|
<navigationItem key="navigationItem" title="App Icon Shortcuts" id="wfE-7e-l8g"/>
|
||||||
|
</tableViewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="Lzk-4m-LKw" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="2220" y="1897"/>
|
||||||
|
</scene>
|
||||||
<!--Controller Skins-->
|
<!--Controller Skins-->
|
||||||
<scene sceneID="IN0-an-SWm">
|
<scene sceneID="IN0-an-SWm">
|
||||||
<objects>
|
<objects>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// GameMetadataTableViewCell.swift
|
// GameTableViewCell.swift
|
||||||
// Delta
|
// Delta
|
||||||
//
|
//
|
||||||
// Created by Riley Testut on 3/27/17.
|
// Created by Riley Testut on 3/27/17.
|
||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class GameMetadataTableViewCell: UITableViewCell
|
class GameTableViewCell: UITableViewCell
|
||||||
{
|
{
|
||||||
@IBOutlet private(set) var nameLabel: UILabel!
|
@IBOutlet private(set) var nameLabel: UILabel!
|
||||||
@IBOutlet private(set) var artworkImageView: UIImageView!
|
@IBOutlet private(set) var artworkImageView: UIImageView!
|
||||||
63
Delta/Components/Table View/GameTableViewCell.xib
Normal file
63
Delta/Components/Table View/GameTableViewCell.xib
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||||
|
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="FL0-zT-qa3" customClass="GameTableViewCell" customModule="Delta" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="97"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="FL0-zT-qa3" id="zSi-4a-DaH">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="96.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5dT-zd-huQ" userLabel="Selected Background View">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="96.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="BoxArt" translatesAutoresizingMaskIntoConstraints="NO" id="68X-vf-MNx">
|
||||||
|
<rect key="frame" x="15" y="8" width="80" height="80"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="width" secondItem="68X-vf-MNx" secondAttribute="height" multiplier="1:1" id="P6f-Lc-8B3"/>
|
||||||
|
</constraints>
|
||||||
|
</imageView>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Super Mario World" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hKz-BX-p8h">
|
||||||
|
<rect key="frame" x="110" y="38.5" width="250" height="20.5"/>
|
||||||
|
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="hKz-BX-p8h" secondAttribute="bottom" constant="1" id="1JB-It-w1s"/>
|
||||||
|
<constraint firstItem="68X-vf-MNx" firstAttribute="leading" secondItem="zSi-4a-DaH" secondAttribute="leading" constant="15" id="CD9-Qz-0UL"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="hKz-BX-p8h" secondAttribute="trailing" constant="15" id="RxT-jB-cvp"/>
|
||||||
|
<constraint firstItem="68X-vf-MNx" firstAttribute="top" secondItem="zSi-4a-DaH" secondAttribute="top" constant="8" id="T5j-O5-aTX"/>
|
||||||
|
<constraint firstItem="hKz-BX-p8h" firstAttribute="leading" secondItem="68X-vf-MNx" secondAttribute="trailing" constant="15" id="jks-s2-5ZX"/>
|
||||||
|
<constraint firstItem="hKz-BX-p8h" firstAttribute="top" relation="greaterThanOrEqual" secondItem="zSi-4a-DaH" secondAttribute="top" constant="1" id="swc-Ib-2wh"/>
|
||||||
|
<constraint firstItem="hKz-BX-p8h" firstAttribute="centerY" secondItem="zSi-4a-DaH" secondAttribute="centerY" id="uyb-vA-Qtb"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="68X-vf-MNx" secondAttribute="bottom" constant="8" id="wGX-lV-ACr"/>
|
||||||
|
</constraints>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
<connections>
|
||||||
|
<outlet property="artworkImageView" destination="68X-vf-MNx" id="Sda-Tl-WEd"/>
|
||||||
|
<outlet property="artworkImageViewLeadingConstraint" destination="CD9-Qz-0UL" id="jhw-i7-9ak"/>
|
||||||
|
<outlet property="artworkImageViewTrailingConstraint" destination="jks-s2-5ZX" id="vrM-OV-rsa"/>
|
||||||
|
<outlet property="nameLabel" destination="hKz-BX-p8h" id="gdI-v9-dj3"/>
|
||||||
|
<outlet property="selectedBackgroundView" destination="5dT-zd-huQ" id="jOr-DK-8bp"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewCell>
|
||||||
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<image name="BoxArt" width="100" height="100"/>
|
||||||
|
</resources>
|
||||||
|
</document>
|
||||||
@ -62,6 +62,8 @@ final class DatabaseManager: NSPersistentContainer
|
|||||||
|
|
||||||
private var gamesDatabase: GamesDatabase? = nil
|
private var gamesDatabase: GamesDatabase? = nil
|
||||||
|
|
||||||
|
private var validationManagedObjectContext: NSManagedObjectContext?
|
||||||
|
|
||||||
private init()
|
private init()
|
||||||
{
|
{
|
||||||
guard
|
guard
|
||||||
@ -94,11 +96,39 @@ extension DatabaseManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - Update -
|
||||||
|
private extension DatabaseManager
|
||||||
|
{
|
||||||
|
func updateRecentGameShortcuts()
|
||||||
|
{
|
||||||
|
guard let managedObjectContext = self.validationManagedObjectContext else { return }
|
||||||
|
|
||||||
|
guard Settings.gameShortcutsMode == .recent else { return }
|
||||||
|
|
||||||
|
let fetchRequest = Game.recentlyPlayedFetchRequest
|
||||||
|
fetchRequest.returnsObjectsAsFaults = false
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let games = try managedObjectContext.fetch(fetchRequest)
|
||||||
|
Settings.gameShortcuts = games
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: - Preparation -
|
//MARK: - Preparation -
|
||||||
private extension DatabaseManager
|
private extension DatabaseManager
|
||||||
{
|
{
|
||||||
func prepareDatabase(completion: @escaping () -> Void)
|
func prepareDatabase(completion: @escaping () -> Void)
|
||||||
{
|
{
|
||||||
|
self.validationManagedObjectContext = self.newBackgroundContext()
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(DatabaseManager.validateManagedObjectContextSave(with:)), name: .NSManagedObjectContextDidSave, object: nil)
|
||||||
|
|
||||||
self.performBackgroundTask { (context) in
|
self.performBackgroundTask { (context) in
|
||||||
|
|
||||||
for system in System.supportedSystems
|
for system in System.supportedSystems
|
||||||
@ -137,7 +167,6 @@ private extension DatabaseManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
completion()
|
completion()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -502,6 +531,28 @@ extension DatabaseManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - Notifications -
|
||||||
|
private extension DatabaseManager
|
||||||
|
{
|
||||||
|
@objc func validateManagedObjectContextSave(with notification: Notification)
|
||||||
|
{
|
||||||
|
guard (notification.object as? NSManagedObjectContext) != self.validationManagedObjectContext else { return }
|
||||||
|
|
||||||
|
let insertedObjects = (notification.userInfo?[NSInsertedObjectsKey] as? Set<NSManagedObject>) ?? []
|
||||||
|
let updatedObjects = (notification.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>) ?? []
|
||||||
|
let deletedObjects = (notification.userInfo?[NSDeletedObjectsKey] as? Set<NSManagedObject>) ?? []
|
||||||
|
|
||||||
|
let allObjects = insertedObjects.union(updatedObjects).union(deletedObjects)
|
||||||
|
|
||||||
|
if allObjects.contains(where: { $0 is Game })
|
||||||
|
{
|
||||||
|
self.validationManagedObjectContext?.perform {
|
||||||
|
self.updateRecentGameShortcuts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: - Private -
|
//MARK: - Private -
|
||||||
private extension DatabaseManager
|
private extension DatabaseManager
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="13532" systemVersion="16G29" minimumToolsVersion="Xcode 7.0" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="1.0">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="13772" systemVersion="16G1114" minimumToolsVersion="Xcode 7.0" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="1.0">
|
||||||
<entity name="Cheat" representedClassName="Cheat" syncable="YES">
|
<entity name="Cheat" representedClassName="Cheat" syncable="YES">
|
||||||
<attribute name="code" attributeType="String" syncable="YES"/>
|
<attribute name="code" attributeType="String" syncable="YES"/>
|
||||||
<attribute name="creationDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
<attribute name="creationDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||||
@ -54,6 +54,7 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||||
<attribute name="name" attributeType="String" syncable="YES"/>
|
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="playedDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||||
<attribute name="type" attributeType="Transformable" syncable="YES">
|
<attribute name="type" attributeType="Transformable" syncable="YES">
|
||||||
<userInfo>
|
<userInfo>
|
||||||
<entry key="attributeValueClassName" value="GameType"/>
|
<entry key="attributeValueClassName" value="GameType"/>
|
||||||
@ -130,7 +131,7 @@
|
|||||||
<elements>
|
<elements>
|
||||||
<element name="Cheat" positionX="-198" positionY="-63" width="128" height="165"/>
|
<element name="Cheat" positionX="-198" positionY="-63" width="128" height="165"/>
|
||||||
<element name="ControllerSkin" positionX="-387" positionY="90" width="128" height="135"/>
|
<element name="ControllerSkin" positionX="-387" positionY="90" width="128" height="135"/>
|
||||||
<element name="Game" positionX="-378" positionY="-54" width="128" height="180"/>
|
<element name="Game" positionX="-378" positionY="-54" width="128" height="195"/>
|
||||||
<element name="GameCollection" positionX="-585" positionY="-27" width="128" height="90"/>
|
<element name="GameCollection" positionX="-585" positionY="-27" width="128" height="90"/>
|
||||||
<element name="GameControllerInputMapping" positionX="-387" positionY="90" width="128" height="105"/>
|
<element name="GameControllerInputMapping" positionX="-387" positionY="90" width="128" height="105"/>
|
||||||
<element name="SaveState" positionX="-198" positionY="113" width="128" height="165"/>
|
<element name="SaveState" positionX="-198" positionY="113" width="128" height="165"/>
|
||||||
|
|||||||
@ -55,6 +55,18 @@ public class Game: _Game, GameProtocol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Game
|
||||||
|
{
|
||||||
|
class var recentlyPlayedFetchRequest: NSFetchRequest<Game> {
|
||||||
|
let fetchRequest: NSFetchRequest<Game> = Game.fetchRequest()
|
||||||
|
fetchRequest.predicate = NSPredicate(format: "%K != nil", #keyPath(Game.playedDate))
|
||||||
|
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Game.playedDate, ascending: false), NSSortDescriptor(keyPath: \Game.name, ascending: true)]
|
||||||
|
fetchRequest.fetchLimit = 4
|
||||||
|
|
||||||
|
return fetchRequest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension Game
|
extension Game
|
||||||
{
|
{
|
||||||
override public func prepareForDeletion()
|
override public func prepareForDeletion()
|
||||||
|
|||||||
@ -22,6 +22,8 @@ public class _Game: NSManagedObject
|
|||||||
|
|
||||||
@NSManaged public var name: String
|
@NSManaged public var name: String
|
||||||
|
|
||||||
|
@NSManaged public var playedDate: Date?
|
||||||
|
|
||||||
@NSManaged public var type: GameType
|
@NSManaged public var type: GameType
|
||||||
|
|
||||||
// MARK: - Relationships
|
// MARK: - Relationships
|
||||||
|
|||||||
@ -54,6 +54,8 @@ class GamesDatabaseBrowserViewController: UITableViewController
|
|||||||
|
|
||||||
self.view.backgroundColor = UIColor.deltaDarkGray
|
self.view.backgroundColor = UIColor.deltaDarkGray
|
||||||
|
|
||||||
|
self.tableView.register(GameTableViewCell.nib!, forCellReuseIdentifier: RSTCellContentGenericCellIdentifier)
|
||||||
|
|
||||||
self.tableView.dataSource = self.dataSource
|
self.tableView.dataSource = self.dataSource
|
||||||
self.tableView.prefetchDataSource = self.dataSource
|
self.tableView.prefetchDataSource = self.dataSource
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ class GamesDatabaseBrowserViewController: UITableViewController
|
|||||||
self.tableView.separatorColor = UIColor.gray
|
self.tableView.separatorColor = UIColor.gray
|
||||||
|
|
||||||
self.dataSource.searchController.delegate = self
|
self.dataSource.searchController.delegate = self
|
||||||
self.dataSource.searchController.searchBar.barStyle = .blackTranslucent
|
self.dataSource.searchController.searchBar.barStyle = .black
|
||||||
|
|
||||||
if #available(iOS 11, *)
|
if #available(iOS 11, *)
|
||||||
{
|
{
|
||||||
@ -95,7 +97,7 @@ private extension GamesDatabaseBrowserViewController
|
|||||||
|
|
||||||
/* Cell Configuration */
|
/* Cell Configuration */
|
||||||
self.dataSource.cellConfigurationHandler = { [unowned self] (cell, metadata, indexPath) in
|
self.dataSource.cellConfigurationHandler = { [unowned self] (cell, metadata, indexPath) in
|
||||||
self.configure(cell: cell as! GameMetadataTableViewCell, with: metadata, for: indexPath)
|
self.configure(cell: cell as! GameTableViewCell, with: metadata, for: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -113,7 +115,7 @@ private extension GamesDatabaseBrowserViewController
|
|||||||
self.dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in
|
self.dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in
|
||||||
guard let image = image else { return }
|
guard let image = image else { return }
|
||||||
|
|
||||||
let cell = cell as! GameMetadataTableViewCell
|
let cell = cell as! GameTableViewCell
|
||||||
|
|
||||||
let artworkDisplaySize = AVMakeRect(aspectRatio: image.size, insideRect: cell.artworkImageView.bounds)
|
let artworkDisplaySize = AVMakeRect(aspectRatio: image.size, insideRect: cell.artworkImageView.bounds)
|
||||||
let offset = (cell.artworkImageView.bounds.width - artworkDisplaySize.width) / 2
|
let offset = (cell.artworkImageView.bounds.width - artworkDisplaySize.width) / 2
|
||||||
@ -150,7 +152,7 @@ private extension GamesDatabaseBrowserViewController
|
|||||||
|
|
||||||
private extension GamesDatabaseBrowserViewController
|
private extension GamesDatabaseBrowserViewController
|
||||||
{
|
{
|
||||||
func configure(cell: GameMetadataTableViewCell, with metadata: GameMetadata, for indexPath: IndexPath)
|
func configure(cell: GameTableViewCell, with metadata: GameMetadata, for indexPath: IndexPath)
|
||||||
{
|
{
|
||||||
cell.backgroundColor = UIColor.deltaDarkGray
|
cell.backgroundColor = UIColor.deltaDarkGray
|
||||||
|
|
||||||
|
|||||||
103
Delta/Deep Linking/DeepLink.swift
Normal file
103
Delta/Deep Linking/DeepLink.swift
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// DeepLink.swift
|
||||||
|
// Delta
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 12/29/17.
|
||||||
|
// Copyright © 2017 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension URL
|
||||||
|
{
|
||||||
|
init(action: DeepLink.Action)
|
||||||
|
{
|
||||||
|
var components = URLComponents()
|
||||||
|
components.host = action.type.rawValue
|
||||||
|
|
||||||
|
switch action
|
||||||
|
{
|
||||||
|
case .launchGame(let identifier): components.path = identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = components.url!
|
||||||
|
self = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UIApplicationShortcutItem
|
||||||
|
{
|
||||||
|
convenience init(localizedTitle: String, action: DeepLink.Action)
|
||||||
|
{
|
||||||
|
var userInfo: [AnyHashable: Any]?
|
||||||
|
|
||||||
|
switch action
|
||||||
|
{
|
||||||
|
case .launchGame(let identifier): userInfo = [DeepLink.Key.identifier.rawValue: identifier]
|
||||||
|
}
|
||||||
|
|
||||||
|
self.init(type: action.type.rawValue, localizedTitle: localizedTitle, localizedSubtitle: nil, icon: nil, userInfo: userInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DeepLink
|
||||||
|
{
|
||||||
|
enum Action
|
||||||
|
{
|
||||||
|
case launchGame(identifier: String)
|
||||||
|
|
||||||
|
var type: ActionType {
|
||||||
|
switch self
|
||||||
|
{
|
||||||
|
case .launchGame: return .launchGame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ActionType: String
|
||||||
|
{
|
||||||
|
case launchGame = "game"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Key: String
|
||||||
|
{
|
||||||
|
case identifier
|
||||||
|
case game
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DeepLink
|
||||||
|
{
|
||||||
|
case url(URL)
|
||||||
|
case shortcut(UIApplicationShortcutItem)
|
||||||
|
|
||||||
|
var actionType: ActionType? {
|
||||||
|
switch self
|
||||||
|
{
|
||||||
|
case .url(let url):
|
||||||
|
guard let host = url.host else { return nil }
|
||||||
|
|
||||||
|
let type = ActionType(rawValue: host)
|
||||||
|
return type
|
||||||
|
|
||||||
|
case .shortcut(let shortcut):
|
||||||
|
let type = ActionType(rawValue: shortcut.type)
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var action: Action? {
|
||||||
|
guard let type = self.actionType else { return nil }
|
||||||
|
|
||||||
|
switch (self, type)
|
||||||
|
{
|
||||||
|
case (.url(let url), .launchGame):
|
||||||
|
let identifier = url.lastPathComponent
|
||||||
|
return .launchGame(identifier: identifier)
|
||||||
|
|
||||||
|
case (.shortcut(let shortcut), .launchGame):
|
||||||
|
guard let identifier = shortcut.userInfo?[Key.identifier.rawValue] as? String else { return nil }
|
||||||
|
return .launchGame(identifier: identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
Delta/Deep Linking/DeepLinkController.swift
Normal file
83
Delta/Deep Linking/DeepLinkController.swift
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
//
|
||||||
|
// DeepLinkController.swift
|
||||||
|
// Delta
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 12/28/17.
|
||||||
|
// Copyright © 2017 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension Notification.Name
|
||||||
|
{
|
||||||
|
static let deepLinkControllerLaunchGame = Notification.Name("deepLinkControllerLaunchGame")
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UIViewController
|
||||||
|
{
|
||||||
|
var allowsDeepLinkingDismissal: Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DeepLinkController
|
||||||
|
{
|
||||||
|
private var window: UIWindow? {
|
||||||
|
guard let delegate = UIApplication.shared.delegate, let window = delegate.window else { return nil }
|
||||||
|
return window
|
||||||
|
}
|
||||||
|
|
||||||
|
private var topViewController: UIViewController? {
|
||||||
|
guard let window = self.window else { return nil }
|
||||||
|
|
||||||
|
var topViewController = window.rootViewController
|
||||||
|
while topViewController?.presentedViewController != nil
|
||||||
|
{
|
||||||
|
guard !(topViewController?.presentedViewController is UIAlertController) else { break }
|
||||||
|
|
||||||
|
topViewController = topViewController?.presentedViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
return topViewController
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DeepLinkController
|
||||||
|
{
|
||||||
|
@discardableResult func handle(_ deepLink: DeepLink) -> Bool
|
||||||
|
{
|
||||||
|
guard let action = deepLink.action else { return false }
|
||||||
|
|
||||||
|
switch action
|
||||||
|
{
|
||||||
|
case .launchGame(let identifier): return self.launchGame(withIdentifier: identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension DeepLinkController
|
||||||
|
{
|
||||||
|
func launchGame(withIdentifier identifier: String) -> Bool
|
||||||
|
{
|
||||||
|
guard let topViewController = self.topViewController, topViewController.allowsDeepLinkingDismissal else { return false }
|
||||||
|
|
||||||
|
let fetchRequest: NSFetchRequest<Game> = Game.fetchRequest()
|
||||||
|
fetchRequest.predicate = NSPredicate(format: "%K == %@", #keyPath(Game.identifier), identifier)
|
||||||
|
fetchRequest.returnsObjectsAsFaults = false
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
guard let game = try DatabaseManager.shared.viewContext.fetch(fetchRequest).first else { return false }
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .deepLinkControllerLaunchGame, object: self, userInfo: [DeepLink.Key.game: game])
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -93,6 +93,21 @@ class GameViewController: DeltaCore.GameViewController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var _deepLinkResumingSaveState: SaveStateProtocol? {
|
||||||
|
didSet {
|
||||||
|
guard let saveState = oldValue, _deepLinkResumingSaveState == nil else { return }
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try FileManager.default.removeItem(at: saveState.fileURL)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var _isLoadingSaveState = false
|
private var _isLoadingSaveState = false
|
||||||
|
|
||||||
private var context = CIContext(options: [kCIContextWorkingColorSpace: NSNull()])
|
private var context = CIContext(options: [kCIContextWorkingColorSpace: NSNull()])
|
||||||
@ -127,6 +142,7 @@ class GameViewController: DeltaCore.GameViewController
|
|||||||
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalGameControllerDidDisconnect, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalGameControllerDidDisconnect, object: nil)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didEnterBackground(with:)), name: .UIApplicationDidEnterBackground, object: UIApplication.shared)
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didEnterBackground(with:)), name: .UIApplicationDidEnterBackground, object: UIApplication.shared)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.settingsDidChange(with:)), name: .settingsDidChange, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.settingsDidChange(with:)), name: .settingsDidChange, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.deepLinkControllerLaunchGame(with:)), name: .deepLinkControllerLaunchGame, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit
|
deinit
|
||||||
@ -364,7 +380,11 @@ extension GameViewController
|
|||||||
@IBAction private func unwindFromGamesViewController(with segue: UIStoryboardSegue)
|
@IBAction private func unwindFromGamesViewController(with segue: UIStoryboardSegue)
|
||||||
{
|
{
|
||||||
self.pausedSaveState = nil
|
self.pausedSaveState = nil
|
||||||
self.emulatorCore?.resume()
|
|
||||||
|
if let emulatorCore = self.emulatorCore, emulatorCore.state == .paused
|
||||||
|
{
|
||||||
|
emulatorCore.resume()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - KVO
|
// MARK: - KVO
|
||||||
@ -375,10 +395,39 @@ extension GameViewController
|
|||||||
|
|
||||||
guard let rawValue = change?[.oldKey] as? Int, let previousState = EmulatorCore.State(rawValue: rawValue) else { return }
|
guard let rawValue = change?[.oldKey] as? Int, let previousState = EmulatorCore.State(rawValue: rawValue) else { return }
|
||||||
|
|
||||||
|
if let saveState = _deepLinkResumingSaveState, let emulatorCore = self.emulatorCore, emulatorCore.state == .running
|
||||||
|
{
|
||||||
|
emulatorCore.pause()
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try emulatorCore.load(saveState)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
_deepLinkResumingSaveState = nil
|
||||||
|
emulatorCore.resume()
|
||||||
|
}
|
||||||
|
|
||||||
if previousState == .stopped
|
if previousState == .stopped
|
||||||
{
|
{
|
||||||
self.emulatorCore?.updateCheats()
|
self.emulatorCore?.updateCheats()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.emulatorCore?.state == .running
|
||||||
|
{
|
||||||
|
DatabaseManager.shared.performBackgroundTask { (context) in
|
||||||
|
guard let game = self.game as? Game else { return }
|
||||||
|
|
||||||
|
let backgroundGame = context.object(with: game.objectID) as! Game
|
||||||
|
backgroundGame.playedDate = Date()
|
||||||
|
|
||||||
|
context.saveWithErrorLogging()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -812,7 +861,8 @@ extension GameViewController: GameViewControllerDelegate
|
|||||||
|
|
||||||
func gameViewControllerShouldResumeEmulation(_ gameViewController: DeltaCore.GameViewController) -> Bool
|
func gameViewControllerShouldResumeEmulation(_ gameViewController: DeltaCore.GameViewController) -> Bool
|
||||||
{
|
{
|
||||||
return (self.presentedViewController == nil || self.presentedViewController?.isDisappearing == true) && !self.isSelectingSustainedButtons && self.view.window != nil
|
let result = (self.presentedViewController == nil || self.presentedViewController?.isDisappearing == true) && !self.isSelectingSustainedButtons && self.view.window != nil
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,4 +908,44 @@ private extension GameViewController
|
|||||||
case .translucentControllerSkinOpacity: self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity
|
case .translucentControllerSkinOpacity: self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc func deepLinkControllerLaunchGame(with notification: Notification)
|
||||||
|
{
|
||||||
|
guard let game = notification.userInfo?[DeepLink.Key.game] as? Game else { return }
|
||||||
|
|
||||||
|
self.game = game
|
||||||
|
|
||||||
|
if let pausedSaveState = self.pausedSaveState, game == (self.game as? Game)
|
||||||
|
{
|
||||||
|
// Launching current game via deep link, so we store a copy of the paused save state to resume when emulator core is started.
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let temporaryURL = FileManager.default.uniqueTemporaryURL()
|
||||||
|
try FileManager.default.copyItem(at: pausedSaveState.fileURL, to: temporaryURL)
|
||||||
|
|
||||||
|
_deepLinkResumingSaveState = DeltaCore.SaveState(fileURL: temporaryURL, gameType: game.type)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let pauseViewController = self.pauseViewController
|
||||||
|
{
|
||||||
|
let segue = UIStoryboardSegue(identifier: "unwindFromPauseMenu", source: pauseViewController, destination: self)
|
||||||
|
self.unwindFromPauseViewController(segue)
|
||||||
|
}
|
||||||
|
else if
|
||||||
|
let navigationController = self.presentedViewController as? UINavigationController,
|
||||||
|
let pageViewController = navigationController.topViewController?.childViewControllers.first as? UIPageViewController,
|
||||||
|
let gameCollectionViewController = pageViewController.viewControllers?.first as? GameCollectionViewController
|
||||||
|
{
|
||||||
|
let segue = UIStoryboardSegue(identifier: "unwindFromGames", source: gameCollectionViewController, destination: self)
|
||||||
|
self.unwindFromGamesViewController(with: segue)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dismiss(animated: true, completion: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -200,6 +200,8 @@ private extension GamesViewController
|
|||||||
searchResultsController?.dataSource.predicate = searchValue.predicate
|
searchResultsController?.dataSource.predicate = searchValue.predicate
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
self.searchController?.searchBar.barStyle = .black
|
||||||
|
|
||||||
self.navigationItem.searchController = self.searchController
|
self.navigationItem.searchController = self.searchController
|
||||||
self.navigationItem.hidesSearchBarWhenScrolling = false
|
self.navigationItem.hidesSearchBarWhenScrolling = false
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import Roxas
|
||||||
|
|
||||||
class LaunchViewController: UIViewController
|
class LaunchViewController: UIViewController
|
||||||
{
|
{
|
||||||
@ -15,6 +16,8 @@ class LaunchViewController: UIViewController
|
|||||||
|
|
||||||
private var presentedGameViewController: Bool = false
|
private var presentedGameViewController: Bool = false
|
||||||
|
|
||||||
|
private var applicationLaunchDeepLinkGame: Game?
|
||||||
|
|
||||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||||
return self.gameViewController?.preferredStatusBarStyle ?? .lightContent
|
return self.gameViewController?.preferredStatusBarStyle ?? .lightContent
|
||||||
}
|
}
|
||||||
@ -27,6 +30,13 @@ class LaunchViewController: UIViewController
|
|||||||
return self.gameViewController
|
return self.gameViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required init?(coder aDecoder: NSCoder)
|
||||||
|
{
|
||||||
|
super.init(coder: aDecoder)
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(LaunchViewController.deepLinkControllerLaunchGame(with:)), name: .deepLinkControllerLaunchGame, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool)
|
override func viewDidAppear(_ animated: Bool)
|
||||||
{
|
{
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
@ -35,10 +45,33 @@ class LaunchViewController: UIViewController
|
|||||||
{
|
{
|
||||||
self.presentedGameViewController = true
|
self.presentedGameViewController = true
|
||||||
|
|
||||||
self.gameViewController.performSegue(withIdentifier: "showInitialGamesViewController", sender: nil)
|
func showGameViewController()
|
||||||
self.transitionCoordinator?.animate(alongsideTransition: nil, completion: { (context) in
|
{
|
||||||
self.view.bringSubview(toFront: self.gameViewContainerView)
|
self.view.bringSubview(toFront: self.gameViewContainerView)
|
||||||
})
|
|
||||||
|
self.setNeedsStatusBarAppearanceUpdate()
|
||||||
|
|
||||||
|
if #available(iOS 11.0, *)
|
||||||
|
{
|
||||||
|
self.setNeedsUpdateOfHomeIndicatorAutoHidden()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let game = self.applicationLaunchDeepLinkGame
|
||||||
|
{
|
||||||
|
self.gameViewController.game = game
|
||||||
|
|
||||||
|
UIView.transition(with: self.view, duration: 0.3, options: [.transitionCrossDissolve], animations: {
|
||||||
|
showGameViewController()
|
||||||
|
}, completion: nil)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.gameViewController.performSegue(withIdentifier: "showInitialGamesViewController", sender: nil)
|
||||||
|
self.transitionCoordinator?.animate(alongsideTransition: nil, completion: { (context) in
|
||||||
|
showGameViewController()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,3 +82,15 @@ class LaunchViewController: UIViewController
|
|||||||
self.gameViewController = segue.destination as! GameViewController
|
self.gameViewController = segue.destination as! GameViewController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extension LaunchViewController
|
||||||
|
{
|
||||||
|
@objc func deepLinkControllerLaunchGame(with notification: Notification)
|
||||||
|
{
|
||||||
|
guard !self.presentedGameViewController else { return }
|
||||||
|
|
||||||
|
guard let game = notification.userInfo?[DeepLink.Key.game] as? Game else { return }
|
||||||
|
|
||||||
|
self.applicationLaunchDeepLinkGame = game
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -130,11 +130,11 @@ extension SaveStatesViewController
|
|||||||
self.navigationController?.toolbar.barStyle = .blackTranslucent
|
self.navigationController?.toolbar.barStyle = .blackTranslucent
|
||||||
|
|
||||||
self.updateTheme()
|
self.updateTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidDisappear(_ animated: Bool)
|
override func viewWillDisappear(_ animated: Bool)
|
||||||
{
|
{
|
||||||
super.viewDidDisappear(animated)
|
super.viewWillDisappear(animated)
|
||||||
|
|
||||||
self.resetEmulatorCoreIfNeeded()
|
self.resetEmulatorCoreIfNeeded()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,355 @@
|
|||||||
|
//
|
||||||
|
// AppIconShortcutsViewController.swift
|
||||||
|
// Delta
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 12/19/17.
|
||||||
|
// Copyright © 2017 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
import DeltaCore
|
||||||
|
|
||||||
|
import Roxas
|
||||||
|
|
||||||
|
@objc(SwitchTableViewCell)
|
||||||
|
private class SwitchTableViewCell: UITableViewCell
|
||||||
|
{
|
||||||
|
@IBOutlet var switchView: UISwitch!
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppIconShortcutsViewController: UITableViewController
|
||||||
|
{
|
||||||
|
private lazy var dataSource = RSTCompositeTableViewPrefetchingDataSource<Game, UIImage>(dataSources: [self.modeDataSource, self.shortcutsDataSource, self.gamesDataSource])
|
||||||
|
private let modeDataSource = RSTDynamicTableViewDataSource<Game>()
|
||||||
|
private let shortcutsDataSource = RSTArrayTableViewPrefetchingDataSource<Game, UIImage>(items: [])
|
||||||
|
private let gamesDataSource = RSTFetchedResultsTableViewPrefetchingDataSource<Game, UIImage>(fetchedResultsController: NSFetchedResultsController())
|
||||||
|
|
||||||
|
required init?(coder aDecoder: NSCoder)
|
||||||
|
{
|
||||||
|
super.init(coder: aDecoder)
|
||||||
|
|
||||||
|
self.prepareDataSource()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad()
|
||||||
|
{
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
self.tableView.register(GameTableViewCell.nib!, forCellReuseIdentifier: RSTCellContentGenericCellIdentifier)
|
||||||
|
|
||||||
|
if #available(iOS 11, *)
|
||||||
|
{
|
||||||
|
self.navigationItem.searchController = self.gamesDataSource.searchController
|
||||||
|
self.navigationItem.hidesSearchBarWhenScrolling = false
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.tableView.tableHeaderView = self.gamesDataSource.searchController.searchBar
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tableView.dataSource = self.dataSource
|
||||||
|
self.tableView.allowsSelectionDuringEditing = true
|
||||||
|
|
||||||
|
self.updateShortcuts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension AppIconShortcutsViewController
|
||||||
|
{
|
||||||
|
func prepareDataSource()
|
||||||
|
{
|
||||||
|
// Mode
|
||||||
|
self.modeDataSource.numberOfSectionsHandler = { 1 }
|
||||||
|
self.modeDataSource.numberOfItemsHandler = { _ in 1 }
|
||||||
|
self.modeDataSource.cellIdentifierHandler = { _ in "SwitchCell" }
|
||||||
|
|
||||||
|
// Shortcuts
|
||||||
|
self.shortcutsDataSource.items = Settings.gameShortcuts
|
||||||
|
|
||||||
|
// Games
|
||||||
|
let gamesFetchRequest: NSFetchRequest<Game> = Game.fetchRequest()
|
||||||
|
gamesFetchRequest.returnsObjectsAsFaults = false
|
||||||
|
gamesFetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Game.type, ascending: true), NSSortDescriptor(key: #keyPath(Game.name), ascending: true)]
|
||||||
|
|
||||||
|
let gamesFetchedResultsController = NSFetchedResultsController(fetchRequest: gamesFetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(Game.type), cacheName: nil)
|
||||||
|
self.gamesDataSource.fetchedResultsController = gamesFetchedResultsController
|
||||||
|
self.gamesDataSource.searchController.searchableKeyPaths = [#keyPath(Game.name)]
|
||||||
|
|
||||||
|
// Data Source
|
||||||
|
self.dataSource.proxy = self
|
||||||
|
self.dataSource.cellConfigurationHandler = { [unowned self] (cell, game, indexPath) in
|
||||||
|
if indexPath.section == 0
|
||||||
|
{
|
||||||
|
self.configureModeCell(cell as! SwitchTableViewCell, for: indexPath)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.configureGameCell(cell as! GameTableViewCell, with: game, for: indexPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.dataSource.prefetchHandler = { (game, indexPath, completionHandler) in
|
||||||
|
guard indexPath.section > 0 else { return nil }
|
||||||
|
|
||||||
|
guard let artworkURL = game.artworkURL else { return nil }
|
||||||
|
|
||||||
|
let imageOperation = LoadImageURLOperation(url: artworkURL)
|
||||||
|
imageOperation.resultHandler = { (image, error) in
|
||||||
|
completionHandler(image, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageOperation
|
||||||
|
}
|
||||||
|
self.dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in
|
||||||
|
guard indexPath.section > 0 else { return }
|
||||||
|
|
||||||
|
guard let image = image else { return }
|
||||||
|
|
||||||
|
let cell = cell as! GameTableViewCell
|
||||||
|
|
||||||
|
let artworkDisplaySize = AVMakeRect(aspectRatio: image.size, insideRect: cell.artworkImageView.bounds)
|
||||||
|
let offset = (cell.artworkImageView.bounds.width - artworkDisplaySize.width) / 2
|
||||||
|
|
||||||
|
// Offset artworkImageViewLeadingConstraint and artworkImageViewTrailingConstraint to right-align artworkImageView
|
||||||
|
cell.artworkImageViewLeadingConstraint.constant += offset
|
||||||
|
cell.artworkImageViewTrailingConstraint.constant -= offset
|
||||||
|
|
||||||
|
cell.artworkImageView.image = image
|
||||||
|
cell.artworkImageView.superview?.layoutIfNeeded()
|
||||||
|
}
|
||||||
|
self.dataSource.rowAnimation = .fade
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureModeCell(_ cell: SwitchTableViewCell, for indexPath: IndexPath)
|
||||||
|
{
|
||||||
|
cell.textLabel?.text = NSLocalizedString("Recently Played Games", comment: "")
|
||||||
|
cell.textLabel?.backgroundColor = .clear
|
||||||
|
|
||||||
|
cell.switchView.isOn = (Settings.gameShortcutsMode == .recent)
|
||||||
|
cell.switchView.onTintColor = self.view.tintColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureGameCell(_ cell: GameTableViewCell, with game: Game, for indexPath: IndexPath)
|
||||||
|
{
|
||||||
|
cell.nameLabel.textColor = .darkText
|
||||||
|
cell.backgroundColor = .white
|
||||||
|
|
||||||
|
cell.nameLabel.text = game.name
|
||||||
|
cell.artworkImageView.image = #imageLiteral(resourceName: "BoxArt")
|
||||||
|
|
||||||
|
cell.artworkImageViewLeadingConstraint.constant = 15
|
||||||
|
cell.artworkImageViewTrailingConstraint.constant = 15
|
||||||
|
|
||||||
|
cell.separatorInset.left = cell.nameLabel.frame.minX
|
||||||
|
|
||||||
|
cell.selectedBackgroundView = nil
|
||||||
|
|
||||||
|
switch (indexPath.section, Settings.gameShortcutsMode)
|
||||||
|
{
|
||||||
|
case (1, _):
|
||||||
|
cell.selectionStyle = .none
|
||||||
|
cell.contentView.alpha = 1.0
|
||||||
|
|
||||||
|
case (2..., .recent):
|
||||||
|
cell.selectionStyle = .none
|
||||||
|
cell.contentView.alpha = 0.3
|
||||||
|
|
||||||
|
case (2..., .manual):
|
||||||
|
cell.selectionStyle = .gray
|
||||||
|
cell.contentView.alpha = 1.0
|
||||||
|
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension AppIconShortcutsViewController
|
||||||
|
{
|
||||||
|
func updateShortcuts()
|
||||||
|
{
|
||||||
|
switch Settings.gameShortcutsMode
|
||||||
|
{
|
||||||
|
case .recent:
|
||||||
|
let fetchRequest = Game.recentlyPlayedFetchRequest
|
||||||
|
fetchRequest.returnsObjectsAsFaults = false
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let games = try DatabaseManager.shared.viewContext.fetch(fetchRequest)
|
||||||
|
self.shortcutsDataSource.setItems(games, with: [])
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tableView.setEditing(false, animated: true)
|
||||||
|
|
||||||
|
case .manual: self.tableView.setEditing(true, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings.gameShortcuts = self.shortcutsDataSource.items
|
||||||
|
}
|
||||||
|
|
||||||
|
func addShortcut(for game: Game)
|
||||||
|
{
|
||||||
|
guard self.shortcutsDataSource.items.count < 4 else { return }
|
||||||
|
|
||||||
|
guard !self.shortcutsDataSource.items.contains(game) else { return }
|
||||||
|
|
||||||
|
// No need to adjust destinationIndexPath, since it forwards change directly to table view.
|
||||||
|
let destinationIndexPath = IndexPath(row: self.shortcutsDataSource.items.count, section: 1)
|
||||||
|
|
||||||
|
let insertion = RSTCellContentChange(type: .insert, currentIndexPath: nil, destinationIndexPath: destinationIndexPath)
|
||||||
|
insertion.rowAnimation = .fade
|
||||||
|
|
||||||
|
var shortcuts = self.shortcutsDataSource.items
|
||||||
|
shortcuts.insert(game, at: destinationIndexPath.row)
|
||||||
|
self.shortcutsDataSource.setItems(shortcuts, with: [insertion])
|
||||||
|
|
||||||
|
self.updateShortcuts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension AppIconShortcutsViewController
|
||||||
|
{
|
||||||
|
@IBAction func switchGameShortcutsMode(with sender: UISwitch)
|
||||||
|
{
|
||||||
|
if sender.isOn
|
||||||
|
{
|
||||||
|
Settings.gameShortcutsMode = .recent
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Settings.gameShortcutsMode = .manual
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tableView.beginUpdates()
|
||||||
|
|
||||||
|
self.updateShortcuts()
|
||||||
|
self.tableView.reloadSections(IndexSet(integersIn: 0 ..< self.tableView.numberOfSections), with: .fade)
|
||||||
|
|
||||||
|
self.tableView.endUpdates()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AppIconShortcutsViewController
|
||||||
|
{
|
||||||
|
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
|
||||||
|
{
|
||||||
|
guard indexPath.section == 0 else { return super.tableView(tableView, heightForRowAt: indexPath) }
|
||||||
|
|
||||||
|
return 44
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
|
||||||
|
{
|
||||||
|
switch section
|
||||||
|
{
|
||||||
|
case 0: return nil
|
||||||
|
case 1: return NSLocalizedString("Shortcuts", comment: "")
|
||||||
|
default:
|
||||||
|
let gameType = GameType(rawValue: self.gamesDataSource.fetchedResultsController.sections![section - 2].name)
|
||||||
|
|
||||||
|
let system = System(gameType: gameType)!
|
||||||
|
return system.localizedName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
|
||||||
|
{
|
||||||
|
switch (section, Settings.gameShortcutsMode)
|
||||||
|
{
|
||||||
|
case (0, .recent): return NSLocalizedString("Your most recently played games will appear as shortcuts when 3D touching the app icon.", comment: "")
|
||||||
|
case (0, .manual): return NSLocalizedString("The games you've selected below will appear as shortcuts when 3D touching the app icon.", comment: "")
|
||||||
|
case (1, .recent): return " " // Return non-empty string since empty string changes vertical offset of section for some reason.
|
||||||
|
case (1, .manual): return NSLocalizedString("You may have up to 4 shortcuts.", comment: "")
|
||||||
|
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
|
||||||
|
{
|
||||||
|
guard indexPath.section > 1 else { return }
|
||||||
|
|
||||||
|
guard Settings.gameShortcutsMode == .manual else { return }
|
||||||
|
|
||||||
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
|
|
||||||
|
let game = self.dataSource.item(at: indexPath)
|
||||||
|
self.addShortcut(for: game)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
|
||||||
|
{
|
||||||
|
switch editingStyle
|
||||||
|
{
|
||||||
|
case .none: break
|
||||||
|
case .delete:
|
||||||
|
let deletion = RSTCellContentChange(type: .delete, currentIndexPath: indexPath, destinationIndexPath: nil)
|
||||||
|
deletion.rowAnimation = .fade
|
||||||
|
|
||||||
|
var shortcuts = self.shortcutsDataSource.items
|
||||||
|
shortcuts.remove(at: indexPath.row) // No need to adjust indexPath, since it forwards change directly to table view.
|
||||||
|
self.shortcutsDataSource.setItems(shortcuts, with: [deletion])
|
||||||
|
|
||||||
|
case .insert:
|
||||||
|
let game = self.dataSource.item(at: indexPath)
|
||||||
|
self.addShortcut(for: game)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.updateShortcuts()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String?
|
||||||
|
{
|
||||||
|
return NSLocalizedString("Remove", comment: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle
|
||||||
|
{
|
||||||
|
switch indexPath.section
|
||||||
|
{
|
||||||
|
case 1: return .delete
|
||||||
|
case 2...: return .insert
|
||||||
|
default: return .none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool
|
||||||
|
{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool
|
||||||
|
{
|
||||||
|
return (indexPath.section == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath
|
||||||
|
{
|
||||||
|
let indexPath: IndexPath
|
||||||
|
|
||||||
|
switch proposedDestinationIndexPath.section
|
||||||
|
{
|
||||||
|
case 0: indexPath = IndexPath(row: 0, section: 1)
|
||||||
|
case 1: indexPath = proposedDestinationIndexPath
|
||||||
|
default: indexPath = IndexPath(row: self.shortcutsDataSource.items.count - 1, section: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return indexPath
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
|
||||||
|
{
|
||||||
|
var items = self.shortcutsDataSource.items
|
||||||
|
|
||||||
|
let game = items.remove(at: sourceIndexPath.row)
|
||||||
|
items.insert(game, at: destinationIndexPath.row)
|
||||||
|
|
||||||
|
self.shortcutsDataSource.items = items
|
||||||
|
|
||||||
|
self.updateShortcuts()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,6 +35,15 @@ extension Settings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Settings
|
||||||
|
{
|
||||||
|
enum GameShortcutsMode: String
|
||||||
|
{
|
||||||
|
case recent
|
||||||
|
case manual
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Settings
|
struct Settings
|
||||||
{
|
{
|
||||||
/// Controllers
|
/// Controllers
|
||||||
@ -66,9 +75,54 @@ struct Settings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var gameShortcutsMode: GameShortcutsMode {
|
||||||
|
set { UserDefaults.standard.gameShortcutsMode = newValue.rawValue }
|
||||||
|
get {
|
||||||
|
let mode = GameShortcutsMode(rawValue: UserDefaults.standard.gameShortcutsMode) ?? .recent
|
||||||
|
return mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static var gameShortcuts: [Game] {
|
||||||
|
set {
|
||||||
|
let identifiers = newValue.map { $0.identifier }
|
||||||
|
UserDefaults.standard.gameShortcutIdentifiers = identifiers
|
||||||
|
|
||||||
|
let shortcuts = newValue.map { UIApplicationShortcutItem(localizedTitle: $0.name, action: .launchGame(identifier: $0.identifier)) }
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
UIApplication.shared.shortcutItems = shortcuts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get {
|
||||||
|
let identifiers = UserDefaults.standard.gameShortcutIdentifiers
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
let fetchRequest: NSFetchRequest<Game> = Game.fetchRequest()
|
||||||
|
fetchRequest.predicate = NSPredicate(format: "%K IN %@", #keyPath(Game.identifier), identifiers)
|
||||||
|
fetchRequest.returnsObjectsAsFaults = false
|
||||||
|
|
||||||
|
let games = try DatabaseManager.shared.viewContext.fetch(fetchRequest).sorted(by: { (game1, game2) -> Bool in
|
||||||
|
let index1 = identifiers.index(of: game1.identifier)!
|
||||||
|
let index2 = identifiers.index(of: game2.identifier)!
|
||||||
|
return index1 < index2
|
||||||
|
})
|
||||||
|
|
||||||
|
return games
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static func registerDefaults()
|
static func registerDefaults()
|
||||||
{
|
{
|
||||||
let defaults = [#keyPath(UserDefaults.translucentControllerSkinOpacity): 0.7]
|
let defaults = [#keyPath(UserDefaults.translucentControllerSkinOpacity): 0.7, #keyPath(UserDefaults.gameShortcutsMode): GameShortcutsMode.recent.rawValue] as [String : Any]
|
||||||
UserDefaults.standard.register(defaults: defaults)
|
UserDefaults.standard.register(defaults: defaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,4 +217,7 @@ private extension UserDefaults
|
|||||||
{
|
{
|
||||||
@NSManaged var translucentControllerSkinOpacity: CGFloat
|
@NSManaged var translucentControllerSkinOpacity: CGFloat
|
||||||
@NSManaged var previousGameCollectionIdentifier: String?
|
@NSManaged var previousGameCollectionIdentifier: String?
|
||||||
|
|
||||||
|
@NSManaged var gameShortcutsMode: String
|
||||||
|
@NSManaged var gameShortcutIdentifiers: [String]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ private extension SettingsViewController
|
|||||||
case controllers
|
case controllers
|
||||||
case controllerSkins
|
case controllerSkins
|
||||||
case controllerOpacity
|
case controllerOpacity
|
||||||
|
case threeDTouch
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Segue: String
|
enum Segue: String
|
||||||
@ -130,6 +131,15 @@ private extension SettingsViewController
|
|||||||
let percentage = String(format: "%.f", Settings.translucentControllerSkinOpacity * 100) + "%"
|
let percentage = String(format: "%.f", Settings.translucentControllerSkinOpacity * 100) + "%"
|
||||||
self.controllerOpacityLabel.text = percentage
|
self.controllerOpacityLabel.text = percentage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isSectionHidden(_ section: Section) -> Bool
|
||||||
|
{
|
||||||
|
switch section
|
||||||
|
{
|
||||||
|
case .threeDTouch: return self.view.traitCollection.forceTouchCapability != .available
|
||||||
|
default: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension SettingsViewController
|
private extension SettingsViewController
|
||||||
@ -183,7 +193,15 @@ extension SettingsViewController
|
|||||||
{
|
{
|
||||||
case .controllers: return 1 // Temporarily hide other controller indexes until controller logic is finalized
|
case .controllers: return 1 // Temporarily hide other controller indexes until controller logic is finalized
|
||||||
case .controllerSkins: return System.supportedSystems.count
|
case .controllerSkins: return System.supportedSystems.count
|
||||||
default: return super.tableView(tableView, numberOfRowsInSection: sectionIndex)
|
default:
|
||||||
|
if isSectionHidden(section)
|
||||||
|
{
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return super.tableView(tableView, numberOfRowsInSection: sectionIndex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +244,64 @@ extension SettingsViewController
|
|||||||
case Section.controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell)
|
case Section.controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell)
|
||||||
case Section.controllerSkins: self.performSegue(withIdentifier: Segue.controllerSkins.rawValue, sender: cell)
|
case Section.controllerSkins: self.performSegue(withIdentifier: Segue.controllerSkins.rawValue, sender: cell)
|
||||||
case Section.controllerOpacity: break
|
case Section.controllerOpacity: break
|
||||||
|
case Section.threeDTouch: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
|
||||||
|
{
|
||||||
|
let section = Section(rawValue: section)!
|
||||||
|
|
||||||
|
if isSectionHidden(section)
|
||||||
|
{
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return super.tableView(tableView, titleForHeaderInSection: section.rawValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
|
||||||
|
{
|
||||||
|
let section = Section(rawValue: section)!
|
||||||
|
|
||||||
|
if isSectionHidden(section)
|
||||||
|
{
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return super.tableView(tableView, titleForFooterInSection: section.rawValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
|
||||||
|
{
|
||||||
|
let section = Section(rawValue: section)!
|
||||||
|
|
||||||
|
if isSectionHidden(section)
|
||||||
|
{
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return super.tableView(tableView, heightForHeaderInSection: section.rawValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
|
||||||
|
{
|
||||||
|
let section = Section(rawValue: section)!
|
||||||
|
|
||||||
|
if isSectionHidden(section)
|
||||||
|
{
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return super.tableView(tableView, heightForFooterInSection: section.rawValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
External/Roxas
vendored
2
External/Roxas
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 97b3a7ab05ee320d3c96eadc3cc69c38d10ec206
|
Subproject commit a903b123e1136d77c8b4f4b0e5f78700160f3e97
|
||||||
Loading…
Reference in New Issue
Block a user