Shows source errors in SourcesViewController

This commit is contained in:
Riley Testut
2020-08-27 16:39:03 -07:00
parent b7564207b3
commit 4c3d33efdc
13 changed files with 158 additions and 17 deletions

View File

@@ -127,6 +127,7 @@
BF4C7F2523801F0800B2556E /* AltSign.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9B63C5229DD44D002F0A62 /* AltSign.framework */; }; BF4C7F2523801F0800B2556E /* AltSign.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9B63C5229DD44D002F0A62 /* AltSign.framework */; };
BF4E8456246F16D700ECCBD4 /* Bundle+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */; }; BF4E8456246F16D700ECCBD4 /* Bundle+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */; };
BF54E8212315EF0D000AE0D8 /* ALTPatreonBenefitType.m in Sources */ = {isa = PBXBuildFile; fileRef = BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */; }; BF54E8212315EF0D000AE0D8 /* ALTPatreonBenefitType.m in Sources */ = {isa = PBXBuildFile; fileRef = BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */; };
BF56333824EC5E9A00038F00 /* SecureValueTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56333724EC5E9A00038F00 /* SecureValueTransformer.swift */; };
BF56D2AA23DF88310006506D /* AppID.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2A923DF88310006506D /* AppID.swift */; }; BF56D2AA23DF88310006506D /* AppID.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2A923DF88310006506D /* AppID.swift */; };
BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */; }; BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */; };
BF56D2AF23DF9E310006506D /* AppIDsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AE23DF9E310006506D /* AppIDsViewController.swift */; }; BF56D2AF23DF9E310006506D /* AppIDsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AE23DF9E310006506D /* AppIDsViewController.swift */; };
@@ -136,11 +137,11 @@
BF58048A246A28F9008AE704 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF580488246A28F9008AE704 /* LaunchScreen.storyboard */; }; BF58048A246A28F9008AE704 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF580488246A28F9008AE704 /* LaunchScreen.storyboard */; };
BF580496246A3CB5008AE704 /* UIColor+AltBackup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF580495246A3CB5008AE704 /* UIColor+AltBackup.swift */; }; BF580496246A3CB5008AE704 /* UIColor+AltBackup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF580495246A3CB5008AE704 /* UIColor+AltBackup.swift */; };
BF580498246A3D19008AE704 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF580497246A3D19008AE704 /* UIKit.framework */; }; BF580498246A3D19008AE704 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF580497246A3D19008AE704 /* UIKit.framework */; };
BF58049B246A432D008AE704 /* NSError+LocalizedFailure.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C336124197D700034FD24 /* NSError+LocalizedFailure.swift */; }; BF58049B246A432D008AE704 /* NSError+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C336124197D700034FD24 /* NSError+AltStore.swift */; };
BF5C5FCF237DF69100EDD0C6 /* ALTPluginService.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5C5FCE237DF69100EDD0C6 /* ALTPluginService.m */; }; BF5C5FCF237DF69100EDD0C6 /* ALTPluginService.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5C5FCE237DF69100EDD0C6 /* ALTPluginService.m */; };
BF663C4F2433ED8200DAA738 /* FileManager+DirectorySize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */; }; BF663C4F2433ED8200DAA738 /* FileManager+DirectorySize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */; };
BF6A5320246DC1B0004F59C8 /* FileManager+SharedDirectories.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */; }; BF6A5320246DC1B0004F59C8 /* FileManager+SharedDirectories.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */; };
BF6C336224197D700034FD24 /* NSError+LocalizedFailure.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C336124197D700034FD24 /* NSError+LocalizedFailure.swift */; }; BF6C336224197D700034FD24 /* NSError+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C336124197D700034FD24 /* NSError+AltStore.swift */; };
BF6C33652419AE310034FD24 /* AltStore4ToAltStore5.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF6C33642419AE310034FD24 /* AltStore4ToAltStore5.xcmappingmodel */; }; BF6C33652419AE310034FD24 /* AltStore4ToAltStore5.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF6C33642419AE310034FD24 /* AltStore4ToAltStore5.xcmappingmodel */; };
BF6C8FAC242935ED00125131 /* NSAttributedString+Markdown.m in Sources */ = {isa = PBXBuildFile; fileRef = BF6C8FAA242935ED00125131 /* NSAttributedString+Markdown.m */; }; BF6C8FAC242935ED00125131 /* NSAttributedString+Markdown.m in Sources */ = {isa = PBXBuildFile; fileRef = BF6C8FAA242935ED00125131 /* NSAttributedString+Markdown.m */; };
BF6C8FAE2429597900125131 /* BannerCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C8FAD2429597900125131 /* BannerCollectionViewCell.swift */; }; BF6C8FAE2429597900125131 /* BannerCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C8FAD2429597900125131 /* BannerCollectionViewCell.swift */; };
@@ -479,6 +480,7 @@
BF4713A422976CFC00784A2F /* openssl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = openssl.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BF4713A422976CFC00784A2F /* openssl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = openssl.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BF54E81F2315EF0D000AE0D8 /* ALTPatreonBenefitType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTPatreonBenefitType.h; sourceTree = "<group>"; }; BF54E81F2315EF0D000AE0D8 /* ALTPatreonBenefitType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTPatreonBenefitType.h; sourceTree = "<group>"; };
BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTPatreonBenefitType.m; sourceTree = "<group>"; }; BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTPatreonBenefitType.m; sourceTree = "<group>"; };
BF56333724EC5E9A00038F00 /* SecureValueTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureValueTransformer.swift; sourceTree = "<group>"; };
BF56D2A823DF87570006506D /* AltStore 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 4.xcdatamodel"; sourceTree = "<group>"; }; BF56D2A823DF87570006506D /* AltStore 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 4.xcdatamodel"; sourceTree = "<group>"; };
BF56D2A923DF88310006506D /* AppID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppID.swift; sourceTree = "<group>"; }; BF56D2A923DF88310006506D /* AppID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppID.swift; sourceTree = "<group>"; };
BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchAppIDsOperation.swift; sourceTree = "<group>"; }; BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchAppIDsOperation.swift; sourceTree = "<group>"; };
@@ -499,7 +501,7 @@
BF5C5FCE237DF69100EDD0C6 /* ALTPluginService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTPluginService.m; sourceTree = "<group>"; }; BF5C5FCE237DF69100EDD0C6 /* ALTPluginService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTPluginService.m; sourceTree = "<group>"; };
BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+DirectorySize.swift"; sourceTree = "<group>"; }; BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+DirectorySize.swift"; sourceTree = "<group>"; };
BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+SharedDirectories.swift"; sourceTree = "<group>"; }; BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+SharedDirectories.swift"; sourceTree = "<group>"; };
BF6C336124197D700034FD24 /* NSError+LocalizedFailure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSError+LocalizedFailure.swift"; sourceTree = "<group>"; }; BF6C336124197D700034FD24 /* NSError+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSError+AltStore.swift"; sourceTree = "<group>"; };
BF6C33632419ADEB0034FD24 /* AltStore 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 5.xcdatamodel"; sourceTree = "<group>"; }; BF6C33632419ADEB0034FD24 /* AltStore 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 5.xcdatamodel"; sourceTree = "<group>"; };
BF6C33642419AE310034FD24 /* AltStore4ToAltStore5.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore4ToAltStore5.xcmappingmodel; sourceTree = "<group>"; }; BF6C33642419AE310034FD24 /* AltStore4ToAltStore5.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore4ToAltStore5.xcmappingmodel; sourceTree = "<group>"; };
BF6C8FAA242935ED00125131 /* NSAttributedString+Markdown.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributedString+Markdown.m"; path = "Dependencies/MarkdownAttributedString/NSAttributedString+Markdown.m"; sourceTree = SOURCE_ROOT; }; BF6C8FAA242935ED00125131 /* NSAttributedString+Markdown.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributedString+Markdown.m"; path = "Dependencies/MarkdownAttributedString/NSAttributedString+Markdown.m"; sourceTree = SOURCE_ROOT; };
@@ -1266,6 +1268,7 @@
BFBBE2DB22931B20002097FA /* AltStore.xcdatamodeld */, BFBBE2DB22931B20002097FA /* AltStore.xcdatamodeld */,
BFB11691229322E400BB457C /* DatabaseManager.swift */, BFB11691229322E400BB457C /* DatabaseManager.swift */,
BF3D64A122E8031100E9056B /* MergePolicy.swift */, BF3D64A122E8031100E9056B /* MergePolicy.swift */,
BF56333724EC5E9A00038F00 /* SecureValueTransformer.swift */,
BFE6326722A858F300F30809 /* Account.swift */, BFE6326722A858F300F30809 /* Account.swift */,
BF56D2A923DF88310006506D /* AppID.swift */, BF56D2A923DF88310006506D /* AppID.swift */,
BF3D648722E79A3700E9056B /* AppPermission.swift */, BF3D648722E79A3700E9056B /* AppPermission.swift */,
@@ -1291,7 +1294,7 @@
BF9ABA4E22DD41A9008935CF /* UIColor+Hex.swift */, BF9ABA4E22DD41A9008935CF /* UIColor+Hex.swift */,
BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */, BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */,
BFF0B6992322D7D0007A79E1 /* UIScreen+CompactHeight.swift */, BFF0B6992322D7D0007A79E1 /* UIScreen+CompactHeight.swift */,
BF6C336124197D700034FD24 /* NSError+LocalizedFailure.swift */, BF6C336124197D700034FD24 /* NSError+AltStore.swift */,
BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */, BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */,
BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */, BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */,
BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */, BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */,
@@ -2005,7 +2008,7 @@
BF580496246A3CB5008AE704 /* UIColor+AltBackup.swift in Sources */, BF580496246A3CB5008AE704 /* UIColor+AltBackup.swift in Sources */,
BF580482246A28F7008AE704 /* ViewController.swift in Sources */, BF580482246A28F7008AE704 /* ViewController.swift in Sources */,
BF44EEF0246B08BA002A52F2 /* BackupController.swift in Sources */, BF44EEF0246B08BA002A52F2 /* BackupController.swift in Sources */,
BF58049B246A432D008AE704 /* NSError+LocalizedFailure.swift in Sources */, BF58049B246A432D008AE704 /* NSError+AltStore.swift in Sources */,
BF58047E246A28F7008AE704 /* AppDelegate.swift in Sources */, BF58047E246A28F7008AE704 /* AppDelegate.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -2024,6 +2027,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
BFDB6A0F22AB2776007EA6D6 /* SendAppOperation.swift in Sources */, BFDB6A0F22AB2776007EA6D6 /* SendAppOperation.swift in Sources */,
BF56333824EC5E9A00038F00 /* SecureValueTransformer.swift in Sources */,
BFDB6A0D22AAFC1A007EA6D6 /* OperationError.swift in Sources */, BFDB6A0D22AAFC1A007EA6D6 /* OperationError.swift in Sources */,
BF74989B23621C0700CED65F /* ForwardingNavigationController.swift in Sources */, BF74989B23621C0700CED65F /* ForwardingNavigationController.swift in Sources */,
BF3D649D22E7AC1B00E9056B /* PermissionPopoverViewController.swift in Sources */, BF3D649D22E7AC1B00E9056B /* PermissionPopoverViewController.swift in Sources */,
@@ -2061,7 +2065,7 @@
BFF0B68E23219520007A79E1 /* PatreonViewController.swift in Sources */, BFF0B68E23219520007A79E1 /* PatreonViewController.swift in Sources */,
BFD5D6EA230CCAE5007955AB /* PatreonAccount.swift in Sources */, BFD5D6EA230CCAE5007955AB /* PatreonAccount.swift in Sources */,
BFE6326822A858F300F30809 /* Account.swift in Sources */, BFE6326822A858F300F30809 /* Account.swift in Sources */,
BF6C336224197D700034FD24 /* NSError+LocalizedFailure.swift in Sources */, BF6C336224197D700034FD24 /* NSError+AltStore.swift in Sources */,
BFE6326622A857C200F30809 /* Team.swift in Sources */, BFE6326622A857C200F30809 /* Team.swift in Sources */,
BFD2476E2284B9A500981D42 /* AppDelegate.swift in Sources */, BFD2476E2284B9A500981D42 /* AppDelegate.swift in Sources */,
BF41B806233423AE00C593A3 /* TabBarController.swift in Sources */, BF41B806233423AE00C593A3 /* TabBarController.swift in Sources */,

View File

@@ -77,6 +77,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
ServerManager.shared.startDiscovering() ServerManager.shared.startDiscovering()
SecureValueTransformer.register()
UserDefaults.standard.registerDefaults() UserDefaults.standard.registerDefaults()
if UserDefaults.standard.firstLaunch == nil if UserDefaults.standard.firstLaunch == nil

View File

@@ -1,9 +1,9 @@
<?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="16092.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="wKh-xq-NuP"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="wKh-xq-NuP">
<device id="retina4_7" orientation="portrait" appearance="light"/> <device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16082.1"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Named colors" minToolsVersion="9.0"/> <capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -38,6 +38,7 @@
<segue destination="faz-B4-Sub" kind="relationship" relationship="viewControllers" id="dXz-Tu-hW8"/> <segue destination="faz-B4-Sub" kind="relationship" relationship="viewControllers" id="dXz-Tu-hW8"/>
<segue destination="3Ew-ox-i4n" kind="relationship" relationship="viewControllers" id="zii-dF-qEt"/> <segue destination="3Ew-ox-i4n" kind="relationship" relationship="viewControllers" id="zii-dF-qEt"/>
<segue destination="p3d-dP-Swg" kind="relationship" relationship="viewControllers" id="4Nf-rL-P4c"/> <segue destination="p3d-dP-Swg" kind="relationship" relationship="viewControllers" id="4Nf-rL-P4c"/>
<segue destination="Qo4-72-Hmr" kind="presentation" identifier="presentSources" id="Qd6-ba-dIo"/>
</connections> </connections>
</tabBarController> </tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="HuB-VB-40B" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="HuB-VB-40B" sceneMemberID="firstResponder"/>
@@ -1004,7 +1005,7 @@ World</string>
</barButtonItem> </barButtonItem>
<barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="NQF-u2-PZv"> <barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="NQF-u2-PZv">
<connections> <connections>
<segue destination="zjS-Nr-VTw" kind="unwind" unwindAction="unwindToBrowseViewController:" id="VFy-hV-mNV"/> <segue destination="zjS-Nr-VTw" kind="unwind" unwindAction="unwindFromSourcesViewController:" id="la1-dJ-UhL"/>
</connections> </connections>
</barButtonItem> </barButtonItem>
</navigationItem> </navigationItem>
@@ -1034,6 +1035,7 @@ World</string>
</scene> </scene>
</scenes> </scenes>
<inferredMetricsTieBreakers> <inferredMetricsTieBreakers>
<segue reference="Qd6-ba-dIo"/>
<segue reference="cnd-KK-o60"/> <segue reference="cnd-KK-o60"/>
</inferredMetricsTieBreakers> </inferredMetricsTieBreakers>
<color key="tintColor" name="Primary"/> <color key="tintColor" name="Primary"/>
@@ -1044,7 +1046,7 @@ World</string>
<image name="News" width="19" height="20"/> <image name="News" width="19" height="20"/>
<image name="Settings" width="20" height="20"/> <image name="Settings" width="20" height="20"/>
<namedColor name="Background"> <namedColor name="Background">
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color red="0.0040000001899898052" green="0.50199997425079346" blue="0.51800000667572021" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor> </namedColor>
<namedColor name="BlurTint"> <namedColor name="BlurTint">
<color red="1" green="1" blue="1" alpha="0.30000001192092896" colorSpace="custom" customColorSpace="sRGB"/> <color red="1" green="1" blue="1" alpha="0.30000001192092896" colorSpace="custom" customColorSpace="sRGB"/>

View File

@@ -59,7 +59,7 @@ class BrowseViewController: UICollectionViewController
self.updateDataSource() self.updateDataSource()
} }
@IBAction private func unwindToBrowseViewController(_ segue: UIStoryboardSegue) @IBAction private func unwindFromSourcesViewController(_ segue: UIStoryboardSegue)
{ {
self.fetchSource() self.fetchSource()
} }
@@ -199,6 +199,7 @@ private extension BrowseViewController
if self.dataSource.itemCount > 0 if self.dataSource.itemCount > 0
{ {
let toastView = ToastView(error: error) let toastView = ToastView(error: error)
toastView.addTarget(nil, action: #selector(TabBarController.presentSources), for: .touchUpInside)
toastView.show(in: self) toastView.show(in: self)
} }

View File

@@ -10,7 +10,8 @@ import UIKit
class BannerCollectionViewCell: UICollectionViewCell class BannerCollectionViewCell: UICollectionViewCell
{ {
@IBOutlet var bannerView: AppBannerView! private(set) var errorBadge: UIView?
@IBOutlet private(set) var bannerView: AppBannerView!
override func awakeFromNib() override func awakeFromNib()
{ {
@@ -18,5 +19,36 @@ class BannerCollectionViewCell: UICollectionViewCell
self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.contentView.preservesSuperviewLayoutMargins = true self.contentView.preservesSuperviewLayoutMargins = true
if #available(iOS 13.0, *)
{
let errorBadge = UIView()
errorBadge.translatesAutoresizingMaskIntoConstraints = false
errorBadge.isHidden = true
self.addSubview(errorBadge)
// Solid background to make the X opaque white.
let backgroundView = UIView()
backgroundView.translatesAutoresizingMaskIntoConstraints = false
backgroundView.backgroundColor = .white
errorBadge.addSubview(backgroundView)
let badgeView = UIImageView(image: UIImage(systemName: "exclamationmark.circle.fill"))
badgeView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(scale: .large)
badgeView.tintColor = .systemRed
errorBadge.addSubview(badgeView, pinningEdgesWith: .zero)
NSLayoutConstraint.activate([
errorBadge.centerXAnchor.constraint(equalTo: self.bannerView.trailingAnchor, constant: -5),
errorBadge.centerYAnchor.constraint(equalTo: self.bannerView.topAnchor, constant: 5),
backgroundView.centerXAnchor.constraint(equalTo: badgeView.centerXAnchor),
backgroundView.centerYAnchor.constraint(equalTo: badgeView.centerYAnchor),
backgroundView.widthAnchor.constraint(equalTo: badgeView.widthAnchor, multiplier: 0.5),
backgroundView.heightAnchor.constraint(equalTo: badgeView.heightAnchor, multiplier: 0.5)
])
self.errorBadge = errorBadge
}
} }
} }

View File

@@ -1,5 +1,5 @@
// //
// NSError+LocalizedFailure.swift // NSError+AltStore.swift
// AltStore // AltStore
// //
// Created by Riley Testut on 3/11/20. // Created by Riley Testut on 3/11/20.
@@ -27,6 +27,21 @@ extension NSError
let error = NSError(domain: self.domain, code: self.code, userInfo: userInfo) let error = NSError(domain: self.domain, code: self.code, userInfo: userInfo)
return error return error
} }
func sanitizedForCoreData() -> NSError
{
var userInfo = self.userInfo
userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure
userInfo[NSLocalizedDescriptionKey] = self.localizedDescription
userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason
userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion
// Remove non-ObjC-compliant userInfo values.
userInfo["NSCodingPath"] = nil
let error = NSError(domain: self.domain, code: self.code, userInfo: userInfo)
return error
}
} }
protocol ALTLocalizedError: LocalizedError, CustomNSError protocol ALTLocalizedError: LocalizedError, CustomNSError

View File

@@ -220,6 +220,7 @@ extension AppManager
case .success(let source): fetchedSources.insert(source) case .success(let source): fetchedSources.insert(source)
case .failure(let error): case .failure(let error):
let source = managedObjectContext.object(with: source.objectID) as! Source let source = managedObjectContext.object(with: source.objectID) as! Source
source.error = (error as NSError).sanitizedForCoreData()
errors[source] = error errors[source] = error
} }

View File

@@ -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="16117.1" systemVersion="19D76" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier=""> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19G73" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Account" representedClassName="Account" syncable="YES"> <entity name="Account" representedClassName="Account" syncable="YES">
<attribute name="appleID" attributeType="String"/> <attribute name="appleID" attributeType="String"/>
<attribute name="firstName" attributeType="String"/> <attribute name="firstName" attributeType="String"/>
@@ -104,6 +104,7 @@
</uniquenessConstraints> </uniquenessConstraints>
</entity> </entity>
<entity name="Source" representedClassName="Source" syncable="YES"> <entity name="Source" representedClassName="Source" syncable="YES">
<attribute name="error" optional="YES" attributeType="Transformable" valueTransformerName="ALTSecureValueTransformer"/>
<attribute name="identifier" attributeType="String"/> <attribute name="identifier" attributeType="String"/>
<attribute name="name" attributeType="String"/> <attribute name="name" attributeType="String"/>
<attribute name="sourceURL" attributeType="URI"/> <attribute name="sourceURL" attributeType="URI"/>
@@ -166,7 +167,7 @@
<element name="NewsItem" positionX="-45" positionY="126" width="128" height="238"/> <element name="NewsItem" positionX="-45" positionY="126" width="128" height="238"/>
<element name="PatreonAccount" positionX="-45" positionY="117" width="128" height="105"/> <element name="PatreonAccount" positionX="-45" positionY="117" width="128" height="105"/>
<element name="RefreshAttempt" positionX="-45" positionY="117" width="128" height="105"/> <element name="RefreshAttempt" positionX="-45" positionY="117" width="128" height="105"/>
<element name="Source" positionX="-45" positionY="99" width="128" height="118"/> <element name="Source" positionX="-45" positionY="99" width="128" height="133"/>
<element name="StoreApp" positionX="-63" positionY="-18" width="128" height="343"/> <element name="StoreApp" positionX="-63" positionY="-18" width="128" height="343"/>
<element name="Team" positionX="-45" positionY="81" width="128" height="148"/> <element name="Team" positionX="-45" positionY="81" width="128" height="148"/>
</elements> </elements>

View File

@@ -0,0 +1,26 @@
//
// SecureValueTransformer.swift
// AltStore
//
// Created by Riley Testut on 8/18/20.
// Copyright © 2020 Riley Testut. All rights reserved.
//
import Foundation
@objc(ALTSecureValueTransformer)
final class SecureValueTransformer: NSSecureUnarchiveFromDataTransformer
{
static let name = NSValueTransformerName(rawValue: "ALTSecureValueTransformer")
override static var allowedTopLevelClasses: [AnyClass] {
let allowedClasses = super.allowedTopLevelClasses + [NSError.self]
return allowedClasses
}
public static func register()
{
let transformer = SecureValueTransformer()
ValueTransformer.setValueTransformer(transformer, forName: name)
}
}

View File

@@ -43,6 +43,8 @@ class Source: NSManagedObject, Fetchable, Decodable
@NSManaged var identifier: String @NSManaged var identifier: String
@NSManaged var sourceURL: URL @NSManaged var sourceURL: URL
@NSManaged var error: NSError?
/* Non-Core Data Properties */ /* Non-Core Data Properties */
var userInfo: [ALTSourceUserInfoKey: String]? var userInfo: [ALTSourceUserInfoKey: String]?

View File

@@ -99,6 +99,11 @@ class NewsViewController: UICollectionViewController
self.collectionView.contentInset.bottom = 20 self.collectionView.contentInset.bottom = 20
} }
} }
@IBAction private func unwindFromSourcesViewController(_ segue: UIStoryboardSegue)
{
self.fetchSource()
}
} }
private extension NewsViewController private extension NewsViewController
@@ -198,6 +203,7 @@ private extension NewsViewController
if self.dataSource.itemCount > 0 if self.dataSource.itemCount > 0
{ {
let toastView = ToastView(error: error) let toastView = ToastView(error: error)
toastView.addTarget(nil, action: #selector(TabBarController.presentSources), for: .touchUpInside)
toastView.show(in: self) toastView.show(in: self)
} }

View File

@@ -53,6 +53,8 @@ private extension SourcesViewController
cell.bannerView.subtitleLabel.text = source.sourceURL.absoluteString cell.bannerView.subtitleLabel.text = source.sourceURL.absoluteString
cell.bannerView.subtitleLabel.numberOfLines = 2 cell.bannerView.subtitleLabel.numberOfLines = 2
cell.errorBadge?.isHidden = (source.error == nil)
// Make sure refresh button is correct size. // Make sure refresh button is correct size.
cell.layoutIfNeeded() cell.layoutIfNeeded()
} }
@@ -98,6 +100,29 @@ private extension SourcesViewController
self.present(alertController, animated: true, completion: nil) self.present(alertController, animated: true, completion: nil)
} }
func present(_ error: Error)
{
let nsError = error as NSError
let message = nsError.userInfo[NSDebugDescriptionErrorKey] as? String ?? nsError.localizedRecoverySuggestion
let alertController = UIAlertController(title: error.localizedDescription, message: message, preferredStyle: .alert)
alertController.addAction(.ok)
self.present(alertController, animated: true, completion: nil)
}
}
extension SourcesViewController
{
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
self.collectionView.deselectItem(at: indexPath, animated: true)
let source = self.dataSource.item(at: indexPath)
guard let error = source.error else { return }
self.present(error)
}
} }
extension SourcesViewController: UICollectionViewDelegateFlowLayout extension SourcesViewController: UICollectionViewDelegateFlowLayout
@@ -134,9 +159,13 @@ extension SourcesViewController
override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration?
{ {
let source = self.dataSource.item(at: indexPath) let source = self.dataSource.item(at: indexPath)
guard source.identifier != Source.altStoreIdentifier else { return nil }
return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: nil) { (suggestedActions) -> UIMenu? in return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: nil) { (suggestedActions) -> UIMenu? in
let viewErrorAction = UIAction(title: NSLocalizedString("View Error", comment: ""), image: UIImage(systemName: "exclamationmark.circle")) { (action) in
guard let error = source.error else { return }
self.present(error)
}
let deleteAction = UIAction(title: NSLocalizedString("Remove", comment: ""), image: UIImage(systemName: "trash"), attributes: [.destructive]) { (action) in let deleteAction = UIAction(title: NSLocalizedString("Remove", comment: ""), image: UIImage(systemName: "trash"), attributes: [.destructive]) { (action) in
DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in
@@ -153,8 +182,20 @@ extension SourcesViewController
} }
} }
} }
var actions: [UIAction] = []
if source.error != nil
{
actions.append(viewErrorAction)
}
if source.identifier != Source.altStoreIdentifier
{
actions.append(deleteAction)
}
let menu = UIMenu(title: "", children: [deleteAction]) let menu = UIMenu(title: "", children: actions)
return menu return menu
} }
} }

View File

@@ -30,6 +30,14 @@ class TabBarController: UITabBarController
} }
} }
extension TabBarController
{
@objc func presentSources(_ sender: Any)
{
self.performSegue(withIdentifier: "presentSources", sender: sender)
}
}
private extension TabBarController private extension TabBarController
{ {
@objc func openPatreonSettings(_ notification: Notification) @objc func openPatreonSettings(_ notification: Notification)