From f6bc41fcc62ec8237c62857bc3a20bcb43814024 Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Sun, 11 Oct 2020 12:07:01 +0300 Subject: [PATCH] Replacing IHProgressHUD with PKHUD --- AutoCat.xcodeproj/project.pbxproj | 73 +- .../xcshareddata/swiftpm/Package.resolved | 9 + AutoCat/AppDelegate.swift | 5 +- AutoCat/Cells/AudioRecordCell.swift | 3 +- AutoCat/Controllers/AuthController.swift | 42 +- AutoCat/Controllers/CheckController.swift | 13 +- .../Controllers/GoogleSignInController.swift | 3 +- .../Location/EventsController.swift | 23 +- .../Location/GlobalEventsController.swift | 7 +- AutoCat/Controllers/RecordsController.swift | 9 +- AutoCat/Controllers/SearchController.swift | 7 +- AutoCat/Extensions/CocoaError.swift | 5 +- AutoCat/SceneDelegate.swift | 7 +- AutoCat/ThirdParty/IHProgressHUD/.gitkeep | 0 .../IHProgressHUD.bundle/angle-mask@1x.png | Bin 4816 -> 0 bytes .../IHProgressHUD.bundle/angle-mask@2x.png | Bin 14646 -> 0 bytes .../IHProgressHUD.bundle/angle-mask@3x.png | Bin 26585 -> 0 bytes .../IHProgressHUD.bundle/error@1x.png | Bin 409 -> 0 bytes .../IHProgressHUD.bundle/error@2x.png | Bin 873 -> 0 bytes .../IHProgressHUD.bundle/error@3x.png | Bin 752 -> 0 bytes .../IHProgressHUD.bundle/info@1x.png | Bin 662 -> 0 bytes .../IHProgressHUD.bundle/info@2x.png | Bin 1458 -> 0 bytes .../IHProgressHUD.bundle/info@3x.png | Bin 2164 -> 0 bytes .../IHProgressHUD.bundle/success@1x.png | Bin 490 -> 0 bytes .../IHProgressHUD.bundle/success@2x.png | Bin 912 -> 0 bytes .../IHProgressHUD.bundle/success@3x.png | Bin 1349 -> 0 bytes .../IHProgressHUD/IHProgressHUD.swift | 1317 ----------------- .../IndefiniteAnimatedView.swift | 197 --- .../IHProgressHUD/ProgressAnimatedView.swift | 128 -- .../IHProgressHUD/RadialGradientLayer.swift | 27 - .../Reactive+RxRealmDataSources.swift | 113 -- .../RealmBindObserver.swift | 41 - .../RxCollectionViewRealmDataSource.swift | 210 --- .../RxTableViewRealmDataSource.swift | 223 --- 34 files changed, 91 insertions(+), 2371 deletions(-) delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/.gitkeep delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@1x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@2x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@3x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/error@1x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/error@2x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/error@3x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/info@1x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/info@2x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/info@3x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/success@1x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/success@2x.png delete mode 100644 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/success@3x.png delete mode 100755 AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.swift delete mode 100755 AutoCat/ThirdParty/IHProgressHUD/IndefiniteAnimatedView.swift delete mode 100755 AutoCat/ThirdParty/IHProgressHUD/ProgressAnimatedView.swift delete mode 100755 AutoCat/ThirdParty/IHProgressHUD/RadialGradientLayer.swift delete mode 100644 AutoCat/ThirdParty/RxRealmDataSources/Reactive+RxRealmDataSources.swift delete mode 100644 AutoCat/ThirdParty/RxRealmDataSources/RealmBindObserver.swift delete mode 100644 AutoCat/ThirdParty/RxRealmDataSources/RxCollectionViewRealmDataSource.swift delete mode 100644 AutoCat/ThirdParty/RxRealmDataSources/RxTableViewRealmDataSource.swift diff --git a/AutoCat.xcodeproj/project.pbxproj b/AutoCat.xcodeproj/project.pbxproj index 9f1bc5a..4d459c7 100644 --- a/AutoCat.xcodeproj/project.pbxproj +++ b/AutoCat.xcodeproj/project.pbxproj @@ -46,10 +46,6 @@ 7A3F07AB24360DC800E59687 /* Dated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3F07AA24360DC800E59687 /* Dated.swift */; }; 7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3F07AC2436350B00E59687 /* SearchController.swift */; }; 7A43F9F8246C8A6200BA5B49 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A43F9F7246C8A6200BA5B49 /* JWT.swift */; }; - 7A488C3C24A74B990054D0B2 /* RxTableViewRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3824A74B990054D0B2 /* RxTableViewRealmDataSource.swift */; }; - 7A488C3D24A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3924A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift */; }; - 7A488C3E24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3A24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift */; }; - 7A488C3F24A74B990054D0B2 /* RealmBindObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3B24A74B990054D0B2 /* RealmBindObserver.swift */; }; 7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7924001D3300CBFE6E /* CheckController.swift */; }; 7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */; }; 7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7F2401803A00CBFE6E /* Vehicle.swift */; }; @@ -58,12 +54,6 @@ 7A64AE742469DFB600ABE48E /* MediaContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE702469DFB600ABE48E /* MediaContentView.swift */; }; 7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE712469DFB600ABE48E /* MediaBrowserViewController.swift */; }; 7A64AE762469DFB600ABE48E /* ContentTransformers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE722469DFB600ABE48E /* ContentTransformers.swift */; }; - 7A64AE7E2469E16100ABE48E /* RadialGradientLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE782469E16100ABE48E /* RadialGradientLayer.swift */; }; - 7A64AE7F2469E16100ABE48E /* IndefiniteAnimatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE792469E16100ABE48E /* IndefiniteAnimatedView.swift */; }; - 7A64AE802469E16100ABE48E /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = 7A64AE7A2469E16100ABE48E /* .gitkeep */; }; - 7A64AE812469E16100ABE48E /* ProgressAnimatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE7B2469E16100ABE48E /* ProgressAnimatedView.swift */; }; - 7A64AE822469E16100ABE48E /* IHProgressHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE7C2469E16100ABE48E /* IHProgressHUD.swift */; }; - 7A64AE832469E16100ABE48E /* IHProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7A64AE7D2469E16100ABE48E /* IHProgressHUD.bundle */; }; 7A659B5924A2B1BA0043A0F2 /* AudioRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A659B5824A2B1BA0043A0F2 /* AudioRecord.swift */; }; 7A659B5B24A3768A0043A0F2 /* Substrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A659B5A24A3768A0043A0F2 /* Substrings.swift */; }; 7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD902242BF4A5009DE740 /* PlateView.swift */; }; @@ -89,6 +79,7 @@ 7A96AE31246B2FE400297C33 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE30246B2FE400297C33 /* Constants.swift */; }; 7A96AE33246C095700297C33 /* Base64FS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE32246C095700297C33 /* Base64FS.swift */; }; 7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FEEC72529AB23001CA50E /* RxRealmDataSource.swift */; }; + 7AABDE1D2532F3EB0041AFC6 /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABDE1C2532F3EB0041AFC6 /* PKHUD */; }; 7AAE6AD324CDDF950023860B /* VehicleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AAE6AD224CDDF950023860B /* VehicleEvent.swift */; }; 7AB562BA249C9E9B00473D53 /* Region.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB562B9249C9E9B00473D53 /* Region.swift */; }; 7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; }; @@ -145,10 +136,6 @@ 7A3F07AA24360DC800E59687 /* Dated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dated.swift; sourceTree = ""; }; 7A3F07AC2436350B00E59687 /* SearchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchController.swift; sourceTree = ""; }; 7A43F9F7246C8A6200BA5B49 /* JWT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = ""; }; - 7A488C3824A74B990054D0B2 /* RxTableViewRealmDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxTableViewRealmDataSource.swift; sourceTree = ""; }; - 7A488C3924A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCollectionViewRealmDataSource.swift; sourceTree = ""; }; - 7A488C3A24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Reactive+RxRealmDataSources.swift"; sourceTree = ""; }; - 7A488C3B24A74B990054D0B2 /* RealmBindObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealmBindObserver.swift; sourceTree = ""; }; 7A530B7924001D3300CBFE6E /* CheckController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckController.swift; sourceTree = ""; }; 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCell.swift; sourceTree = ""; }; 7A530B7F2401803A00CBFE6E /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = ""; }; @@ -157,12 +144,6 @@ 7A64AE702469DFB600ABE48E /* MediaContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaContentView.swift; sourceTree = ""; }; 7A64AE712469DFB600ABE48E /* MediaBrowserViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaBrowserViewController.swift; sourceTree = ""; }; 7A64AE722469DFB600ABE48E /* ContentTransformers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentTransformers.swift; sourceTree = ""; }; - 7A64AE782469E16100ABE48E /* RadialGradientLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadialGradientLayer.swift; sourceTree = ""; }; - 7A64AE792469E16100ABE48E /* IndefiniteAnimatedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndefiniteAnimatedView.swift; sourceTree = ""; }; - 7A64AE7A2469E16100ABE48E /* .gitkeep */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; - 7A64AE7B2469E16100ABE48E /* ProgressAnimatedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressAnimatedView.swift; sourceTree = ""; }; - 7A64AE7C2469E16100ABE48E /* IHProgressHUD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IHProgressHUD.swift; sourceTree = ""; }; - 7A64AE7D2469E16100ABE48E /* IHProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = IHProgressHUD.bundle; sourceTree = ""; }; 7A659B5824A2B1BA0043A0F2 /* AudioRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecord.swift; sourceTree = ""; }; 7A659B5A24A3768A0043A0F2 /* Substrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Substrings.swift; sourceTree = ""; }; 7A6DD902242BF4A5009DE740 /* PlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateView.swift; sourceTree = ""; }; @@ -223,6 +204,7 @@ 7A96AE2A246AFD6200297C33 /* Eureka in Frameworks */, 7A051611241412CA00FC55AC /* SwiftDate in Frameworks */, 7A11472323FEA18700B424AF /* RxBlocking in Frameworks */, + 7AABDE1D2532F3EB0041AFC6 /* PKHUD in Frameworks */, 7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */, 7A11471F23FEA18700B424AF /* RxRelay in Frameworks */, 7AF58D2F24029C5200CE01A0 /* MagazineLayout in Frameworks */, @@ -295,8 +277,6 @@ 7A11472C23FECA3E00B424AF /* ThirdParty */ = { isa = PBXGroup; children = ( - 7A488C3724A74B990054D0B2 /* RxRealmDataSources */, - 7A64AE772469E16100ABE48E /* IHProgressHUD */, 7A64AE6E2469DFB600ABE48E /* ATGMediaBrowser */, 7A6DD90724329144009DE740 /* CenterTextLayer.swift */, 7A96AE32246C095700297C33 /* Base64FS.swift */, @@ -366,17 +346,6 @@ path = Extensions; sourceTree = ""; }; - 7A488C3724A74B990054D0B2 /* RxRealmDataSources */ = { - isa = PBXGroup; - children = ( - 7A488C3824A74B990054D0B2 /* RxTableViewRealmDataSource.swift */, - 7A488C3924A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift */, - 7A488C3A24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift */, - 7A488C3B24A74B990054D0B2 /* RealmBindObserver.swift */, - ); - path = RxRealmDataSources; - sourceTree = ""; - }; 7A530B7C24017FBE00CBFE6E /* Cells */ = { isa = PBXGroup; children = ( @@ -404,19 +373,6 @@ path = ATGMediaBrowser; sourceTree = ""; }; - 7A64AE772469E16100ABE48E /* IHProgressHUD */ = { - isa = PBXGroup; - children = ( - 7A64AE782469E16100ABE48E /* RadialGradientLayer.swift */, - 7A64AE792469E16100ABE48E /* IndefiniteAnimatedView.swift */, - 7A64AE7A2469E16100ABE48E /* .gitkeep */, - 7A64AE7B2469E16100ABE48E /* ProgressAnimatedView.swift */, - 7A64AE7C2469E16100ABE48E /* IHProgressHUD.swift */, - 7A64AE7D2469E16100ABE48E /* IHProgressHUD.bundle */, - ); - path = IHProgressHUD; - sourceTree = ""; - }; 7A6DD901242BF48D009DE740 /* Views */ = { isa = PBXGroup; children = ( @@ -484,6 +440,7 @@ 7A0516172414EC1200FC55AC /* RxDataSources */, 7A96AE29246AFD6200297C33 /* Eureka */, 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */, + 7AABDE1C2532F3EB0041AFC6 /* PKHUD */, ); productName = AutoCat; productReference = 7A1146FD23FDE7E500B424AF /* AutoCat.app */; @@ -523,6 +480,7 @@ 7A0516142414EC1200FC55AC /* XCRemoteSwiftPackageReference "RxDataSources" */, 7A96AE28246AFD6200297C33 /* XCRemoteSwiftPackageReference "Eureka" */, 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */, + 7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */, ); productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */; projectDirPath = ""; @@ -542,10 +500,8 @@ 7A7547DE2403180A004E8406 /* SectionHeader.xib in Resources */, 7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */, 7A6DD90A24329541009DE740 /* RoadNumbers2.0.otf in Resources */, - 7A64AE802469E16100ABE48E /* .gitkeep in Resources */, 7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */, 7A11470823FDE7E500B424AF /* Main.storyboard in Resources */, - 7A64AE832469E16100ABE48E /* IHProgressHUD.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -560,7 +516,6 @@ 7A96AE33246C095700297C33 /* Base64FS.swift in Sources */, 7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */, 7A96AE31246B2FE400297C33 /* Constants.swift in Sources */, - 7A64AE822469E16100ABE48E /* IHProgressHUD.swift in Sources */, 7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */, 7ADF6C9D250FA96000F237B2 /* SwiftMaskTextfield.swift in Sources */, 7A27ADF924A09CAD0035F39E /* CocoaError.swift in Sources */, @@ -570,7 +525,6 @@ 7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */, 7AB562BA249C9E9B00473D53 /* Region.swift in Sources */, 7A659B5924A2B1BA0043A0F2 /* AudioRecord.swift in Sources */, - 7A488C3C24A74B990054D0B2 /* RxTableViewRealmDataSource.swift in Sources */, 7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */, 7AE26A3524F31B0700625033 /* EventsController.swift in Sources */, 7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */, @@ -590,8 +544,6 @@ 7A11474923FF2B2D00B424AF /* Response.swift in Sources */, 7A64AE762469DFB600ABE48E /* ContentTransformers.swift in Sources */, 7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */, - 7A64AE7E2469E16100ABE48E /* RadialGradientLayer.swift in Sources */, - 7A64AE7F2469E16100ABE48E /* IndefiniteAnimatedView.swift in Sources */, 7AE24C5F251F1B4E00758E39 /* Buttons.swift in Sources */, 7A11471A23FE839000B424AF /* AuthController.swift in Sources */, 7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */, @@ -610,18 +562,15 @@ 7A43F9F8246C8A6200BA5B49 /* JWT.swift in Sources */, 7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */, 7ADF6C9F251201D200F237B2 /* GlobalEventsController.swift in Sources */, - 7A488C3F24A74B990054D0B2 /* RealmBindObserver.swift in Sources */, 7AAE6AD324CDDF950023860B /* VehicleEvent.swift in Sources */, 7A11470323FDE7E500B424AF /* SceneDelegate.swift in Sources */, 7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */, 7A813DCB250B5DC900CC93B9 /* LocationPickerController.swift in Sources */, 7A11474423FF06CA00B424AF /* Api.swift in Sources */, - 7A488C3D24A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift in Sources */, 7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */, 7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */, 7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */, 7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */, - 7A488C3E24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift in Sources */, 7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */, 7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */, 7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */, @@ -630,7 +579,6 @@ 7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */, 7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */, 7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */, - 7A64AE812469E16100ABE48E /* ProgressAnimatedView.swift in Sources */, 7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */, 7A000AA224C2EEDE001F5B00 /* Location.swift in Sources */, 7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */, @@ -897,6 +845,14 @@ minimumVersion = 5.2.1; }; }; + 7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/pkluz/PKHUD.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.4.0; + }; + }; 7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/airbnb/MagazineLayout"; @@ -976,6 +932,11 @@ package = 7A96AE28246AFD6200297C33 /* XCRemoteSwiftPackageReference "Eureka" */; productName = Eureka; }; + 7AABDE1C2532F3EB0041AFC6 /* PKHUD */ = { + isa = XCSwiftPackageProductDependency; + package = 7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */; + productName = PKHUD; + }; 7AF58D2E24029C5200CE01A0 /* MagazineLayout */ = { isa = XCSwiftPackageProductDependency; package = 7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */; diff --git a/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8bb26d0..f1cb54a 100644 --- a/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -37,6 +37,15 @@ "version": "1.6.3" } }, + { + "package": "PKHUD", + "repositoryURL": "https://github.com/pkluz/PKHUD.git", + "state": { + "branch": null, + "revision": "8fd26f23057c6bebd6695524b1c3e05e93aba571", + "version": "5.4.0" + } + }, { "package": "Realm", "repositoryURL": "https://github.com/realm/realm-cocoa", diff --git a/AutoCat/AppDelegate.swift b/AutoCat/AppDelegate.swift index 913574d..6ff3536 100644 --- a/AutoCat/AppDelegate.swift +++ b/AutoCat/AppDelegate.swift @@ -3,6 +3,7 @@ import RealmSwift import RxSwift import RxCocoa import os.log +import PKHUD extension OSLog { static let startup = OSLog(subsystem: "pro.aliencat.autocat.startup", category: "startup") @@ -68,8 +69,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Realm.Configuration.defaultConfiguration = config - IHProgressHUD.set(defaultStyle: .dark) - IHProgressHUD.set(defaultMaskType: .black) + HUD.dimsBackground = true + HUD.allowsInteraction = false Logging.URLRequests = { _ in false }; diff --git a/AutoCat/Cells/AudioRecordCell.swift b/AutoCat/Cells/AudioRecordCell.swift index b3f71d9..34de807 100644 --- a/AutoCat/Cells/AudioRecordCell.swift +++ b/AutoCat/Cells/AudioRecordCell.swift @@ -1,5 +1,6 @@ import UIKit import RxSwift +import PKHUD class AudioRecordCell: UITableViewCell, ConfigurableCell { @@ -74,7 +75,7 @@ class AudioRecordCell: UITableViewCell, ConfigurableCell { try AudioPlayer.shared.play(url: url) } catch { print("Error playing audio record: \(error.localizedDescription)") - IHProgressHUD.showError(withStatus: error.localizedDescription) + HUD.show(error: error) } } } diff --git a/AutoCat/Controllers/AuthController.swift b/AutoCat/Controllers/AuthController.swift index 281914f..5b5d222 100644 --- a/AutoCat/Controllers/AuthController.swift +++ b/AutoCat/Controllers/AuthController.swift @@ -3,6 +3,7 @@ import RxSwift import RxCocoa import RealmSwift import AuthenticationServices +import PKHUD class AuthController: UIViewController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { @@ -35,20 +36,20 @@ class AuthController: UIViewController, ASAuthorizationControllerDelegate, ASAut @IBAction func loginTapped(_ sender: UIButton) { guard let email = self.username.text, let pass = self.password.text else { return } - IHProgressHUD.show() + HUD.show(.progress) Api.login(email: email, password: pass) .observeOn(MainScheduler.instance) - .subscribe(onSuccess: self.goToMainScreen(user:), onError: self.displayError(error:)) + .subscribe(onSuccess: self.goToMainScreen(user:), onError: HUD.show(error:)) .disposed(by: self.bag) } @IBAction func signupTapped(_ sender: UIButton) { guard let email = self.username.text, let pass = self.password.text else { return } - IHProgressHUD.show() + HUD.show(.progress) Api.signUp(email: email, password: pass) .observeOn(MainScheduler.instance) - .subscribe(onSuccess: self.goToMainScreen(user:), onError: self.displayError(error:)) + .subscribe(onSuccess: self.goToMainScreen(user:), onError: HUD.show(error:)) .disposed(by: self.bag) } @@ -64,29 +65,24 @@ class AuthController: UIViewController, ASAuthorizationControllerDelegate, ASAut } func goToMainScreen(user: User) { -// guard let realm = try? Realm() else { -// IHProgressHUD.showError(withStatus: "Database error") -// return -// } + guard let realm = try? Realm() else { + HUD.flash(.labeledError(title: nil, subtitle: "Database error")) + return + } - IHProgressHUD.dismiss() + HUD.hide() -// if user.email != Settings.shared.user.email { -// try? realm.write { -// realm.deleteAll() -// } -// } + if user.email != Settings.shared.user.email { + try? realm.write { + realm.deleteAll() + } + } Settings.shared.user = user let storyboard = UIStoryboard(name: "Main", bundle: nil) self.view.window?.rootViewController = storyboard.instantiateViewController(identifier: "MainSplitController") } - func displayError(error: Error) { - IHProgressHUD.showError(withStatus: error.localizedDescription) - print(error) - } - // MARK: - Apple SignIn func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { @@ -97,14 +93,14 @@ class AuthController: UIViewController, ASAuthorizationControllerDelegate, ASAut switch authorization.credential { case let appleIDCredential as ASAuthorizationAppleIDCredential: guard let email = appleIDCredential.email else { - IHProgressHUD.showError(withStatus: "Cannot get email") + HUD.flash(.labeledError(title: nil, subtitle: "Cannot get email")) return } - IHProgressHUD.show() + HUD.show(.progress) Api.signIn(email: email, password: appleIDCredential.user) .observeOn(MainScheduler.instance) - .subscribe(onSuccess: self.goToMainScreen(user:), onError: self.displayError(error:)) + .subscribe(onSuccess: self.goToMainScreen(user:), onError: HUD.show(error:)) .disposed(by: self.bag) if let tokenData = appleIDCredential.identityToken { @@ -116,7 +112,7 @@ class AuthController: UIViewController, ASAuthorizationControllerDelegate, ASAut }) } default: - IHProgressHUD.showError(withStatus: "Unsupported authorization credential") + HUD.flash(.labeledError(title: nil, subtitle: "Unsupported authorization credential")) break } } diff --git a/AutoCat/Controllers/CheckController.swift b/AutoCat/Controllers/CheckController.swift index 65975c6..b46e481 100644 --- a/AutoCat/Controllers/CheckController.swift +++ b/AutoCat/Controllers/CheckController.swift @@ -3,6 +3,7 @@ import RealmSwift import RxSwift import SwiftDate import RxRealm +import PKHUD enum EventAction { case doNotSend @@ -99,12 +100,12 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat self.number.text = nil self.check.isEnabled = false - IHProgressHUD.show() + HUD.show(.progress) self.check(number: numberNormalized, action: .receiveAndSend).subscribe { vehicle in self.updateDetailController(with: vehicle) - IHProgressHUD.dismiss() + HUD.hide() } onError: { error in - IHProgressHUD.show(error: error) + HUD.show(error: error) } .disposed(by: self.bag) @@ -198,7 +199,7 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat // MARK: - Contextual actions func update(vehicle: Vehicle) { - IHProgressHUD.show() + HUD.show(.progress) var eventAction: EventAction = .doNotSend if vehicle.unrecognized, let savedEvent = vehicle.events.first { @@ -207,9 +208,9 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat self.check(number: vehicle.getNumber(), action: eventAction, force: true).subscribe { vehicle in self.updateDetailController(with: vehicle) - IHProgressHUD.dismiss() + HUD.hide() } onError: { error in - IHProgressHUD.show(error: error) + HUD.show(error: error) } .disposed(by: self.bag) } diff --git a/AutoCat/Controllers/GoogleSignInController.swift b/AutoCat/Controllers/GoogleSignInController.swift index feb1468..bd61bad 100644 --- a/AutoCat/Controllers/GoogleSignInController.swift +++ b/AutoCat/Controllers/GoogleSignInController.swift @@ -2,6 +2,7 @@ import UIKit import WebKit import CommonCrypto import RxSwift +import PKHUD struct TokenResponse: Codable { var id_token: String @@ -58,7 +59,7 @@ class GoogleSignInController: UIViewController, WKNavigationDelegate { .subscribe(onSuccess: { _ in self.dismiss(animated: true, completion: self.completion) }, onError: { error in - IHProgressHUD.showError(withStatus: error.localizedDescription) + HUD.flash(.labeledError(title: nil, subtitle: error.localizedDescription)) }) .disposed(by: self.bag) return diff --git a/AutoCat/Controllers/Location/EventsController.swift b/AutoCat/Controllers/Location/EventsController.swift index b44f414..74cd342 100644 --- a/AutoCat/Controllers/Location/EventsController.swift +++ b/AutoCat/Controllers/Location/EventsController.swift @@ -3,6 +3,7 @@ import MapKit import RxSwift import Realm import RealmSwift +import PKHUD class EventPin: NSObject, MKAnnotation { var coordinate: CLLocationCoordinate2D @@ -148,18 +149,18 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele func deleteEvent(index: Int, completion: @escaping (Bool) -> Void) { guard let vehicle = self.vehicle else { - IHProgressHUD.showError(withStatus: "Unknown vehicle") + HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle")) return } let event = vehicle.events[index] if let eventId = event.id { - IHProgressHUD.show() + HUD.show(.progress) Api.remove(event: eventId).observeOn(MainScheduler.instance).subscribe(onSuccess: { vehicle in completion(self.update(vehicle: vehicle)) }, onError: { error in completion(false) - IHProgressHUD.show(error: error) + HUD.show(error: error) print(error) }).disposed(by: self.bag) } else { @@ -169,7 +170,7 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele func editEvent(index: Int) { guard let vehicle = self.vehicle else { - IHProgressHUD.showError(withStatus: "Unknown vehicle") + HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle")) return } @@ -182,12 +183,12 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele controller.onDone = { newEvent in newEvent.id = event.id self.navigationController?.popViewController(animated: true, completion: { - IHProgressHUD.show() + HUD.show(.progress) Api.edit(event: newEvent) .observeOn(MainScheduler.instance) .subscribe(onSuccess: { self.update(vehicle: $0) }, onError: { error in - IHProgressHUD.show(error: error) + HUD.show(error: error) }) .disposed(by: self.bag) }) @@ -197,7 +198,7 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele @objc func addEvent(_ sender: UIBarButtonItem) { guard let vehicle = self.vehicle else { - IHProgressHUD.showError(withStatus: "Unknown vehicle") + HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle")) return } @@ -206,12 +207,12 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele controller.title = "Add new event" controller.onDone = { newEvent in self.navigationController?.popViewController(animated: true, completion: { - IHProgressHUD.show() + HUD.show(.progress) Api.add(event: newEvent, to: vehicle.getNumber()) .observeOn(MainScheduler.instance) .subscribe(onSuccess: { self.update(vehicle: $0) }, onError: { error in - IHProgressHUD.show(error: error) + HUD.show(error: error) }) .disposed(by: self.bag) }) @@ -231,10 +232,10 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele self.vehicle?.events.append(objectsIn: vehicle.events) } self.updateInterface() - IHProgressHUD.dismiss() + HUD.hide() return true } catch { - IHProgressHUD.show(error: error) + HUD.show(error: error) print(error) return false } diff --git a/AutoCat/Controllers/Location/GlobalEventsController.swift b/AutoCat/Controllers/Location/GlobalEventsController.swift index ea7c721..7f97422 100644 --- a/AutoCat/Controllers/Location/GlobalEventsController.swift +++ b/AutoCat/Controllers/Location/GlobalEventsController.swift @@ -1,6 +1,7 @@ import UIKit import MapKit import RxSwift +import PKHUD class GlobalEventsController: UIViewController { @@ -16,7 +17,7 @@ class GlobalEventsController: UIViewController { self.map.showsZoomControls = true #endif - IHProgressHUD.show() + HUD.show(.progress) Api.events(with: self.filter) .observeOn(MainScheduler.init()) .subscribe(onSuccess: { events in @@ -25,9 +26,9 @@ class GlobalEventsController: UIViewController { self.map.removeAnnotations(self.map.annotations) self.map.addAnnotations(pins) self.map.centerOnPins() - IHProgressHUD.dismiss() + HUD.hide() }) { error in - IHProgressHUD.show(error: error) + HUD.show(error: error) } .disposed(by: self.bag) } diff --git a/AutoCat/Controllers/RecordsController.swift b/AutoCat/Controllers/RecordsController.swift index d302e6a..d8c97f3 100644 --- a/AutoCat/Controllers/RecordsController.swift +++ b/AutoCat/Controllers/RecordsController.swift @@ -7,6 +7,7 @@ import Intents import CoreSpotlight import MobileCoreServices import os.log +import PKHUD class RecordsController: UIViewController, UITableViewDelegate { @@ -84,7 +85,7 @@ class RecordsController: UIViewController, UITableViewDelegate { @objc func onAddVoiceRecord(_ sender: UIBarButtonItem) { guard let recorder = self.recorder else { - IHProgressHUD.showError(withStatus: "Audio recorder is not available") + HUD.flash(.labeledError(title: nil, subtitle: "Audio recorder is not available")) return } @@ -142,10 +143,10 @@ class RecordsController: UIViewController, UITableViewDelegate { }) { error in if let alert = alert { alert.dismiss(animated: true) { - IHProgressHUD.show(error: error) + HUD.show(error: error) } } else { - IHProgressHUD.show(error: error) + HUD.show(error: error) } self.addButton.isEnabled = true } @@ -274,7 +275,7 @@ class RecordsController: UIViewController, UITableViewDelegate { self.present(controller, animated: true) } catch { print("Error sharing audio record: \(error.localizedDescription)") - IHProgressHUD.showError(withStatus: error.localizedDescription) + HUD.show(error: error) } } let showText = UIAlertAction(title: "Show recognized text", style: .default) { action in diff --git a/AutoCat/Controllers/SearchController.swift b/AutoCat/Controllers/SearchController.swift index 1dd6f93..2e6b643 100644 --- a/AutoCat/Controllers/SearchController.swift +++ b/AutoCat/Controllers/SearchController.swift @@ -3,6 +3,7 @@ import RxDataSources import RxSwift import RxCocoa import RealmSwift +import PKHUD class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDelegate { @@ -160,9 +161,9 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe } func update(vehicle: Vehicle, at indexPath: IndexPath) { - IHProgressHUD.show() + HUD.show(.progress) Api.checkVehicle(by: vehicle.getNumber(), force: true).observeOn(MainScheduler.instance).subscribe { newVehicle in - IHProgressHUD.dismiss() + HUD.hide() if let realm = try? Realm() { if realm.object(ofType: Vehicle.self, forPrimaryKey: vehicle.getNumber()) != nil { try? realm.write { @@ -173,7 +174,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe self.datasource[indexPath] = newVehicle self.updateDetailController(with: newVehicle) } onError: { err in - IHProgressHUD.show(error: err) + HUD.show(error: err) }.disposed(by: self.bag) } } diff --git a/AutoCat/Extensions/CocoaError.swift b/AutoCat/Extensions/CocoaError.swift index 0a2c60a..391ddae 100644 --- a/AutoCat/Extensions/CocoaError.swift +++ b/AutoCat/Extensions/CocoaError.swift @@ -1,4 +1,5 @@ import UIKit +import PKHUD extension NSError { var displayMessage: (title: String, body: String) { @@ -50,9 +51,9 @@ extension UIViewController { } } -extension IHProgressHUD { +extension HUD { static func show(error: Error) { let msg = (error as NSError).displayMessage - self.showError(withStatus: msg.title + "\n" + msg.body) + self.flash(.labeledError(title: msg.title, subtitle: msg.body), delay: 2.0) } } diff --git a/AutoCat/SceneDelegate.swift b/AutoCat/SceneDelegate.swift index 50a0162..d822548 100644 --- a/AutoCat/SceneDelegate.swift +++ b/AutoCat/SceneDelegate.swift @@ -2,6 +2,7 @@ import UIKit import os.log import AVFoundation import RxSwift +import PKHUD class SceneDelegate: UIResponder, UIWindowSceneDelegate { @@ -145,7 +146,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func openReport(with number: String) { guard let rootController = self.window?.rootViewController else { return } - IHProgressHUD.show() + HUD.show(.progress) _ = Api.getReport(for: number).observeOn(MainScheduler.instance).subscribe { vehicle in let sb = UIStoryboard(name: "Main", bundle: nil) let controller = sb.instantiateViewController(identifier: "ReportController") as ReportController @@ -154,9 +155,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { nav.modalPresentationStyle = .fullScreen controller.navigationItem.leftBarButtonItem = BlockBarButtonItem(barButtonSystemItem: .close) { _ in nav.dismiss(animated: true) } rootController.present(nav, animated: true) - IHProgressHUD.dismiss() + HUD.hide() } onError: { error in - IHProgressHUD.show(error: error) + HUD.show(error: error) } } } diff --git a/AutoCat/ThirdParty/IHProgressHUD/.gitkeep b/AutoCat/ThirdParty/IHProgressHUD/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@1x.png b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@1x.png deleted file mode 100644 index ffecbd448c0a3e7e44f60d152db622763eb27804..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4816 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 diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@2x.png b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@2x.png deleted file mode 100644 index 452458effa72b5dc46d3c143e7648db424151138..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14646 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 diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@3x.png b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/angle-mask@3x.png deleted file mode 100644 index bf8e5e42c9b77f08d82183544cb48fa3422b3c03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26585 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 diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/error@2x.png b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/error@2x.png deleted file mode 100644 index 5c11ed00fc95704ec8e18f23eea7f25cad873f8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 873 zcmV-v1D5=WP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91IG_Un1ONa40RR91H~;_u01a1YQvd)0(@8`@RA>e5T3bp4K@40Ke1XUD z%kzjIzCDcZLkS*55K%-^unlcd*?D!(WMl)OH@)3GsZ^5QU3Rfp%Q^y~Bd|r@9hiM) zdT9D$`fWM~*)bKv%Hg&NSa}Z#GgOn!qRcmir3d8wpWS!9k51ZOvE$Ul?4cZ1bWMfl2sK zB+DW)IhZ+4F%>ODZwe->`4WN2;> zF^QV20TO4bZdsf;4#F5rj?Nr|L`PF~QG!VY4$m6BbJt)}fvZ|`%pBV#nN;8=VU9t1 zOm;~r6{ty>W00!5BKmD=(qpcAw`34ab{{6gGsmDkCIOxWbE*@EW3H{^c}*(j09FNp z&ktdP1vH8L+cp4TUa^d|;h8fZ|A|pcKeH zsh`elHL7koG%dXcd+A!OCKYqFz$MTg$l^?T-Lgc@B{1HoKo;$;iaFFr@hEx-m(QwF zljxS}p2PguqB=Kx>+Oq5jj@^IAR=oNlbuT?5_1f4Fq08#jzO{QG1=G`upmm!F(|e@ zCRc*IvQzSpNXYknJ~@yL-?%0(bN~2f!`#Ltes21nZwU4pzQITMnk2`t*hsU>5r2q1 zHvKYvGW{@}gCJc`Oz{WbXVW*+wX7pBhY0)vJ=%=xUShwC00000NkvXXu0mjfr9O1x diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/error@3x.png b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/error@3x.png deleted file mode 100644 index 91add0971f95a29474a4ef78012bcab927acfd28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 752 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 M07*qoM6N<$f|p&cQ2+n{ diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/info@3x.png b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/info@3x.png deleted file mode 100644 index 6539bda822cc755f1688d0970932e636256338f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2164 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 T@yzxND4acA{an^LB{Ts5hA+LD diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/success@2x.png b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.bundle/success@2x.png deleted file mode 100644 index b70ab2b3a4364f4669faab8f2721ddb5e9152cc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 912 zcmV;B18@9^P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91IG_Un1ONa40RR91H~;_u01a1YQvd)0`bk7VRA>e5nM;UHVHn59osnA> zE*r{i7Lp>DQWh4bSXo%Gn1wQBL}r$7w%Dbfg}5lADD;|L7NvF}=RJ(7cN zhGp;wzCoB6hDjIvF3}Oj3=zq7mc%632W=1{24k@ket}i*7`ZOj5TQ%)2bkP>^2QKm zNNj@dU~-qp$3lo`!QvB`+%@tEA60Xzqjdq%zpLd0Awo`A`{BwrH342fBw`^@CtkT*k!n1+RB zNRxXmWo-#NsNL+*k6J5N1e>fs0^rTCi?`5HSji9xyq5hFP?Z zK<22E)7owqga|EI4}h=SZrUM!FS6CRms2J66GVvEj>S(f!IR{=7ej<*M=z(@Q?qC; z(MYcwVFT!f&pTQ|3=U3woXwQJEg=92~c}YE=hF9PWmea>8*SG#} zFsB0jmfeLUkAs&yM0+5WT*&?}T%XG4L(M`mr@>3^r~N;boX37oU0+&_FNT_jBu{{s z)a6>v#50raAG$tt|LIaKOh~dDyyQOG{dtX=&UW|QzFLhpL*YWR>nX@e{_AqpGwrt9 z=L5MO4}}d$o&l5WBkzQvkPWTIuY+x?x0UtTjf&XTt6VqOiR)96zLMi;Uvb-fCU1qh z303ken4~JX7Y2du*9&0ZX~DV;^j%$rD(NMylKurjD})_&WtBNuN%nwMEBm>J@BVgw zX1XbMb2O)S4zhAb_*;J-BgM8Wot-M_C3TsW^CD0c$$?G+s$?5z!qIOjdMuPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91RGcFeylm`ti5LM@64Gqv*z^b<>myOfD>>6PQVE` z0Vm)DoIqI!^kJgkpvUMedIP!TB+#32yU@Q0ozGdT^26#NurmSDpgyTQnVbMN1z-y5 zww(1UJ?zU2mdvHFL|Aez5RY)qxe zYbxW!9saphrq2%h9 z+aQ|PFZ|4iI-UxFK}gq>2GP8(JwHNj5d;R3dlVT&^SUcq7*WSlA)x#3KafF8`Y)VN z907HP_GiFcA6Lq=)otIC0duqCi6fwH`*#^Iza_5s-69BVAvbxhwC&x*b>zB55crB* z1DN#th4&qWLCbuOPPw0#nEhJ-WC}T>VbB2m%wyRcGCfNb~oI zsT1!OL0~Modgfyg%?t3G5p_Hj0;5o<+pe$vbSD%?;APUYy6x}9mGW#|{+vPf^)|0- z&kr3>906UJA4dk!yzYwTBDV+v>b4(71~KWEM%3x_)WPgQe;oY<>9(zirq0l>C<)QF z*A;ETzo#a;reG6P&vI{Sjs|mM!RGq^bV9dls|zwwb<=-91~BP&5HDo6{kMz>uO!~x zww(ziA=>tj#0v>iz+OV;B2cbt7Cy1A}+g=Om zvQ8xW0kuPqF3u6x?PjS>&4?A4CiNm1(5g8EqpOmZ?cLfv*XjmLFB{X&)y)JBv(f^?*Q+Kw5IXRN@b>k9Cs zcGNA!Q2iJEDoQV2Q1z#RSkr^ETPR&mU;U}E#mbsLf{9;4X$XS4C}L4M;{OWN(T~zQ z5p{Y*YI~vT@+Wlj&`Nw(k06v|5ewgNP#V%RVo9hk@LGQ%Oy}u!(VE#zse4UOucI_9L7j*C zApN;D{k~p*jobnRMiaY%($MrnqyJ;3<9fXnxz!+`Tf`955X|q%t*cSX-+E3!P@7Q* zqQ!pV{oc>>-L-*$?trqO9^k#wblcmo)-FqVoju(|c2vqALb`Nv%Sk{->S6Q{?LwvP zwljA(C*TB}fD>>6PQVE`0Vm)DoPZN>0#3jQH~}Zn#RUEXk_`GvI4v`+00000NkvXX Hu0mjfpde?D diff --git a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.swift b/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.swift deleted file mode 100755 index 0e3ff45..0000000 --- a/AutoCat/ThirdParty/IHProgressHUD/IHProgressHUD.swift +++ /dev/null @@ -1,1317 +0,0 @@ -// -// Converted to Swift 4 by Swiftify v4.2.29618 - https://objectivec2swift.com/ -// -// IndefiniteAnimatedView.swift -// SVProgressHUD, https://github.com/IHProgressHUD/IHProgressHUD -// -// Original Copyright (c) 2014-2018 Guillaume Campagna. All rights reserved. -// Modified Copyright © 2018 Ibrahim Hassan. All rights reserved. -// - - -import UIKit - -public enum NotificationName : String { - case IHProgressHUDDidReceiveTouchEvent, IHProgressHUDDidTouchDownInside, IHProgressHUDWillDisappear, IHProgressHUDDidDisappear, IHProgressHUDWillAppear, IHProgressHUDDidAppear, IHProgressHUDStatusUserInfoKey - public func getNotificationName() -> Notification.Name { - return Notification.Name.init(self.rawValue) - } -} - -public enum IHProgressHUDStyle : Int { - case light - case dark - case custom -} - -public enum IHProgressHUDMaskType : Int { - case none = 1 - case clear - case black - case gradient - case custom -} - -public enum IHProgressHUDAnimationType : Int { - case flat - case native -} - -private let IHProgressHUDParallaxDepthPoints : CGFloat = 10.0 -private let IHProgressHUDUndefinedProgress : CGFloat = -1 -private let IHProgressHUDDefaultAnimationDuration: CGFloat = 0.15 -private let IHProgressHUDVerticalSpacing: CGFloat = 12.0 -private let IHProgressHUDHorizontalSpacing: CGFloat = 12.0 -private let IHProgressHUDLabelSpacing: CGFloat = 8.0 - -public class IHProgressHUD : UIView { - - static var isNotAppExtension = true - - private var defaultStyle = IHProgressHUDStyle.light - private var defaultMaskType = IHProgressHUDMaskType.none - private var defaultAnimationType = IHProgressHUDAnimationType.flat - private var containerView: UIView? - private var minimumSize = CGSize.init(width: 50, height: 50) - private var ringThickness: CGFloat = 2.0 - private var ringRadius: CGFloat = 18.0 - private var ringNoTextRadius: CGFloat = 24.0 - private var cornerRadius: CGFloat = 14.0 - private var font = UIFont.preferredFont(forTextStyle: .subheadline) - private var foregroundColor : UIColor? - private var backgroundLayerColor = UIColor.init(white: 0, alpha: 0.4) - private var imageViewSize: CGSize = CGSize.init(width: 28, height: 28) - private var shouldTintImages : Bool = true - private var infoImage: UIImage! - private var successImage: UIImage! //= UIImage.init(named: "success")! - private var errorImage: UIImage! //= UIImage.init(named: "error")! - private var viewForExtension: UIView? - private var graceTimeInterval: TimeInterval = 0.0 - private var minimumDismissTimeInterval: TimeInterval = 5.0 - private var maximumDismissTimeInterval: TimeInterval = TimeInterval(CGFloat.infinity) - private var offsetFromCenter: UIOffset = UIOffset.init(horizontal: 0, vertical: 0) - private var fadeInAnimationDuration: TimeInterval = TimeInterval(IHProgressHUDDefaultAnimationDuration) - private var fadeOutAnimationDuration: TimeInterval = TimeInterval(IHProgressHUDDefaultAnimationDuration) - private var maxSupportedWindowLevel: UIWindow.Level = UIWindow.Level.normal - private var hapticsEnabled = false - private var graceTimer: Timer? - private var fadeOutTimer: Timer? - private var controlView: UIControl? - private var backgroundView: UIView? - private var backgroundRadialGradientLayer: RadialGradientLayer? - private var hudView: UIVisualEffectView? - private var statusLabel: UILabel? - private var imageView: UIImageView? - private var indefiniteAnimatedView: IndefiniteAnimatedView? - private var ringView: ProgressAnimatedView? - private var backgroundRingView: ProgressAnimatedView? - private var progress: Float = 0.0 - private var activityCount: Int = 0 - private var visibleKeyboardHeight: CGFloat = 0.0 - private var frontWindow: UIWindow? - private var hudBackgroundColor : UIColor? - #if os(iOS) - @available(iOS 10.0, *) - private var hapticGenerator: UINotificationFeedbackGenerator? { - get { - if hapticsEnabled == true { - return UINotificationFeedbackGenerator() - } else { - return nil - } - } - } - #endif - private override init(frame: CGRect) { - super.init(frame: frame) - infoImage = loadImageBundle(named: "info")! - successImage = loadImageBundle(named: "success")! - errorImage = loadImageBundle(named: "error") - isUserInteractionEnabled = false - activityCount = 0 - getBackGroundView().alpha = 0.0 - getImageView().alpha = 0.0 - getStatusLabel().alpha = 1.0 - getIndefiniteAnimatedView().alpha = 0.0 - getBackgroundRingView().alpha = 0.0 - backgroundColor = UIColor.clear - accessibilityIdentifier = "IHProgressHUD" - isAccessibilityElement = true - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - private func getIndefiniteAnimatedView() -> IndefiniteAnimatedView { - if defaultAnimationType == .flat { - if (indefiniteAnimatedView == nil) { - indefiniteAnimatedView = IndefiniteAnimatedView.init(frame: .zero) - } - indefiniteAnimatedView?.setIndefinite(strokeColor: foreGroundColorForStyle()) - indefiniteAnimatedView?.setIndefinite(strokeThickness: ringThickness) - var radius :CGFloat = 0.0 - if getStatusLabel().text != nil { - radius = ringRadius - } else { - radius = ringNoTextRadius - } - indefiniteAnimatedView?.setIndefinite(radius: radius) - } else { - indefiniteAnimatedView?.removeAnimationLayer() - indefiniteAnimatedView?.setActivityIndicator(color: foreGroundColorForStyle()) - indefiniteAnimatedView?.startAnimation() - } - indefiniteAnimatedView?.sizeToFit() - return indefiniteAnimatedView! - } - - private static let sharedView : IHProgressHUD = { - var localInstance : IHProgressHUD? - if Thread.current.isMainThread { - if IHProgressHUD.isNotAppExtension { - if let window = UIApplication.shared.delegate?.window { - localInstance = IHProgressHUD.init(frame: window?.bounds ?? CGRect.zero) - } else { - localInstance = IHProgressHUD() - } - } - else { - localInstance = IHProgressHUD.init(frame: UIScreen.main.bounds) - } - } else { - DispatchQueue.main.sync { - if IHProgressHUD.isNotAppExtension { - if let window = UIApplication.shared.delegate?.window { - localInstance = IHProgressHUD.init(frame: window?.bounds ?? CGRect.zero) - } else { - localInstance = IHProgressHUD() - } - } else { - localInstance = IHProgressHUD.init(frame: UIScreen.main.bounds) - } - } - } - return localInstance! - }() - - // MARK :- Setters - - private func showProgress(progress: Float, status: String?) { - OperationQueue.main.addOperation({ [weak self] in - guard let strongSelf = self else { return } - if strongSelf.fadeOutTimer != nil { - strongSelf.activityCount = 0 - } - - // Stop timer - strongSelf.setFadeOut(timer: nil) - strongSelf.setGrace(timer: nil) - - // Update / Check view hierarchy to ensure the HUD is visible - strongSelf.updateViewHierarchy() - - // Reset imageView and fadeout timer if an image is currently displayed - strongSelf.getImageView().isHidden = true - strongSelf.getImageView().image = nil - - // Update text and set progress to the given value - strongSelf.getStatusLabel().isHidden = (status?.count ?? 0) == 0 - strongSelf.getStatusLabel().text = status - strongSelf.progress = progress - - // Choose the "right" indicator depending on the progress - if progress >= 0 { - // Cancel the indefiniteAnimatedView, then show the ringLayer - strongSelf.cancelIndefiniteAnimatedViewAnimation() - - // Add ring to HUD - if strongSelf.getRingView().superview == nil { - strongSelf.getHudView().contentView.addSubview(strongSelf.getRingView()) - } - if strongSelf.getBackgroundRingView().superview == nil { - strongSelf.getHudView().contentView.addSubview(strongSelf.getBackgroundRingView()) - } - - // Set progress animated - CATransaction.begin() - CATransaction.setDisableActions(true) - strongSelf.getRingView().set(strokeEnd: CGFloat(progress)) - // strongSelf.ringView.strokeEnd = progress; - CATransaction.commit() - - // Update the activity count - if progress == 0 { - strongSelf.activityCount += 1 - } - } else { - // Cancel the ringLayer animation, then show the indefiniteAnimatedView - strongSelf.cancelRingLayerAnimation() - - // Add indefiniteAnimatedView to HUD - strongSelf.getHudView().contentView.addSubview(strongSelf.getIndefiniteAnimatedView()) - - if strongSelf.defaultAnimationType == .native { - strongSelf.getIndefiniteAnimatedView().stopActivityIndicator() - } - - // Update the activity count - strongSelf.activityCount += 1 - } - - // Fade in delayed if a grace time is set - if strongSelf.graceTimeInterval > 0.0 && strongSelf.getBackGroundView().alpha == 0.0 { - let timer = Timer(timeInterval: strongSelf.graceTimeInterval, target: strongSelf, selector: #selector(strongSelf.fadeIn(_:)), userInfo: nil, repeats: false) - strongSelf.setGrace(timer: timer) - if let aTimer = strongSelf.graceTimer { - RunLoop.main.add(aTimer, forMode: .common) - } - } else { - strongSelf.fadeIn(nil) - } - - // Tell the Haptics Generator to prepare for feedback, which may come soon - #if os(iOS) - if #available(iOS 10.0, *) { - strongSelf.hapticGenerator?.prepare() - } - #endif - }) - } - - @objc private func controlViewDidReceiveTouchEvent(_ sender: Any?, for event: UIEvent?) { - NotificationCenter.default.post(name: NotificationName.IHProgressHUDDidReceiveTouchEvent.getNotificationName(), object: self, userInfo: notificationUserInfo()) - - if let touchLocation = event?.allTouches?.first?.location(in: self) { - if getHudView().frame.contains(touchLocation) { - NotificationCenter.default.post(name: - NotificationName.IHProgressHUDDidTouchDownInside.getNotificationName(), object: self, userInfo: notificationUserInfo()) - } - } - - } - - func notificationUserInfo() -> [String : Any]? { - if let statusText = getStatusLabel().text { - return [NotificationName.IHProgressHUDStatusUserInfoKey.rawValue: statusText] - } - return nil - } - - - @objc private func fadeIn(_ object: AnyObject?) { - updateHUDFrame() - positionHUD() - if (defaultMaskType != .none) { - getControlView().isUserInteractionEnabled = true - accessibilityLabel = getStatusLabel().text ?? "Loading" - isAccessibilityElement = true - getControlView().accessibilityViewIsModal = true - } else { - getControlView().isUserInteractionEnabled = false - getHudView().accessibilityLabel = getStatusLabel().text ?? "Loading" - getHudView().isAccessibilityElement = true - getControlView().accessibilityViewIsModal = false - } - - if getBackGroundView().alpha != 1.0 { - NotificationCenter.default.post(name: NotificationName.IHProgressHUDWillAppear.getNotificationName(), object: self, userInfo: notificationUserInfo()) - - getHudView().transform = CGAffineTransform.init(scaleX: 1/1.5, y: 1/1.5) - let animationsBlock : () -> Void = { - // Zoom HUD a little to make a nice appear / pop up animation - self.getHudView().transform = CGAffineTransform.identity - - // Fade in all effects (colors, blur, etc.) - self.fadeInEffects() - } - - - let completionBlock : () -> Void = { - if self.getBackGroundView().alpha == 1.0 { - self.registerNotifications() - } - - NotificationCenter.default.post(name: NotificationName.IHProgressHUDDidAppear.getNotificationName(), object: self, userInfo: self.notificationUserInfo()) - - // Update accessibility - - UIAccessibility.post(notification: UIAccessibility.Notification.screenChanged, argument: nil) - - UIAccessibility.post(notification: UIAccessibility.Notification.announcement, argument: self.statusLabel?.text) - if let cd : TimeInterval = object as? TimeInterval { - let timer = Timer.init(timeInterval: cd, target: self, selector: #selector(self.dismiss), userInfo: nil, repeats: false) - self.setFadeOut(timer: timer) - RunLoop.main.add(self.fadeOutTimer!, forMode: .common) - } - } - - if fadeInAnimationDuration > 0 { - UIView.animate(withDuration: self.fadeInAnimationDuration, delay: 0, options: [.allowUserInteraction, .curveEaseIn, .beginFromCurrentState], animations: animationsBlock, completion: { - finished in - completionBlock() - }) - } else { - animationsBlock() - completionBlock() - } - self.setNeedsDisplay() - } else { - UIAccessibility.post(notification: UIAccessibility.Notification.screenChanged, argument: nil) - - UIAccessibility.post(notification: UIAccessibility.Notification.announcement, argument: self.statusLabel?.text) - - if let convertedDuration : TimeInterval = object as? TimeInterval { - let timer = Timer.init(timeInterval: convertedDuration, target: self, selector: #selector(dismiss), userInfo: nil, repeats: false) - setFadeOut(timer: timer) - RunLoop.main.add(self.fadeOutTimer!, forMode: .common) - } - } - } - - @objc private func positionHUD(_ notification: Notification? = nil) { - var keyboardHeight: CGFloat = 0.0 - var animationDuration: Double = 0.0 - - if IHProgressHUD.isNotAppExtension == false { - if viewForExtension != nil { - frame = viewForExtension!.frame - } else { - frame = UIScreen.main.bounds - } - } - - var statusBarFrame = CGRect.zero - - #if os(iOS) // notAppExtension + iOS - var orientation = UIInterfaceOrientation.portrait - if IHProgressHUD.isNotAppExtension { - if #available(iOS 13.0, *) { - var rootVC:UIViewController? = nil - for scene in UIApplication.shared.connectedScenes { - if scene.activationState == .foregroundActive { - if let vc = ((scene as? UIWindowScene)?.delegate as? UIWindowSceneDelegate)?.window??.rootViewController { - rootVC = vc - break - } - } - } - frame = rootVC?.view.window?.bounds ?? UIScreen.main.bounds - if let or = rootVC?.view.window?.windowScene?.interfaceOrientation { - orientation = or - } - if let statFrame = rootVC?.view.window?.windowScene?.statusBarManager?.statusBarFrame { - statusBarFrame = statFrame - } - } else { - // Fallback on earlier versions - if let appDelegate = UIApplication.shared.delegate { - if let window = appDelegate.window { - if let windowFrame = window?.bounds { - frame = windowFrame - } - } - } - orientation = UIApplication.shared.statusBarOrientation - statusBarFrame = UIApplication.shared.statusBarFrame - } - - - if frame.width > frame.height { - orientation = .landscapeLeft - } else { - orientation = .portrait - } - if let notificationData = notification { - let keyboardInfo = notificationData.userInfo - if let keyboardFrame: NSValue = keyboardInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { - let keyboardFrame: CGRect = keyboardFrame.cgRectValue - if (notification?.name.rawValue == UIResponder.keyboardWillShowNotification.rawValue || notification?.name.rawValue == UIResponder.keyboardDidShowNotification.rawValue) { - keyboardHeight = keyboardFrame.width - if orientation.isPortrait { - keyboardHeight = keyboardFrame.height - } - } - } - if let aDuration: Double = keyboardInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double { - animationDuration = aDuration - } - } else { - keyboardHeight = getVisibleKeyboardHeight() - } - - updateMotionEffectForOrientation(orientation) - } - #endif - - let orientationFrame = bounds - #if os(tvOS) - if IHProgressHUD.isNotAppExtension { - if let keyWindow : UIWindow = UIApplication.shared.keyWindow { - frame = keyWindow.bounds - } - } - updateMotionEffect(forXMotionEffectType: .tiltAlongHorizontalAxis, yMotionEffectType: .tiltAlongHorizontalAxis) - #endif - - var activeHeight = orientationFrame.height - - if keyboardHeight > 0 { - activeHeight += statusBarFrame.height * 2 - } - activeHeight -= keyboardHeight - - let posX = orientationFrame.midX - let posY = CGFloat(floor(activeHeight * 0.45)) - - let rotateAngle : CGFloat = 0.0 - let newCenter = CGPoint.init(x: posX, y: posY) - - if notification != nil { - // Animate update if notification was present - UIView.animate(withDuration: TimeInterval(animationDuration), delay: 0, options: [.allowUserInteraction, .beginFromCurrentState], animations: { - self.move(to: newCenter, rotateAngle: rotateAngle) - self.getHudView().setNeedsDisplay() - }) - } else { - move(to: newCenter, rotateAngle: rotateAngle) - } - } - - private func updateViewHierarchy() { - // Add the overlay to the application window if necessary - if getControlView().superview == nil { - if containerView != nil { - self.containerView!.addSubview(getControlView()) - // self.frame = containerView!.frame - } else { - if IHProgressHUD.isNotAppExtension { - if self.containerView != nil { - containerView?.addSubview(getControlView()) - } else { - getFrontWindow()?.addSubview(getControlView()) - } - } - else { - // If IHProgressHUD is used inside an app extension add it to the given view - if viewForExtension != nil { - viewForExtension!.addSubview(getControlView()) - } - } - } - } else { - // The HUD is already on screen, but maybe not in front. Therefore - // ensure that overlay will be on top of rootViewController (which may - // be changed during runtime). - getControlView().superview?.bringSubviewToFront(getControlView()) - } - - // Add self to the overlay view - if superview == nil { - getControlView().addSubview(self) - } - } - - private func cancelIndefiniteAnimatedViewAnimation(){ - self.indefiniteAnimatedView?.stopActivityIndicator() - self.indefiniteAnimatedView?.removeFromSuperview() - } - - private func cancelRingLayerAnimation() { - // Animate value update, stop animation - CATransaction.begin() - CATransaction.setDisableActions(true) - - getHudView().layer.removeAllAnimations() - getRingView().set(strokeEnd: 0.0) - - CATransaction.commit() - - // Remove from view - getRingView().removeFromSuperview() - getBackgroundRingView().removeFromSuperview() - } - - // stops the activity indicator, shows a glyph + status, and dismisses the HUD a little bit later - - private func show(image: UIImage, status: String?, duration: TimeInterval) { - OperationQueue.main.addOperation({ [weak self] in - guard let strongSelf = self else { return } - - strongSelf.setFadeOut(timer: nil) - strongSelf.setGrace(timer: nil) - strongSelf.updateViewHierarchy() - - strongSelf.progress = Float(IHProgressHUDUndefinedProgress) - strongSelf.cancelRingLayerAnimation() - strongSelf.cancelIndefiniteAnimatedViewAnimation() - - if strongSelf.shouldTintImages { - if image.renderingMode != UIImage.RenderingMode.alwaysTemplate { - strongSelf.getImageView().image = image.withRenderingMode(.alwaysTemplate) - strongSelf.getImageView().tintColor = strongSelf.foreGroundColorForStyle() - } - } else { - strongSelf.getImageView().image = image - } - strongSelf.getImageView().isHidden = false - - strongSelf.getStatusLabel().isHidden = status == nil || status?.count == 0 - if let stts = status { - strongSelf.getStatusLabel().text = stts - } - if (strongSelf.graceTimeInterval > 0.0 && strongSelf.getBackGroundView().alpha == 0.0) { - let timer = Timer.init(timeInterval: strongSelf.graceTimeInterval, target: strongSelf, selector: #selector(strongSelf.fadeIn(_:)), userInfo: duration, repeats: false) - strongSelf.setGrace(timer: timer) - RunLoop.main.add(strongSelf.graceTimer!, forMode: .common) - } else { - strongSelf.fadeIn(duration as AnyObject) - } - }) - } - // shows a image + status, use white PNGs with the imageViewSize (default is 28x28 pt) - - private func dismissWithDelay(_ delay: TimeInterval, completion: (() -> Void)?) { - OperationQueue.main.addOperation({ [weak self] in - guard let strongSelf = self else { return } - // Stop timer - strongSelf.setGrace(timer: nil) - // Post notification to inform user - NotificationCenter.default.post(name: NotificationName.IHProgressHUDWillDisappear.getNotificationName(), object: nil, userInfo: strongSelf.notificationUserInfo()) - - // Reset activity count - strongSelf.activityCount = 0 - - let animationsBlock: () -> Void = { - // Shrink HUD a little to make a nice disappear animation - strongSelf.getHudView().transform = strongSelf.getHudView().transform.scaledBy(x: 1 / 1.3, y: 1 / 1.3) - - // Fade out all effects (colors, blur, etc.) - strongSelf.fadeOutEffects() - } - - let completionBlock: (() -> Void) = { - // Check if we really achieved to dismiss the HUD (<=> alpha values are applied) - // and the change of these values has not been cancelled in between e.g. due to a new show - if strongSelf.getBackGroundView().alpha == 0.0 { - // Clean up view hierarchy (overlays) - strongSelf.getControlView().removeFromSuperview() - strongSelf.getBackGroundView().removeFromSuperview() - strongSelf.getHudView().removeFromSuperview() - strongSelf.removeFromSuperview() - - // Reset progress and cancel any running animation - strongSelf.progress = Float(IHProgressHUDUndefinedProgress) - strongSelf.cancelRingLayerAnimation() - strongSelf.cancelIndefiniteAnimatedViewAnimation() - - // Remove observer <=> we do not have to handle orientation changes etc. - NotificationCenter.default.removeObserver(strongSelf) - // Post notification to inform user - //IHProgressHUDDidDisappearNotification - NotificationCenter.default.post(name: NotificationName.IHProgressHUDDidDisappear.getNotificationName(), object: strongSelf, userInfo: strongSelf.notificationUserInfo()) - - // Tell the rootViewController to update the StatusBar appearance - #if os(iOS) - if IHProgressHUD.isNotAppExtension { - if #available(iOS 13.0, *) { - var rootVC:UIViewController? = nil - for scene in UIApplication.shared.connectedScenes { - if scene.activationState == .foregroundActive { - rootVC = ((scene as? UIWindowScene)?.delegate as? UIWindowSceneDelegate)?.window??.rootViewController - break - } - } - rootVC?.setNeedsStatusBarAppearanceUpdate() - } else { - // Fallback on earlier versions - let rootController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController - rootController?.setNeedsStatusBarAppearanceUpdate() - } - - } - #endif - if completion != nil { - completion!() - } - // Run an (optional) completionHandler - - } - } - - // UIViewAnimationOptionBeginFromCurrentState AND a delay doesn't always work as expected - // When UIViewAnimationOptionBeginFromCurrentState is set, animateWithDuration: evaluates the current - // values to check if an animation is necessary. The evaluation happens at function call time and not - // after the delay => the animation is sometimes skipped. Therefore we delay using dispatch_after. - - let dipatchTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) - DispatchQueue.main.asyncAfter(deadline: dipatchTime, execute: { - if strongSelf.fadeOutAnimationDuration > 0 { - UIView.animate(withDuration: strongSelf.fadeOutAnimationDuration, delay: 0, options: [.allowUserInteraction, .curveEaseOut, .beginFromCurrentState], animations: { - animationsBlock() - }) { finished in - completionBlock() - } - }else { - animationsBlock() - completionBlock() - } - }) - - // Inform iOS to redraw the view hierarchy - strongSelf.setNeedsDisplay() - } - ) - } - - @objc private func dismiss() { - dismissWithDelay(0.0, completion: nil) - } - - private func setStatus(_ status: String?) { - getStatusLabel().text = status - updateHUDFrame() - } - - private func updateHUDFrame() { - // Check if an image or progress ring is displayed - let imageUsed: Bool = (getImageView().image) != nil && !((getImageView().isHidden) ) - let progressUsed: Bool = getImageView().isHidden - - // Calculate size of string - var labelRect : CGRect = CGRect.zero - var labelHeight: CGFloat = 0.0 - var labelWidth: CGFloat = 0.0 - - if getStatusLabel().text != nil { - let constraintSize = CGSize(width: 200.0, height: 300.0) - labelRect = getStatusLabel().text?.boundingRect(with: constraintSize, options: [.usesFontLeading, .truncatesLastVisibleLine, .usesLineFragmentOrigin], attributes: [NSAttributedString.Key.font: getStatusLabel().font ?? UIFont.systemFont(ofSize: 15)], context: nil) ?? CGRect.zero - labelHeight = CGFloat(ceilf(Float(labelRect.height ))) - labelWidth = CGFloat(ceilf(Float(labelRect.width ))) - } - - // Calculate hud size based on content - // For the beginning use default values, these - // might get update if string is too large etc. - var hudWidth: CGFloat - var hudHeight: CGFloat - - var contentWidth: CGFloat = 0.0 - var contentHeight: CGFloat = 0.0 - - if (imageUsed || progressUsed) { - if imageUsed { - contentWidth = getImageView().frame.width - contentHeight = getImageView().frame.height - } else { - contentWidth = getIndefiniteAnimatedView().frame.width - contentHeight = getIndefiniteAnimatedView().frame.height - } - } - // |-spacing-content-spacing-| - hudWidth = CGFloat(IHProgressHUDHorizontalSpacing + max(labelWidth, contentWidth) + IHProgressHUDHorizontalSpacing) - - // |-spacing-content-(labelSpacing-label-)spacing-| - hudHeight = CGFloat(IHProgressHUDVerticalSpacing) + labelHeight + contentHeight + CGFloat(IHProgressHUDVerticalSpacing) - if ((getStatusLabel().text != nil) && (imageUsed || progressUsed )) { - // Add spacing if both content and label are used - hudHeight += CGFloat(IHProgressHUDLabelSpacing)//8 [80] - } - - // Update values on subviews - getHudView().bounds = CGRect(x: 0.0, y: 0.0, width: max(minimumSize.width, hudWidth), height: max(minimumSize.height, hudHeight)) - - // Animate value update - CATransaction.begin() - CATransaction.setDisableActions(true) - - // Spinner and image view - var centerY: CGFloat - if getStatusLabel().text != nil { - let yOffset = max(IHProgressHUDVerticalSpacing, (minimumSize.height - contentHeight - CGFloat(IHProgressHUDLabelSpacing) - labelHeight) / 2.0)//12 - centerY = yOffset + contentHeight / 2.0 //26 - } else { - centerY = getHudView().bounds.midY - } - getIndefiniteAnimatedView().center = CGPoint(x: getHudView().bounds.midX, y: centerY) - if CGFloat(progress) != IHProgressHUDUndefinedProgress { - getRingView().center = CGPoint(x: getHudView().bounds.midX , y: centerY) - getBackgroundRingView().center = getRingView().center - } - getImageView().center = CGPoint(x: getHudView().bounds.midX , y: centerY) - // Label - if imageUsed || progressUsed { - if imageUsed { - centerY = getImageView().frame.maxY + IHProgressHUDLabelSpacing + labelHeight / 2.0 - } else { - centerY = getIndefiniteAnimatedView().frame.maxY + IHProgressHUDLabelSpacing + labelHeight / 2.0 - } - } else { - centerY = getHudView().bounds.midY - } - getStatusLabel().frame = labelRect - getStatusLabel().center = CGPoint(x: getHudView().bounds.midX , y: centerY) - CATransaction.commit() - } - - private func registerNotifications() { - #if os(iOS) - if #available(iOS 13.0, *) { - NotificationCenter.default.addObserver(self, selector: #selector(positionHUD(_:)), name: UIDevice.orientationDidChangeNotification, object: nil) - } else { - NotificationCenter.default.addObserver(self, selector: #selector(positionHUD(_:)), name: UIApplication.didChangeStatusBarOrientationNotification, object: nil) - } - NotificationCenter.default.addObserver(self, selector: #selector(self.positionHUD(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(self.positionHUD(_:)), name: UIResponder.keyboardDidHideNotification, object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(self.positionHUD(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(self.positionHUD(_:)), name: UIResponder.keyboardDidShowNotification, object: nil) - #endif - NotificationCenter.default.addObserver(self, selector: #selector(self.positionHUD(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) - } - - private func fadeOutEffects() { - if defaultStyle == .custom { - getHudView().effect = nil - } - getHudView().backgroundColor = .clear - getBackGroundView().alpha = 0.0 - - getImageView().alpha = 0.0 - getStatusLabel().alpha = 0.0 - getIndefiniteAnimatedView().alpha = 0.0 - getRingView().alpha = 0 - getBackgroundRingView().alpha = 0 - }// - - private func getBackgroundRingView() -> ProgressAnimatedView { - if backgroundRingView == nil { - backgroundRingView = ProgressAnimatedView.init(frame: .zero) - backgroundRingView?.set(strokeEnd: 1.0) - } - - backgroundRingView?.set(strokeColor: foreGroundColorForStyle().withAlphaComponent(0.1)) - backgroundRingView?.set(strokeThickness: ringThickness) - - var radius : CGFloat = 0.0 - if getStatusLabel().text != nil { - radius = ringRadius - } else { - radius = ringNoTextRadius - } - backgroundRingView?.set(radius: radius) - return backgroundRingView! - } - - private func getRingView() -> ProgressAnimatedView { - if ringView == nil { - ringView = ProgressAnimatedView.init(frame: .zero) - } - - ringView?.set(strokeThickness: ringThickness) - ringView?.set(strokeColor: foreGroundColorForStyle()) - var radius : CGFloat = 0.0 - if getStatusLabel().text != nil { - radius = ringRadius - } else { - radius = ringNoTextRadius - } - ringView?.set(radius: radius) - - return ringView! - } - - private func getImageView() -> UIImageView { - if imageView != nil && imageView?.bounds.size != imageViewSize { - imageView?.removeFromSuperview() - imageView = nil - } - - if imageView == nil { - imageView = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: imageViewSize.width, height: imageViewSize.height)) - } - if imageView?.superview == nil { - getHudView().contentView.addSubview(imageView!) - } - - return imageView! - } - - private func getStatusLabel() -> UILabel { - if statusLabel == nil { - statusLabel = UILabel.init(frame: .zero) - statusLabel?.backgroundColor = .clear - statusLabel?.adjustsFontSizeToFitWidth = true - statusLabel?.textAlignment = .center - statusLabel?.baselineAdjustment = .alignCenters - statusLabel?.numberOfLines = 0 - } - if statusLabel?.superview == nil && statusLabel != nil { - getHudView().contentView.addSubview(statusLabel!) - } - statusLabel?.textColor = foreGroundColorForStyle() - statusLabel?.font = font - statusLabel?.alpha = 1.0 - statusLabel?.isHidden = false - return statusLabel! - } - - private func fadeInEffects() { - if defaultStyle != .custom { - var blurStyle = UIBlurEffect.Style.light - if defaultStyle == .dark { - blurStyle = UIBlurEffect.Style.light - } - let blurEffect = UIBlurEffect.init(style: blurStyle) - getHudView().effect = blurEffect - - getHudView().backgroundColor = backgroundColorForStyle().withAlphaComponent(0.6) - } else { - getHudView().backgroundColor = backgroundColorForStyle() - } - - getBackGroundView().alpha = 1.0 - getImageView().alpha = 1.0 - getIndefiniteAnimatedView().alpha = 1.0 - getRingView().alpha = 1.0 - getBackgroundRingView().alpha = 1.0 - } - - private func backgroundColorForStyle() -> UIColor { - if defaultStyle == .light { - return .white - } else if defaultStyle == .dark { - return .black - } else { - let color = hudBackgroundColor ?? backgroundColor! - return color - } - } - - private func getFrontWindow() -> UIWindow? { - if IHProgressHUD.isNotAppExtension { - let frontToBackWindows: NSEnumerator = (UIApplication.shared.windows as NSArray).reverseObjectEnumerator() - for window in frontToBackWindows { - guard let win : UIWindow = window as? UIWindow else {return nil} - let windowOnMainScreen: Bool = win.screen == UIScreen.main - let windowIsVisible: Bool = !win.isHidden && (win.alpha > 0) - var windowLevelSupported = false - windowLevelSupported = win.windowLevel >= UIWindow.Level.normal && win.windowLevel <= maxSupportedWindowLevel - - let windowKeyWindow = win.isKeyWindow - print("=====================================") - print("windowOnMainScreen: \(windowOnMainScreen)") - print("windowIsVisible: \(windowIsVisible)") - print("windowLevelSupported: \(windowLevelSupported)") - print("windowKeyWindow: \(windowKeyWindow)") - - if windowOnMainScreen && windowIsVisible && windowLevelSupported && windowKeyWindow { - return win - } - } - } - return nil - } - - private func getVisibleKeyboardHeight() -> CGFloat { - if IHProgressHUD.isNotAppExtension { - var keyboardWindow : UIWindow? = nil - for testWindow in UIApplication.shared.windows { - if !testWindow.self.isEqual(UIWindow.self) { - keyboardWindow = testWindow - break - } - } - for possibleKeyboard in keyboardWindow?.subviews ?? [] { - var viewName = String.init(describing: possibleKeyboard.self) - if viewName.hasPrefix("UI") { - if viewName.hasSuffix("PeripheralHostView") || viewName.hasSuffix("Keyboard") { - return possibleKeyboard.bounds.height - } else if viewName.hasSuffix("InputSetContainerView") { - for possibleKeyboardSubview: UIView? in possibleKeyboard.subviews { - viewName = String.init(describing: possibleKeyboardSubview.self) - if viewName.hasPrefix("UI") && viewName.hasSuffix("InputSetHostView") { - let convertedRect = possibleKeyboard.convert(possibleKeyboardSubview?.frame ?? CGRect.zero, to: self) - let intersectedRect: CGRect = convertedRect.intersection(bounds) - if !intersectedRect.isNull { - return intersectedRect.height - } - } - } - } - } - } - } - return 0 - } - - #if os(iOS) - private func updateMotionEffectForOrientation(_ orientation: UIInterfaceOrientation) { - let xMotionEffectType: UIInterpolatingMotionEffect.EffectType = orientation.isPortrait ? .tiltAlongHorizontalAxis : .tiltAlongVerticalAxis - let yMotionEffectType: UIInterpolatingMotionEffect.EffectType = orientation.isPortrait ? .tiltAlongVerticalAxis : .tiltAlongHorizontalAxis - updateMotionEffect(forXMotionEffectType: xMotionEffectType, yMotionEffectType: yMotionEffectType) - } - #endif - - private func updateMotionEffect(forXMotionEffectType xMotionEffectType: UIInterpolatingMotionEffect.EffectType, yMotionEffectType: UIInterpolatingMotionEffect.EffectType) { - let effectX = UIInterpolatingMotionEffect(keyPath: "center.x", type: xMotionEffectType) - effectX.minimumRelativeValue = -IHProgressHUDParallaxDepthPoints - effectX.maximumRelativeValue = IHProgressHUDParallaxDepthPoints - - let effectY = UIInterpolatingMotionEffect(keyPath: "center.y", type: yMotionEffectType) - effectY.minimumRelativeValue = -IHProgressHUDParallaxDepthPoints - effectY.maximumRelativeValue = IHProgressHUDParallaxDepthPoints - - let effectGroup = UIMotionEffectGroup() - effectGroup.motionEffects = [effectX, effectY] - - // Clear old motion effect, then add new motion effects - getHudView().motionEffects = [] - getHudView().addMotionEffect(effectGroup) - } - - private func move(to newCenter: CGPoint, rotateAngle angle: CGFloat) { - getHudView().transform = CGAffineTransform(rotationAngle: angle) - guard let container = containerView else { - getHudView().center = CGPoint(x: newCenter.x + offsetFromCenter.horizontal, y: newCenter.y + offsetFromCenter.vertical) - return - } - getHudView().center = CGPoint(x: container.center.x + offsetFromCenter.horizontal, y: container.center.y + offsetFromCenter.vertical) - } -} - -extension IHProgressHUD { - - public class func set(defaultStyle style: IHProgressHUDStyle) { - sharedView.defaultStyle = style - } - - public class func setHUD(backgroundColor color: UIColor) { - sharedView.defaultStyle = .custom - sharedView.hudBackgroundColor = color - } - - public class func set(defaultMaskType maskType: IHProgressHUDMaskType) { - sharedView.defaultMaskType = maskType - } - - public class func set(defaultAnimationType type: IHProgressHUDAnimationType) { - sharedView.defaultAnimationType = type - } - - public class func set(status: String?) { - sharedView.setStatus(status) - } - - public class func set(containerView: UIView?) { - sharedView.containerView = containerView - } // default is window level - - public class func set(minimumSize: CGSize) { - sharedView.minimumSize = minimumSize - } - - // default is CGSizeZero, can be used to avoid resizing for a larger message - - public class func set(ringThickness: CGFloat) { - sharedView.ringThickness = ringThickness - } // default is 2 pt - - public class func set(ringRadius : CGFloat) { - sharedView.ringRadius = ringRadius - }// default is 18 pt - - public class func setRing(noTextRingRadius radius: CGFloat) { - sharedView.ringNoTextRadius = radius - } // default is 24 pt - - public class func set(cornerRadius: CGFloat) { - sharedView.cornerRadius = cornerRadius - }// default is 14 pt - - public class func set(borderColor color : UIColor) { - sharedView.getHudView().layer.borderColor = color.cgColor - - }// default is nil - - public class func set(borderWidth width: CGFloat) { - sharedView.getHudView().layer.borderWidth = width - }// default is 0 - - public class func set(font: UIFont) { - sharedView.font = font - } // default is [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline] - - public class func set(foregroundColor color: UIColor) { - sharedView.foregroundColor = color - // sharedView.defaultStyle = .custom - } - // default is [UIColor blackColor], only used for ProgressHUDStyleCustom - - public class func set(backgroundColor color: UIColor) { - sharedView.backgroundColor = color - sharedView.defaultStyle = .custom - } // default is [UIColor whiteColor], only used for ProgressHUDStyleCustom - - public class func set(backgroundLayerColor color: UIColor) { - sharedView.backgroundLayerColor = color - } // default is [UIColor colorWithWhite:0 alpha:0.5], only used for ProgressHUDMaskTypeCustom - - public class func set(imageViewSize size: CGSize) { - sharedView.imageViewSize = size - } // default is 28x28 pt - - public class func set(shouldTintImages: Bool) { - sharedView.shouldTintImages = shouldTintImages - } // default is YES - - public class func set(infoImage image: UIImage) { - sharedView.infoImage = image - } // default is the bundled info image provided by Freepik - - public class func setSuccessImage(successImage image: UIImage) { - sharedView.successImage = image - } // default is the bundled success image provided by Freepik - - public class func setErrorImage(errorImage image: UIImage) { - sharedView.errorImage = image - } // default is the bundled error image provided by Freepik - - public class func set(viewForExtension view: UIView) { - IHProgressHUD.isNotAppExtension = false - sharedView.viewForExtension = view - }// default is nil, only used if #define SV_APP_EXTENSIONS is set - - public class func set(graceTimeInterval interval: TimeInterval) { - sharedView.graceTimeInterval = interval - } // default is 0 seconds - - public class func set(minimumDismiss interval: TimeInterval) { - sharedView.minimumDismissTimeInterval = interval - } // default is 5.0 seconds - - public class func set(maximumDismissTimeInterval interval: TimeInterval) { - sharedView.maximumDismissTimeInterval = interval - } // default is infinite - - public class func setFadeInAnimationDuration(fadeInAnimationDuration duration: TimeInterval) { - sharedView.fadeInAnimationDuration = duration - } // default is 0.15 seconds - - public class func setFadeOutAnimationDuration(fadeOutAnimationDuration duration: TimeInterval) { - sharedView.fadeOutAnimationDuration = duration - } // default is 0.15 seconds - - public class func setMaxSupportedWindowLevel(maxSupportedWindowLevel windowLevel: UIWindow.Level) { - sharedView.maxSupportedWindowLevel = windowLevel - } // default is UIWindowLevelNormal - - public class func setHapticsEnabled(hapticsEnabled: Bool) { - sharedView.hapticsEnabled = hapticsEnabled - } // default is NO - - - // MARK: - Show Methods - public class func show() { - show(withStatus: nil) - } - - public class func show(withStatus status: String?) { - show(progress: IHProgressHUDUndefinedProgress, status: status) - } - - public class func show(progress: CGFloat) { - show(progress: progress, status: nil) - } - - public class func show(progress: CGFloat, status: String?) { - sharedView.showProgress(progress: Float(progress), status: status) - } - - public class func setOffsetFromCenter(_ offset: UIOffset) { - sharedView.offsetFromCenter = offset - } - - public class func resetOffsetFromCenter() { - setOffsetFromCenter(.zero) - } - - public class func popActivity() { - if sharedView.activityCount > 0 { - sharedView.activityCount -= 1 - } - if sharedView.activityCount == 0 { - sharedView.dismiss() - } - } // decrease activity count, if activity count == 0 the HUD is dismissed - - public class func dismiss() { - dismissWithDelay(0.0) - } - - public class func dismissWithCompletion(_ completion: (() -> Void)?) { - dismissWithDelay(0.0, completion: completion) - } - - public class func dismissWithDelay(_ delay: TimeInterval) { - dismissWithDelay(delay, completion: nil) - } - - public class func dismissWithDelay(_ delay: TimeInterval, completion: (() -> Void)?) { - sharedView.dismissWithDelay(delay, completion: completion) - } - - public class func isVisible() -> Bool { - return sharedView.getBackGroundView().alpha > 0.0 - } - - public class func displayDurationForString(_ string:String?) -> TimeInterval { - let minimum = max(CGFloat(string?.count ?? 0) * 0.06 + 0.5, CGFloat(sharedView.minimumDismissTimeInterval)) - return TimeInterval(min(minimum, CGFloat(sharedView.maximumDismissTimeInterval))) - } - - public class func showInfowithStatus(_ status: String?) { - showImage(sharedView.infoImage, status: status) - #if os(iOS) - if #available(iOS 10.0, *) { - sharedView.hapticGenerator?.notificationOccurred(.warning) - } - #endif - } - - public class func showImage(_ image: UIImage, status: String?) { - let displayInterval = displayDurationForString(status) - sharedView.show(image: image, status: status, duration: displayInterval) - } - - public class func showSuccesswithStatus(_ status: String?) { - showImage(sharedView.successImage, status: status) - #if os(iOS) - if #available(iOS 10.0, *) { - sharedView.hapticGenerator?.notificationOccurred(.success) - } - #endif - } - - public class func showError(withStatus status: String?) { - showImage(sharedView.errorImage, status: status) - #if os(iOS) - if #available(iOS 10.0, *) { - sharedView.hapticGenerator?.notificationOccurred(.error) - } - #endif - } -} -//MARK: - -extension IHProgressHUD { - private func setGrace(timer: Timer?) { - if (graceTimer != nil) { - graceTimer?.invalidate() - graceTimer = nil - } else { - if timer != nil { - graceTimer = timer - } - } - } - - private func setFadeOut(timer: Timer?) { - if (fadeOutTimer != nil) { - fadeOutTimer?.invalidate() - fadeOutTimer = nil - } - if timer != nil { - fadeOutTimer = timer - } - } -} - -//MARK: - Instance Getter Methods -extension IHProgressHUD { - private func foreGroundColorForStyle() -> UIColor { - guard let color = foregroundColor else { - if defaultStyle == .light { - return .black - } else if defaultStyle == .dark { - return .white - } else { - return .black - } - } - return color - } - - private func getHudView() -> UIVisualEffectView { - if hudView == nil { - let tmphudView = UIVisualEffectView() - tmphudView.layer.masksToBounds = true - tmphudView.autoresizingMask = [.flexibleBottomMargin, .flexibleTopMargin, .flexibleRightMargin, .flexibleLeftMargin] - hudView = tmphudView - hudView?.accessibilityLabel = "HUD View" - } - - if hudView?.superview == nil { - self.addSubview(hudView!) - } - - hudView?.layer.cornerRadius = cornerRadius - return hudView! - } - - private func getBackGroundView() -> UIView { - if backgroundView == nil { - backgroundView = UIView() - backgroundView?.autoresizingMask = [.flexibleWidth, .flexibleHeight] - } - if backgroundView?.superview == nil { - insertSubview(self.backgroundView!, belowSubview: getHudView()) - } - // Update styling - if defaultMaskType == .gradient { - if (backgroundRadialGradientLayer == nil) { - backgroundRadialGradientLayer = RadialGradientLayer() - } - if (backgroundRadialGradientLayer?.superlayer == nil) { - backgroundView!.layer.insertSublayer(backgroundRadialGradientLayer!, at: 0) - } - } else { - if ((backgroundRadialGradientLayer != nil) && (backgroundRadialGradientLayer?.superlayer != nil)) { - backgroundRadialGradientLayer?.removeFromSuperlayer() - } - if defaultMaskType == .black { - backgroundView?.backgroundColor = UIColor(white: 0, alpha: 0.4) - } else if defaultMaskType == .custom { - backgroundView?.backgroundColor = backgroundLayerColor - } else { - backgroundView?.backgroundColor = UIColor.clear - } - } - - // Update frame - if backgroundView != nil { - backgroundView?.frame = bounds - } - if backgroundRadialGradientLayer != nil { - backgroundRadialGradientLayer?.frame = bounds - - // Calculate the new center of the gradient, it may change if keyboard is visible - var gradientCenter: CGPoint = center - gradientCenter.y = (bounds.size.height - visibleKeyboardHeight) / 2 - backgroundRadialGradientLayer?.gradientCenter = gradientCenter - backgroundRadialGradientLayer?.setNeedsDisplay() - } - return backgroundView! - } - - private func getControlView() -> UIControl { - if controlView == nil { - controlView = UIControl.init() - controlView?.autoresizingMask = [.flexibleWidth, .flexibleHeight] - controlView?.backgroundColor = .clear - controlView?.isUserInteractionEnabled = true - controlView?.addTarget(self, action: #selector(controlViewDidReceiveTouchEvent(_:for:)), for: .touchDown) - } - if IHProgressHUD.isNotAppExtension { - if let windowBounds : CGRect = UIApplication.shared.delegate?.window??.bounds { - controlView?.frame = windowBounds - } - } - else { - controlView?.frame = UIScreen.main.bounds - } - return controlView! - } - - private func loadImageBundle(named imageName:String) -> UIImage? { - var imageBundle = Bundle.init(for: IHProgressHUD.self) - if let resourcePath = imageBundle.path(forResource: "IHProgressHUD", ofType: "bundle") { - if let resourcesBundle = Bundle(path: resourcePath) { - imageBundle = resourcesBundle - } - } - - return (UIImage(named: imageName, in: imageBundle, compatibleWith: nil)) - } -} diff --git a/AutoCat/ThirdParty/IHProgressHUD/IndefiniteAnimatedView.swift b/AutoCat/ThirdParty/IHProgressHUD/IndefiniteAnimatedView.swift deleted file mode 100755 index 0911028..0000000 --- a/AutoCat/ThirdParty/IHProgressHUD/IndefiniteAnimatedView.swift +++ /dev/null @@ -1,197 +0,0 @@ -// -// Converted to Swift 4 by Swiftify v4.2.29618 - https://objectivec2swift.com/ -// -// IndefiniteAnimatedView.swift -// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD -// -// Original Copyright (c) 2014-2018 Guillaume Campagna. All rights reserved. -// Modified Copyright © 2018 Ibrahim Hassan. All rights reserved. -// - -import UIKit - -class IndefiniteAnimatedView : UIView { - - private var activityIndicator : UIActivityIndicatorView? - private var strokeThickness : CGFloat? - private var strokeColor : UIColor? - private var indefinteAnimatedLayer : CAShapeLayer? - private var radius : CGFloat? - - override init(frame: CGRect) { - super.init(frame: frame) - if self.superview != nil { - layoutAnimatedLayer() - } - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -//MARK: - Setter Functions -extension IndefiniteAnimatedView { - - func setIndefinite(radius: CGFloat) { - if (self.radius != radius) { - self.radius = radius - - self.getIndefinteAnimatedLayer().removeFromSuperlayer() - self.indefinteAnimatedLayer = nil - - if superview != nil { - layoutAnimatedLayer() - } - } - } - - func setIndefinite(strokeThickness : CGFloat) { - self.strokeThickness = strokeThickness - if let strkthickness = self.strokeThickness { - getIndefinteAnimatedLayer().lineWidth = strkthickness - } - } - - func setIndefinite(strokeColor: UIColor) { - self.strokeColor = strokeColor - getIndefinteAnimatedLayer().strokeColor = strokeColor.cgColor - } - -} - -//MARK: - Getter Functions -extension IndefiniteAnimatedView { - private func getIndefinteAnimatedLayer() -> CAShapeLayer { - if self.indefinteAnimatedLayer != nil { - return self.indefinteAnimatedLayer! - } else { - let localRingRadius : CGFloat = radius ?? 18 - let localStrokeThickness : CGFloat = strokeThickness ?? 2 - let localStrokeColor : UIColor = strokeColor ?? UIColor.black - - let arcCenter = CGPoint(x: localRingRadius + localStrokeThickness / 2 + 5, y: localRingRadius + localStrokeThickness / 2 + 5) - let smoothedPath = UIBezierPath(arcCenter: arcCenter, radius: localRingRadius, startAngle: -CGFloat.pi / 2, endAngle: CGFloat.pi + CGFloat.pi / 2, clockwise: true) - - indefinteAnimatedLayer = CAShapeLayer() - indefinteAnimatedLayer?.contentsScale = UIScreen.main.scale - indefinteAnimatedLayer?.frame = CGRect.init(x: 0, y: 0, width: arcCenter.x * 2, height: arcCenter.y * 2) - indefinteAnimatedLayer?.fillColor = UIColor.clear.cgColor - indefinteAnimatedLayer?.strokeColor = localStrokeColor.cgColor - indefinteAnimatedLayer?.lineWidth = localStrokeThickness - indefinteAnimatedLayer?.lineCap = CAShapeLayerLineCap.round - indefinteAnimatedLayer?.lineJoin = CAShapeLayerLineJoin.bevel - indefinteAnimatedLayer?.path = smoothedPath.cgPath - - let maskLayer = CALayer() - let image = loadImageBundle(named: "angle-mask")! - maskLayer.contents = image.cgImage - maskLayer.frame = indefinteAnimatedLayer!.bounds - indefinteAnimatedLayer?.mask = maskLayer - - let animationDuration = TimeInterval.init(1) - let linearCurve = CAMediaTimingFunction.init(name: .linear) - let animation = CABasicAnimation.init(keyPath: "transform.rotation") - animation.fromValue = 0 - animation.toValue = CGFloat.pi * 2 - animation.duration = animationDuration - animation.timingFunction = linearCurve - animation.isRemovedOnCompletion = false - animation.repeatCount = .infinity - animation.fillMode = .forwards - animation.autoreverses = false - indefinteAnimatedLayer?.mask?.add(animation, forKey: "rotate") - - - let animationGroup = CAAnimationGroup.init() - animationGroup.duration = animationDuration - animationGroup.repeatCount = .infinity - animationGroup.isRemovedOnCompletion = false - animationGroup.timingFunction = linearCurve - - let strokeStartAnimation = CABasicAnimation.init(keyPath: "strokeStart") - strokeStartAnimation.duration = animationDuration - strokeStartAnimation.fromValue = 0.015 - strokeStartAnimation.toValue = 0.0001 - - animationGroup.animations = [strokeStartAnimation] - indefinteAnimatedLayer?.add(animationGroup, forKey: "progress") - } - return self.indefinteAnimatedLayer! - } -} - -//MARK: - ActivityIndicatorView Functions -extension IndefiniteAnimatedView { - - func removeAnimationLayer() { - for view in self.subviews { - if let activityView = view as? UIActivityIndicatorView { - activityView.removeFromSuperview() - } - } - getIndefinteAnimatedLayer().removeFromSuperlayer() - } - - func startAnimation() { - if let activityIndicator = activityIndicator { - self.addSubview(activityIndicator) - activityIndicator.frame = CGRect.init(x: 8, y: 8, width: self.frame.size.width - 16, height: self.frame.size.height - 16) - } - } - - func stopActivityIndicator() { - activityIndicator?.stopAnimating() - } - - func setActivityIndicator(color: UIColor) { - activityIndicator = UIActivityIndicatorView.init(style: UIActivityIndicatorView.Style.large) - activityIndicator?.hidesWhenStopped = true - activityIndicator?.startAnimating() - activityIndicator?.color = color - } -} -//MARK: - -extension IndefiniteAnimatedView { - override func willMove(toSuperview newSuperview: UIView?) { - if let _ = newSuperview { - layoutAnimatedLayer() - } else { - getIndefinteAnimatedLayer().removeFromSuperlayer() - indefinteAnimatedLayer = nil - } - } - - private func layoutAnimatedLayer() { - let calayer = getIndefinteAnimatedLayer() - self.layer.addSublayer(calayer) - let widthDiff: CGFloat = bounds.width - layer.bounds.width - let heightDiff: CGFloat = bounds.height - layer.bounds.height - let xPos = bounds.width - layer.bounds.width / 2 - widthDiff / 2 - let yPos = bounds.height - layer.bounds.height / 2 - heightDiff / 2 - calayer.position = CGPoint.init(x: xPos, y: yPos) - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - let localRadius : CGFloat = radius ?? 18 - let localStrokeThickness : CGFloat = strokeThickness ?? 2 - for view in self.subviews { - if let _ = view as? UIActivityIndicatorView { - return CGSize.init(width: 50, height: 50) - } - } - return CGSize.init(width: (localRadius + localStrokeThickness / 2 + 5) * 2, height: (localRadius + localStrokeThickness / 2 + 5) * 2) - } - - private func loadImageBundle(named imageName:String) -> UIImage? { - var imageBundle = Bundle.init(for: IndefiniteAnimatedView.self) - if let resourcePath = imageBundle.path(forResource: "IHProgressHUD", ofType: "bundle") { - if let resourcesBundle = Bundle(path: resourcePath) { - imageBundle = resourcesBundle - } - } - - return (UIImage(named: imageName, in: imageBundle, compatibleWith: nil)) - } -} - diff --git a/AutoCat/ThirdParty/IHProgressHUD/ProgressAnimatedView.swift b/AutoCat/ThirdParty/IHProgressHUD/ProgressAnimatedView.swift deleted file mode 100755 index 5437310..0000000 --- a/AutoCat/ThirdParty/IHProgressHUD/ProgressAnimatedView.swift +++ /dev/null @@ -1,128 +0,0 @@ -// -// Converted to Swift 4 by Swiftify v4.2.29618 - https://objectivec2swift.com/ -// -// IndefiniteAnimatedView.swift -// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD -// -// Original Copyright (c) 2014-2018 Guillaume Campagna. All rights reserved. -// Modified Copyright © 2018 Ibrahim Hassan. All rights reserved. -// - -import UIKit - -class ProgressAnimatedView: UIView { - - private var radius : CGFloat? - private var strokeThickness : CGFloat? - private var strokeColor : UIColor? - private var strokeEnd : CGFloat? - private var ringAnimatedLayer : CAShapeLayer? - - override init(frame: CGRect) { - super.init(frame: frame) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func willMove(toSuperview newSuperview: UIView?) { - if let _ = newSuperview { - layoutAnimatedLayer() - } else { - getRingAnimatedLayer().removeFromSuperlayer() - ringAnimatedLayer = nil - } - } - - func layoutAnimatedLayer() { - let rlayer = getRingAnimatedLayer() - layer.addSublayer(rlayer) - let widthDiff = bounds.width - layer.bounds.width - let heightDiff = bounds.height - layer.bounds.height - let layerPositionX = bounds.width - layer.bounds.width / 2 - widthDiff / 2 - let layerPositionY = bounds.height - layer.bounds.height / 2 - heightDiff / 2 - rlayer.position = CGPoint.init(x: layerPositionX, y: layerPositionY) - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - let localRadius : CGFloat = radius ?? 18 - let localStrokeThickness : CGFloat = strokeThickness ?? 2 - return CGSize(width: (localRadius + localStrokeThickness / 2 + 5) * 2, height: (localRadius + localStrokeThickness / 2 + 5) * 2) - } - -} - -//MARK: - Setter -extension ProgressAnimatedView { - @objc public func set(radius: CGFloat) { - if radius != self.radius { - self.radius = radius - - getRingAnimatedLayer().removeFromSuperlayer() - ringAnimatedLayer = nil - - if superview != nil { - layoutAnimatedLayer() - } - } - } - - func set(strokeThickness : CGFloat) { - self.strokeThickness = strokeThickness - getRingAnimatedLayer().lineWidth = strokeThickness - - if superview != nil { - layoutAnimatedLayer() - } - - } - - func set(strokeEnd: CGFloat) { - self.strokeEnd = strokeEnd - getRingAnimatedLayer().strokeEnd = strokeEnd - - if superview != nil { - layoutAnimatedLayer() - } - - } - - func set(strokeColor: UIColor) { - - self.strokeColor = strokeColor - self.getRingAnimatedLayer().strokeColor = strokeColor.cgColor - - if superview != nil { - layoutAnimatedLayer() - } - } -} - -//MARK: - Getter -extension ProgressAnimatedView { - private func getRingAnimatedLayer() -> CAShapeLayer { - if self.ringAnimatedLayer != nil { - return self.ringAnimatedLayer! - } else { - let localStrokeThickness: CGFloat = strokeThickness ?? 2 - let localRingRadius: CGFloat = radius ?? 18 - - let arcCenter = CGPoint(x: localRingRadius + localStrokeThickness / 2 + 5, y: localRingRadius + localStrokeThickness / 2 + 5) - let smoothedPath = UIBezierPath(arcCenter: arcCenter, radius: localRingRadius, startAngle: -CGFloat.pi / 2, endAngle: CGFloat.pi + CGFloat.pi / 2, clockwise: true) - - let _ringAnimatedLayer = CAShapeLayer() - _ringAnimatedLayer.contentsScale = UIScreen.main.scale - _ringAnimatedLayer.frame = CGRect(x: 0.0, y: 0.0, width: arcCenter.x * 2, height: arcCenter.y * 2) - _ringAnimatedLayer.fillColor = UIColor.clear.cgColor - _ringAnimatedLayer.strokeColor = strokeColor?.cgColor - _ringAnimatedLayer.lineWidth = localStrokeThickness - _ringAnimatedLayer.lineCap = .round - _ringAnimatedLayer.lineJoin = .bevel - _ringAnimatedLayer.path = smoothedPath.cgPath - self.ringAnimatedLayer = _ringAnimatedLayer - } - return self.ringAnimatedLayer! - } - -} diff --git a/AutoCat/ThirdParty/IHProgressHUD/RadialGradientLayer.swift b/AutoCat/ThirdParty/IHProgressHUD/RadialGradientLayer.swift deleted file mode 100755 index 1be0c08..0000000 --- a/AutoCat/ThirdParty/IHProgressHUD/RadialGradientLayer.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// Converted to Swift 4 by Swiftify v4.2.29618 - https://objectivec2swift.com/ -// -// IndefiniteAnimatedView.swift -// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD -// -// Original Copyright (c) 2014-2018 Guillaume Campagna. All rights reserved. -// Modified Copyright © 2018 Ibrahim Hassan. All rights reserved. -// - -import QuartzCore - -class RadialGradientLayer: CALayer { - var gradientCenter = CGPoint.zero - override func draw(in context: CGContext) { - super.draw(in: context) - let locationsCount = 2 - let locations : [CGFloat] = [0.0, 1.0] - let colors : [CGFloat] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.75] - let colorSpace = CGColorSpaceCreateDeviceRGB() - if let gradient = CGGradient.init(colorSpace: colorSpace, colorComponents: colors, locations: locations, count: locationsCount) { - let radius = min(bounds.size.width, bounds.size.height) - - context.drawRadialGradient(gradient, startCenter: gradientCenter, startRadius: 0, endCenter: gradientCenter, endRadius: radius, options: CGGradientDrawingOptions.drawsAfterEndLocation) - } - } -} diff --git a/AutoCat/ThirdParty/RxRealmDataSources/Reactive+RxRealmDataSources.swift b/AutoCat/ThirdParty/RxRealmDataSources/Reactive+RxRealmDataSources.swift deleted file mode 100644 index c51ca48..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/Reactive+RxRealmDataSources.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -#if os(iOS) -// MARK: - iOS / UIKit - -import UIKit -extension Reactive where Base: UITableView { - - public func realmChanges(_ dataSource: RxTableViewRealmDataSource) - -> RealmBindObserver, RxTableViewRealmDataSource> { - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if ds.tableView == nil { - ds.tableView = self.base - } - ds.tableView?.dataSource = ds - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } - - public func realmModelSelected(_ modelType: E.Type) -> ControlEvent where E: RealmSwift.Object { - - let source: Observable = self.itemSelected.flatMap { [weak view = self.base as UITableView] indexPath -> Observable in - guard let view = view, let ds = view.dataSource as? RxTableViewRealmDataSource else { - return Observable.empty() - } - - return Observable.just(ds.model(at: indexPath)) - } - - return ControlEvent(events: source) - } - -} - -extension Reactive where Base: UICollectionView { - - public func realmChanges(_ dataSource: RxCollectionViewRealmDataSource) - -> RealmBindObserver, RxCollectionViewRealmDataSource> { - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if ds.collectionView == nil { - ds.collectionView = self.base - } - ds.collectionView?.dataSource = ds - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } - - public func realmModelSelected(_ modelType: E.Type) -> ControlEvent where E: RealmSwift.Object { - - let source: Observable = self.itemSelected.flatMap { [weak view = self.base as UICollectionView] indexPath -> Observable in - guard let view = view, let ds = view.dataSource as? RxCollectionViewRealmDataSource else { - return Observable.empty() - } - - return Observable.just(ds.model(at: indexPath)) - } - - return ControlEvent(events: source) - } -} - - -#elseif os(OSX) -// MARK: - macOS / Cocoa - -import Cocoa -extension Reactive where Base: NSTableView { - - public func realmChanges(_ dataSource: RxTableViewRealmDataSource) - -> RealmBindObserver, RxTableViewRealmDataSource> { - - base.delegate = dataSource - base.dataSource = dataSource - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if dataSource.tableView == nil { - dataSource.tableView = self.base - } - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } -} - -extension Reactive where Base: NSCollectionView { - - public func realmChanges(_ dataSource: RxCollectionViewRealmDataSource) - -> RealmBindObserver, RxCollectionViewRealmDataSource> { - - return RealmBindObserver(dataSource: dataSource) {ds, results, changes in - if ds.collectionView == nil { - ds.collectionView = self.base - } - ds.collectionView?.dataSource = ds - ds.applyChanges(items: AnyRealmCollection(results), changes: changes) - } - } -} - -#endif diff --git a/AutoCat/ThirdParty/RxRealmDataSources/RealmBindObserver.swift b/AutoCat/ThirdParty/RxRealmDataSources/RealmBindObserver.swift deleted file mode 100644 index a60b378..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/RealmBindObserver.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -public class RealmBindObserver: ObserverType { - typealias BindingType = (DS, C, RealmChangeset?) -> Void - public typealias E = (C, RealmChangeset?) - - let dataSource: DS - let binding: BindingType - - init(dataSource: DS, binding: @escaping BindingType) { - self.dataSource = dataSource - self.binding = binding - } - - public func on(_ event: Event) { - switch event { - case .next(let element): - binding(dataSource, element.0, element.1) - case .error: - return - case .completed: - return - } - } - - func asObserver() -> AnyObserver { - return AnyObserver(eventHandler: on) - } -} diff --git a/AutoCat/ThirdParty/RxRealmDataSources/RxCollectionViewRealmDataSource.swift b/AutoCat/ThirdParty/RxRealmDataSources/RxCollectionViewRealmDataSource.swift deleted file mode 100644 index 8883732..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/RxCollectionViewRealmDataSource.swift +++ /dev/null @@ -1,210 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -#if os(iOS) - // MARK: - iOS / UIKit - - import UIKit - - public typealias CollectionCellFactory = (RxCollectionViewRealmDataSource, UICollectionView, IndexPath, E) -> UICollectionViewCell - public typealias CollectionCellConfig = (CellType, IndexPath, E) -> Void - - open class RxCollectionViewRealmDataSource : NSObject, UICollectionViewDataSource { - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var collectionView: UICollectionView? - public var animated = true - - // MARK: - Init - public let cellIdentifier: String - public let cellFactory: CollectionCellFactory - - public init(cellIdentifier: String, cellFactory: @escaping CollectionCellFactory) { - self.cellIdentifier = cellIdentifier - self.cellFactory = cellFactory - } - - public init(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping CollectionCellConfig) where CellType: UICollectionViewCell { - self.cellIdentifier = cellIdentifier - self.cellFactory = {ds, cv, ip, model in - let cell = cv.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: ip) as! CellType - cellConfig(cell, ip, model) - return cell - } - } - - // MARK: - Data access - public func model(at indexPath: IndexPath) -> E { - return items![indexPath.row] - } - - // MARK: - UICollectionViewDataSource protocol - public func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return items?.count ?? 0 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - return cellFactory(self, collectionView, indexPath, items![indexPath.row]) - } - - // MARK: - Applying changeset to the collection view - private let fromRow = {(row: Int) in return IndexPath(row: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let collectionView = collectionView else { - fatalError("You have to bind a collection view to the data source.") - } - - guard animated else { - collectionView.reloadData() - return - } - - guard let changes = changes else { - collectionView.reloadData() - return - } - - let lastItemCount = collectionView.numberOfItems(inSection: 0) - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - collectionView.reloadData() - return - } - - collectionView.performBatchUpdates({[unowned self] in - collectionView.deleteItems(at: changes.deleted.map(self.fromRow)) - collectionView.reloadItems(at: changes.updated.map(self.fromRow)) - collectionView.insertItems(at: changes.inserted.map(self.fromRow)) - }, completion: nil) - } -} - -#elseif os(OSX) -// MARK: - macOS / Cocoa - -import Cocoa - - public typealias CollectionItemFactory = (RxCollectionViewRealmDataSource, NSCollectionView, IndexPath, E) -> NSCollectionViewItem - public typealias CollectionItemConfig = (ItemType, IndexPath, E) -> Void - - open class RxCollectionViewRealmDataSource : NSObject, NSCollectionViewDataSource { - - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var collectionView: NSCollectionView? - public var animated = true - - // MARK: - Init - public let itemIdentifier: String - public let itemFactory: CollectionItemFactory - - public weak var delegate: NSCollectionViewDelegate? - public weak var dataSource: NSCollectionViewDataSource? - - public init(itemIdentifier: String, itemFactory: @escaping CollectionItemFactory) { - self.itemIdentifier = itemIdentifier - self.itemFactory = itemFactory - } - - public init(itemIdentifier: String, itemType: ItemType.Type, itemConfig: @escaping CollectionItemConfig) where ItemType: NSCollectionViewItem { - self.itemIdentifier = itemIdentifier - self.itemFactory = { ds, cv, ip, model in - let item = cv.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: itemIdentifier), for: ip) as! ItemType - itemConfig(item, ip, model) - return item - } - } - - // MARK: - NSCollectionViewDataSource protocol - public func numberOfSections(in collectionView: NSCollectionView) -> Int { - return 1 - } - - public func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { - return items?.count ?? 0 - } - - @available(OSX 10.11, *) - public func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { - return itemFactory(self, collectionView, indexPath, items![indexPath.item]) - } - - // MARK: - Proxy unimplemented data source and delegate methods - open override func responds(to aSelector: Selector!) -> Bool { - if RxCollectionViewRealmDataSource.instancesRespond(to: aSelector) { - return true - } else if let delegate = delegate { - return delegate.responds(to: aSelector) - } else if let dataSource = dataSource { - return dataSource.responds(to: aSelector) - } else { - return false - } - } - - open override func forwardingTarget(for aSelector: Selector!) -> Any? { - return delegate ?? dataSource - } - - // MARK: - Applying changeset to the collection view - private let fromRow = {(row: Int) in return IndexPath(item: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let collectionView = collectionView else { - fatalError("You have to bind a collection view to the data source.") - } - - guard animated else { - collectionView.reloadData() - return - } - - guard let changes = changes else { - collectionView.reloadData() - return - } - - let lastItemCount = collectionView.numberOfItems(inSection: 0) - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - collectionView.reloadData() - return - } - - collectionView.performBatchUpdates({[unowned self] in - //TODO: this should be animated, but doesn't seem to be? - collectionView.animator().deleteItems(at: Set(changes.deleted.map(self.fromRow))) - collectionView.animator().reloadItems(at: Set(changes.updated.map(self.fromRow))) - collectionView.animator().insertItems(at: Set(changes.inserted.map(self.fromRow))) - }, completionHandler: nil) - } - } - - -#endif diff --git a/AutoCat/ThirdParty/RxRealmDataSources/RxTableViewRealmDataSource.swift b/AutoCat/ThirdParty/RxRealmDataSources/RxTableViewRealmDataSource.swift deleted file mode 100644 index c80bb80..0000000 --- a/AutoCat/ThirdParty/RxRealmDataSources/RxTableViewRealmDataSource.swift +++ /dev/null @@ -1,223 +0,0 @@ -// -// RxRealm extensions -// -// Copyright (c) 2016 RxSwiftCommunity. All rights reserved. -// Check the LICENSE file for details -// - -import Foundation - -import RealmSwift -import RxSwift -import RxCocoa -import RxRealm - -#if os(iOS) - // MARK: - iOS / UIKit - - import UIKit - - public typealias TableCellFactory = (RxTableViewRealmDataSource, UITableView, IndexPath, E) -> UITableViewCell - public typealias TableCellConfig = (CellType, IndexPath, E) -> Void - - open class RxTableViewRealmDataSource: NSObject, UITableViewDataSource { - - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var tableView: UITableView? - public var animated = true - public var rowAnimations = ( - insert: UITableView.RowAnimation.automatic, - update: UITableView.RowAnimation.automatic, - delete: UITableView.RowAnimation.automatic) - - public var headerTitle: String? - public var footerTitle: String? - - // MARK: - Init - public let cellIdentifier: String - public let cellFactory: TableCellFactory - - public init(cellIdentifier: String, cellFactory: @escaping TableCellFactory) { - self.cellIdentifier = cellIdentifier - self.cellFactory = cellFactory - } - - public init(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping TableCellConfig) where CellType: UITableViewCell { - self.cellIdentifier = cellIdentifier - self.cellFactory = {ds, tv, ip, model in - let cell = tv.dequeueReusableCell(withIdentifier: cellIdentifier, for: ip) as! CellType - cellConfig(cell, ip, model) - return cell - } - } - - // MARK: - Data access - public func model(at indexPath: IndexPath) -> E { - return items![indexPath.row] - } - - // MARK: - UITableViewDataSource protocol - public func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return items?.count ?? 0 - } - - public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return cellFactory(self, tableView, indexPath, items![indexPath.row]) - } - - public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return headerTitle - } - - public func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return footerTitle - } - - // MARK: - Applying changeset to the table view - private let fromRow = {(row: Int) in return IndexPath(row: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let tableView = tableView else { - fatalError("You have to bind a table view to the data source.") - } - - guard animated else { - tableView.reloadData() - return - } - - guard let changes = changes else { - tableView.reloadData() - return - } - - let lastItemCount = tableView.numberOfRows(inSection: 0) - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - tableView.reloadData() - return - } - - tableView.beginUpdates() - tableView.deleteRows(at: changes.deleted.map(fromRow), with: rowAnimations.delete) - tableView.insertRows(at: changes.inserted.map(fromRow), with: rowAnimations.insert) - tableView.reloadRows(at: changes.updated.map(fromRow), with: rowAnimations.update) - tableView.endUpdates() - } - } - -#elseif os(OSX) - // MARK: - macOS / Cocoa - - import Cocoa - - public typealias TableCellFactory = (RxTableViewRealmDataSource, NSTableView, Int, E) -> NSTableCellView - public typealias TableCellConfig = (CellType, Int, E) -> Void - - open class RxTableViewRealmDataSource: NSObject, NSTableViewDataSource, NSTableViewDelegate { - - private var items: AnyRealmCollection? - - // MARK: - Configuration - - public var tableView: NSTableView? - public var animated = true - public var rowAnimations = ( - insert: NSTableView.AnimationOptions.effectFade, - update: NSTableView.AnimationOptions.effectFade, - delete: NSTableView.AnimationOptions.effectFade) - - public weak var delegate: NSTableViewDelegate? - public weak var dataSource: NSTableViewDataSource? - - // MARK: - Init - public let cellIdentifier: String - public let cellFactory: TableCellFactory - - public init(cellIdentifier: String, cellFactory: @escaping TableCellFactory) { - self.cellIdentifier = cellIdentifier - self.cellFactory = cellFactory - } - - public init(cellIdentifier: String, cellType: CellType.Type, cellConfig: @escaping TableCellConfig) where CellType: NSTableCellView { - self.cellIdentifier = cellIdentifier - self.cellFactory = { ds, tv, row, model in - let cell = tv.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: tv) as! CellType - cellConfig(cell, row, model) - return cell - } - } - - // MARK: - UITableViewDataSource protocol - public func numberOfRows(in tableView: NSTableView) -> Int { - return items?.count ?? 0 - } - - public func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - return cellFactory(self, tableView, row, items![row]) - } - - // MARK: - Proxy unimplemented data source and delegate methods - open override func responds(to aSelector: Selector!) -> Bool { - if RxTableViewRealmDataSource.instancesRespond(to: aSelector) { - return true - } else if let delegate = delegate { - return delegate.responds(to: aSelector) - } else if let dataSource = dataSource { - return dataSource.responds(to: aSelector) - } else { - return false - } - } - - open override func forwardingTarget(for aSelector: Selector!) -> Any? { - return delegate ?? dataSource - } - - // MARK: - Applying changeset to the table view - private let fromRow = {(row: Int) in return IndexPath(item: row, section: 0)} - - func applyChanges(items: AnyRealmCollection, changes: RealmChangeset?) { - if self.items == nil { - self.items = items - } - - guard let tableView = tableView else { - fatalError("You have to bind a table view to the data source.") - } - - guard animated else { - tableView.reloadData() - return - } - - guard let changes = changes else { - tableView.reloadData() - return - } - - let lastItemCount = tableView.numberOfRows - guard items.count == lastItemCount + changes.inserted.count - changes.deleted.count else { - tableView.reloadData() - return - } - - tableView.beginUpdates() - tableView.removeRows(at: IndexSet(changes.deleted), withAnimation: rowAnimations.delete) - tableView.insertRows(at: IndexSet(changes.inserted), withAnimation: rowAnimations.insert) - tableView.reloadData(forRowIndexes: IndexSet(changes.updated), columnIndexes: IndexSet([0])) - tableView.endUpdates() - } - } - -#endif