diff --git a/.swiftlint.yml b/.swiftlint.yml index 2fce9c8de..45694f160 100755 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -28,7 +28,8 @@ included: excluded: - Carthage - Pods - - Riot/Generated/ + - Riot/Generated/ + - Riot/Modules/LaunchLoading/LoadingAnimation/ line_length: warning: 250 diff --git a/Podfile b/Podfile index 86c8e6171..37784efb0 100644 --- a/Podfile +++ b/Podfile @@ -61,7 +61,8 @@ abstract_target 'RiotPods' do # Remove warnings from "bad" pods pod 'OLMKit', :inhibit_warnings => true pod 'cmark', :inhibit_warnings => true - pod 'zxcvbn-ios' + pod 'zxcvbn-ios', :inhibit_warnings => true + pod 'HPGrowingTextView', :inhibit_warnings => true # Tools pod 'SwiftGen', '~> 6.1' @@ -101,12 +102,7 @@ post_install do |installer| # Because the WebRTC pod (included by the JingleCallStack pod) does not support it. # Plus the app does not enable it target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - - # Force SwiftUTI Swift version to 5.0 (as there is no code changes to perform for SwiftUTI fork using Swift 4.2) - if target.name.include? 'SwiftUTI' - config.build_settings['SWIFT_VERSION'] = '5.0' - end + config.build_settings['ENABLE_BITCODE'] = 'NO' end end end diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index fda1d2a5b..05d756727 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -145,9 +145,6 @@ 32FD757924D2C9BA00BA7B37 /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32FD757524D2C9BA00BA7B37 /* Bundle.swift */; }; 32FD757A24D2C9BA00BA7B37 /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32FD757524D2C9BA00BA7B37 /* Bundle.swift */; }; 32FDC1CD2386CD390084717A /* RiotSettingIntegrationProvisioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32FDC1CC2386CD390084717A /* RiotSettingIntegrationProvisioning.swift */; }; - 39D49C6524B8D40500FEDBC8 /* ElementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6224B8D40500FEDBC8 /* ElementViewController.swift */; }; - 39D49C6624B8D40500FEDBC8 /* Timeline_1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6324B8D40500FEDBC8 /* Timeline_1.swift */; }; - 39D49C6724B8D40500FEDBC8 /* ElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D49C6424B8D40500FEDBC8 /* ElementView.swift */; }; 3AF393339D2D566CE14AC200 /* Pods_RiotTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 129EB7E27E7E4AC3F5F098F5 /* Pods_RiotTests.framework */; }; 405FD41D306133A48D9B5AA1 /* Pods_RiotPods_Riot.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACF09217ADF1D7E7A35BC02 /* Pods_RiotPods_Riot.framework */; }; 670966FEFE120D865FD8A5B6 /* Pods_RiotPods_SiriIntents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51187E952D5CECF6D6F5A28E /* Pods_RiotPods_SiriIntents.framework */; }; @@ -186,6 +183,9 @@ B1098C1021ED07E4000DDA48 /* Presentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098C0B21ED07E4000DDA48 /* Presentable.swift */; }; B1098C1121ED07E4000DDA48 /* NavigationRouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098C0C21ED07E4000DDA48 /* NavigationRouterType.swift */; }; B109D6F1222D8C400061B6D9 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = B109D6F0222D8C400061B6D9 /* UIApplication.swift */; }; + B10A3E8E24FE4368007C380F /* ElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8B24FE4367007C380F /* ElementView.swift */; }; + B10A3E8F24FE4368007C380F /* Timeline_1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8C24FE4367007C380F /* Timeline_1.swift */; }; + B10A3E9024FE4368007C380F /* ElementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8D24FE4367007C380F /* ElementViewController.swift */; }; B10CFBC32268D99D00A5842E /* JitsiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10CFBC22268D99D00A5842E /* JitsiService.swift */; }; B1107EC82200B0720038014B /* KeyBackupRecoverSuccessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1107EC72200B0720038014B /* KeyBackupRecoverSuccessViewController.swift */; }; B1107ECA2200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1107EC92200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard */; }; @@ -1060,9 +1060,6 @@ 32FD757524D2C9BA00BA7B37 /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = ""; }; 32FDC1CC2386CD390084717A /* RiotSettingIntegrationProvisioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiotSettingIntegrationProvisioning.swift; sourceTree = ""; }; 3942DD65EBEB7AE647C6392A /* Pods-RiotPods-SiriIntents.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-SiriIntents.debug.xcconfig"; path = "Target Support Files/Pods-RiotPods-SiriIntents/Pods-RiotPods-SiriIntents.debug.xcconfig"; sourceTree = ""; }; - 39D49C6224B8D40500FEDBC8 /* ElementViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementViewController.swift; sourceTree = ""; }; - 39D49C6324B8D40500FEDBC8 /* Timeline_1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timeline_1.swift; sourceTree = ""; }; - 39D49C6424B8D40500FEDBC8 /* ElementView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementView.swift; sourceTree = ""; }; 3D78489021AC9E6400B98A7D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; 3D78489121AC9E6500B98A7D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; 3D78489221AC9E6500B98A7D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Vector.strings; sourceTree = ""; }; @@ -1114,6 +1111,9 @@ B1098C0B21ED07E4000DDA48 /* Presentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Presentable.swift; sourceTree = ""; }; B1098C0C21ED07E4000DDA48 /* NavigationRouterType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationRouterType.swift; sourceTree = ""; }; B109D6F0222D8C400061B6D9 /* UIApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplication.swift; sourceTree = ""; }; + B10A3E8B24FE4367007C380F /* ElementView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementView.swift; sourceTree = ""; }; + B10A3E8C24FE4367007C380F /* Timeline_1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timeline_1.swift; sourceTree = ""; }; + B10A3E8D24FE4367007C380F /* ElementViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementViewController.swift; sourceTree = ""; }; B10CFBC22268D99D00A5842E /* JitsiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiService.swift; sourceTree = ""; }; B1107EC72200B0720038014B /* KeyBackupRecoverSuccessViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverSuccessViewController.swift; sourceTree = ""; }; B1107EC92200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = KeyBackupRecoverSuccessViewController.storyboard; sourceTree = ""; }; @@ -2398,16 +2398,6 @@ path = Config; sourceTree = ""; }; - 39D49C6124B8D3B000FEDBC8 /* LaunchLoadingAnimation */ = { - isa = PBXGroup; - children = ( - 39D49C6424B8D40500FEDBC8 /* ElementView.swift */, - 39D49C6224B8D40500FEDBC8 /* ElementViewController.swift */, - 39D49C6324B8D40500FEDBC8 /* Timeline_1.swift */, - ); - name = LaunchLoadingAnimation; - sourceTree = ""; - }; 4220F60B660591FD80AF3428 /* Pods */ = { isa = PBXGroup; children = ( @@ -2554,6 +2544,16 @@ path = Routers; sourceTree = ""; }; + B10A3E8A24FE4367007C380F /* LoadingAnimation */ = { + isa = PBXGroup; + children = ( + B10A3E8B24FE4367007C380F /* ElementView.swift */, + B10A3E8C24FE4367007C380F /* Timeline_1.swift */, + B10A3E8D24FE4367007C380F /* ElementViewController.swift */, + ); + path = LoadingAnimation; + sourceTree = ""; + }; B1107EC62200B0190038014B /* Success */ = { isa = PBXGroup; children = ( @@ -2699,7 +2699,7 @@ B1560DA024B65A9500490F50 /* LaunchLoading */ = { isa = PBXGroup; children = ( - 39D49C6124B8D3B000FEDBC8 /* LaunchLoadingAnimation */, + B10A3E8A24FE4367007C380F /* LoadingAnimation */, B1560DA124B65AFA00490F50 /* LaunchLoadingView.swift */, B1560DA324B65B3700490F50 /* LaunchLoadingView.xib */, ); @@ -5969,6 +5969,7 @@ B1B558C920EF768F00210D55 /* RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.m in Sources */, B1B5571B20EE6C4D00210D55 /* DeactivateAccountViewController.m in Sources */, B1DCC63922E85E9A00625807 /* EmojiMartStore.swift in Sources */, + B10A3E9024FE4368007C380F /* ElementViewController.swift in Sources */, B1B5590620EF768F00210D55 /* RoomMembershipCollapsedWithPaginationTitleBubbleCell.m in Sources */, B139C21D21FE5BF500BB68EC /* KeyBackupRecoverFromPassphraseViewModelType.swift in Sources */, B157FA9F23264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinator.swift in Sources */, @@ -6143,7 +6144,6 @@ B1B557D820EF5EA900210D55 /* RoomActivitiesView.m in Sources */, B1B9DEE922EB34EF0065E677 /* ReactionHistoryViewController.swift in Sources */, B1B5596620EF9E9B00210D55 /* RoomTableViewCell.m in Sources */, - 39D49C6624B8D40500FEDBC8 /* Timeline_1.swift in Sources */, EC711B7D24A63B37008F830C /* SecretsSetupRecoveryPassphraseViewModel.swift in Sources */, EC711B8024A63B37008F830C /* SecretsSetupRecoveryPassphraseViewState.swift in Sources */, B1C45A89232A8C2600165425 /* SettingsIdentityServerViewController.swift in Sources */, @@ -6206,12 +6206,11 @@ B1B5574720EE6C4D00210D55 /* UsersDevicesViewController.m in Sources */, B1098BFF21ECFE65000DDA48 /* PasswordStrengthView.swift in Sources */, B1B558D220EF768F00210D55 /* RoomEncryptedDataBubbleCell.m in Sources */, + B10A3E8F24FE4368007C380F /* Timeline_1.swift in Sources */, EC711BB024A63B58008F830C /* SecureBackupBannerCell.swift in Sources */, B1B558FA20EF768F00210D55 /* RoomMembershipBubbleCell.m in Sources */, - 39D49C6724B8D40500FEDBC8 /* ElementView.swift in Sources */, B157FAA223264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewAction.swift in Sources */, EC85D6AE2477DC89002C44C9 /* RoundedButton.swift in Sources */, - 39D49C6524B8D40500FEDBC8 /* ElementViewController.swift in Sources */, B1CE83D72422817200D07506 /* KeyVerificationVerifyByScanningViewModelType.swift in Sources */, 3232ABA1225730E100AD6A5C /* KeyVerificationCoordinatorType.swift in Sources */, B1C562D9228C0B760037F12A /* RoomContextualMenuItem.swift in Sources */, @@ -6329,6 +6328,7 @@ B1B9DEEE22EB34EF0065E677 /* ReactionHistoryViewAction.swift in Sources */, EC711BB624A63C11008F830C /* AuthenticatedSessionViewControllerFactory.swift in Sources */, B1C543A4239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift in Sources */, + B10A3E8E24FE4368007C380F /* ElementView.swift in Sources */, B1CE83B62422812100D07506 /* KeyVerificationCoordinatorBridgePresenter.swift in Sources */, 32B94DFA228EC26400716A26 /* ReactionsMenuButton.swift in Sources */, B1B9DEEC22EB34EF0065E677 /* ReactionHistoryViewModelType.swift in Sources */, diff --git a/Riot/Categories/UIApplication.swift b/Riot/Categories/UIApplication.swift index ff16ad049..866c843bc 100644 --- a/Riot/Categories/UIApplication.swift +++ b/Riot/Categories/UIApplication.swift @@ -26,13 +26,8 @@ extension UIApplication { return } - if #available(iOS 10.0, *) { - application.open(url, options: [:], completionHandler: { success in - completion?(success) - }) - } else { - let success = application.openURL(url) + application.open(url, options: [:], completionHandler: { success in completion?(success) - } + }) } } diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index ff25ed412..43933b026 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -42,7 +42,10 @@ final class RiotSettings: NSObject { /// UserDefaults to be used on reads and writes. private lazy var defaults: UserDefaults = { - return UserDefaults(suiteName: BuildSettings.applicationGroupIdentifier)! + guard let userDefaults = UserDefaults(suiteName: BuildSettings.applicationGroupIdentifier) else { + fatalError("[RiotSettings] Fail to load shared UserDefaults") + } + return userDefaults }() // MARK: - Public diff --git a/Riot/Managers/Theme/Theme.swift b/Riot/Managers/Theme/Theme.swift index 3216c6eb9..59bef035b 100644 --- a/Riot/Managers/Theme/Theme.swift +++ b/Riot/Managers/Theme/Theme.swift @@ -93,12 +93,12 @@ import UIKit /// Apply the theme on a navigation bar /// /// - Parameter navigationBar: the navigation bar to customise. - func applyStyle(onNavigationBar: UINavigationBar) + func applyStyle(onNavigationBar navigationBar: UINavigationBar) /// Apply the theme on a search bar. /// /// - Parameter searchBar: the search bar to customise. - func applyStyle(onSearchBar: UISearchBar) + func applyStyle(onSearchBar searchBar: UISearchBar) /// Apply the theme on a text field. /// diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 71f6c3531..35c4ac39b 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -1134,16 +1134,14 @@ { NSLog(@"[AuthenticationVC] showResourceLimitExceededError"); - [self showResourceLimitExceededError:errorDict onAdminContactTapped:^(NSURL *adminContact) { + [self showResourceLimitExceededError:errorDict onAdminContactTapped:^(NSURL *adminContactURL) { - if ([[UIApplication sharedApplication] canOpenURL:adminContact]) - { - [[UIApplication sharedApplication] openURL:adminContact]; - } - else - { - NSLog(@"[AuthenticationVC] adminContact(%@) cannot be opened", adminContact); - } + [[UIApplication sharedApplication] vc_open:adminContactURL completionHandler:^(BOOL success) { + if (!success) + { + NSLog(@"[AuthenticationVC] adminContact(%@) cannot be opened", adminContactURL); + } + }]; }]; } diff --git a/Riot/Modules/Common/Flow/Animation.swift b/Riot/Modules/Common/Flow/Animation.swift deleted file mode 100644 index b70713e50..000000000 --- a/Riot/Modules/Common/Flow/Animation.swift +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -open class Animation: NSObject, CAAnimationDelegate { - /// Key frame animations which animate the properties of `layer`. - fileprivate var keyframeAnimations: [CAKeyframeAnimation] - - /// The CALayer whose properties are animated. - open var layer: CALayer - - /// Specifies whether or not the animation should autoreverse. - var autoreverses: Bool - - /// Determines the number of times the animation will repeat. - /// - /// May be fractional. If the repeatCount is 0, it is ignored. - /// Setting this property to greatestFiniteMagnitude will cause the animation to repeat forever. - var repeatCount: Float - - weak var delegate: AnimationDelegate? - - /// The current time of the animation. i.e. what time is being displayed. - var time: TimeInterval { - return layer.timeOffset - } - - /// True if the animation is playing. - var playing: Bool { - return layer.speed != 0.0 - } - - // MARK: - Initializers - - public init(layer: CALayer, keyframeAnimations: [CAKeyframeAnimation], autoreverses: Bool = false, repeatCount: Float = 0) { - self.layer = layer - self.keyframeAnimations = keyframeAnimations - self.autoreverses = autoreverses - self.repeatCount = repeatCount - - super.init() - keyframeAnimations.forEach(configure) - reset() - } - - private func configure(keyframeAnimation: CAKeyframeAnimation) { - keyframeAnimation.delegate = self - keyframeAnimation.isRemovedOnCompletion = false - keyframeAnimation.fillMode = .both - keyframeAnimation.autoreverses = autoreverses - keyframeAnimation.repeatCount = repeatCount - } - - // MARK: - Playing & Resetting Animation - - /// Resumes the animation from where it was paused. - open func play() { - let pausedTime = layer.timeOffset - layer.speed = 1.0 - layer.timeOffset = 0.0 - layer.beginTime = 0.0 - let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime - layer.beginTime = timeSincePause - } - - /// Pauses the animation. - open func pause() { - let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil) - offset(to: pausedTime) - } - - /// Resets the animation to time 0. - open func reset() { - CATransaction.suppressAnimations { - layer.removeAllAnimations() - layer.beginTime = 0 - offset(to: 0) - - for keyframeAnimation in keyframeAnimations { - layer.setValue(keyframeAnimation.values?.first, forKeyPath: keyframeAnimation.keyPath!) - } - - addAllAnimations() - layer.speed = 0 - } - } - - /// Adds all the animations to `layer` so they can be played. - private func addAllAnimations() { - DispatchQueue.main.async { [weak self] in - guard let keyframeAnimations = self?.keyframeAnimations, let layer = self?.layer else { - return - } - for keyframeAnimation in keyframeAnimations { - layer.add(keyframeAnimation, forKey: keyframeAnimation.keyPath) - } - } - } - - // MARK: - Driving Animation - - /// Shows the animation at time `time`. - open func offset(to time: TimeInterval) { - layer.speed = 0.0 - layer.timeOffset = time - } - - // MARK: - CAAnimationDelegate - - public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { - guard flag else { - return - } - - let time = autoreverses ? 0 : (keyframeAnimations.first?.duration ?? 0) - offset(to: time) - - if let keyframeAnimation = anim as? CAKeyframeAnimation, - keyframeAnimations.first?.keyPath == keyframeAnimation.keyPath { - delegate?.didStop(animation: self) - } - } -} - -public extension Animation { - var reversed: Animation { - let reversedKeyFrameAnimations = keyframeAnimations.map { $0.reversed } - return Animation(layer: layer, keyframeAnimations: reversedKeyFrameAnimations) - } -} - -protocol AnimationDelegate: class { - func didStop(animation: Animation) -} diff --git a/Riot/Modules/Common/Flow/CAKeyframeAnimation+Extension.swift b/Riot/Modules/Common/Flow/CAKeyframeAnimation+Extension.swift deleted file mode 100644 index 917f8e5e8..000000000 --- a/Riot/Modules/Common/Flow/CAKeyframeAnimation+Extension.swift +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import Foundation -import UIKit - -public extension CAKeyframeAnimation { - var reversed: CAKeyframeAnimation { - let reversed = CAKeyframeAnimation(keyPath: keyPath) - reversed.keyTimes = keyTimes?.reversed().map { NSNumber(floatLiteral: 1.0 - $0.doubleValue) } - reversed.values = values?.reversed() - reversed.timingFunctions = timingFunctions?.reversed().map { $0.reversed } - reversed.duration = duration - return reversed - } -} diff --git a/Riot/Modules/Common/Flow/CAMediaTimingFunction+Extension.swift b/Riot/Modules/Common/Flow/CAMediaTimingFunction+Extension.swift deleted file mode 100644 index 924692189..000000000 --- a/Riot/Modules/Common/Flow/CAMediaTimingFunction+Extension.swift +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import Foundation -import UIKit - -public extension CAMediaTimingFunction { - static let linear = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) - static let easeIn = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) - static let easeOut = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) - static let easeInEaseOut = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) - - var reversed: CAMediaTimingFunction { - let (c1, c2) = controlPoints - let x1 = Float(1 - c2.x) - let y1 = Float(1 - c2.y) - let x2 = Float(1 - c1.x) - let y2 = Float(1 - c1.y) - return CAMediaTimingFunction(controlPoints: x1, y1, x2, y2) - } - - var controlPoints: (CGPoint, CGPoint) { - var c1: [Float] = [0, 0] - var c2: [Float] = [0, 0] - getControlPoint(at: 1, values: &c1) - getControlPoint(at: 2, values: &c2) - - let c1x = CGFloat(c1[0]) - let c1y = CGFloat(c1[1]) - let c2x = CGFloat(c2[0]) - let c2y = CGFloat(c2[1]) - - return (CGPoint(x: c1x, y: c1y), CGPoint(x: c2x, y: c2y)) - } -} diff --git a/Riot/Modules/Common/Flow/CATransaction+Extension.swift b/Riot/Modules/Common/Flow/CATransaction+Extension.swift deleted file mode 100644 index fc3840b3a..000000000 --- a/Riot/Modules/Common/Flow/CATransaction+Extension.swift +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -extension CATransaction { - static public func suppressAnimations(actions: () -> Void) { - begin() - setAnimationDuration(0) - actions() - commit() - } -} diff --git a/Riot/Modules/Common/Flow/CGPath+SVG.swift b/Riot/Modules/Common/Flow/CGPath+SVG.swift deleted file mode 100644 index 63eda8bff..000000000 --- a/Riot/Modules/Common/Flow/CGPath+SVG.swift +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import QuartzCore - -public func CGPathCreateWithSVGString(_ string: String) -> CGPath? { - let parser = SVGPathStringParser() - return try? parser.parse(string) -} - -class SVGPathStringParser { - enum Error: Swift.Error { - case invalidSyntax - case missingValues - } - - let path = CGMutablePath() - var currentPoint = CGPoint() - var lastControlPoint = CGPoint() - - var command: UnicodeScalar? - var values = [CGFloat]() - - func parse(_ string: String) throws -> CGPath { - let tokens = SVGPathStringTokenizer(string: string).tokenize() - - for token in tokens { - switch token { - case .command(let c): - command = c - values.removeAll() - - case .value(let v): - values.append(v) - } - - do { - try addCommand() - } catch Error.missingValues { - // Ignore - } - } - - return path - } - - fileprivate func addCommand() throws { - guard let command = command else { - return - } - - switch command { - case "M": - if values.count < 2 { throw Error.missingValues } - path.move(to: CGPoint(x: values[0], y: values[1])) - currentPoint = CGPoint(x: values[0], y: values[1]) - lastControlPoint = currentPoint - values.removeFirst(2) - - case "m": - if values.count < 2 { throw Error.missingValues } - let point = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1]) - path.move(to: point) - currentPoint.x += values[0] - currentPoint.y += values[1] - lastControlPoint = currentPoint - values.removeFirst(2) - - case "L": - if values.count < 2 { throw Error.missingValues } - let point = CGPoint(x: values[0], y: values[1]) - path.addLine(to: point) - currentPoint = CGPoint(x: values[0], y: values[1]) - lastControlPoint = currentPoint - values.removeFirst(2) - - case "l": - if values.count < 2 { throw Error.missingValues } - let point = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1]) - path.addLine(to: point) - currentPoint.x += values[0] - currentPoint.y += values[1] - lastControlPoint = currentPoint - values.removeFirst(2) - - case "H": - if values.count < 1 { throw Error.missingValues } - let point = CGPoint(x: values[0], y: currentPoint.y) - path.addLine(to: point) - currentPoint.x = values[0] - lastControlPoint = currentPoint - values.removeFirst(1) - - case "h": - if values.count < 1 { throw Error.missingValues } - let point = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y) - path.addLine(to: point) - currentPoint.x += values[0] - lastControlPoint = currentPoint - values.removeFirst(1) - - case "V": - if values.count < 1 { throw Error.missingValues } - let point = CGPoint(x: currentPoint.x, y: values[0]) - path.addLine(to: point) - currentPoint.y = values[0] - lastControlPoint = currentPoint - values.removeFirst(1) - - case "v": - if values.count < 1 { throw Error.missingValues } - let point = CGPoint(x: currentPoint.x, y: currentPoint.y + values[0]) - path.addLine(to: point) - currentPoint.y += values[0] - lastControlPoint = currentPoint - values.removeFirst(1) - - case "C": - if values.count < 6 { throw Error.missingValues } - let c1 = CGPoint(x: values[0], y: values[1]) - let c2 = CGPoint(x: values[2], y: values[3]) - let to = CGPoint(x: values[4], y: values[5]) - path.addCurve(to: to, control1: c1, control2: c2) - lastControlPoint = c2 - currentPoint = to - values.removeFirst(6) - - case "c": - if values.count < 6 { throw Error.missingValues } - let c1 = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1]) - let c2 = CGPoint(x: currentPoint.x + values[2], y: currentPoint.y + values[3]) - let to = CGPoint(x: currentPoint.x + values[4], y: currentPoint.y + values[5]) - path.addCurve(to: to, control1: c1, control2: c2) - lastControlPoint = c2 - currentPoint = to - values.removeFirst(6) - - case "S": - if values.count < 4 { throw Error.missingValues } - var c1 = CGPoint() - c1.x = currentPoint.x + (currentPoint.x - lastControlPoint.x) - c1.y = currentPoint.y + (currentPoint.y - lastControlPoint.y) - let c2 = CGPoint(x: values[0], y: values[1]) - let to = CGPoint(x: values[2], y: values[3]) - path.addCurve(to: to, control1: c1, control2: c2) - lastControlPoint = c2 - currentPoint = to - values.removeFirst(4) - - case "s": - if values.count < 4 { throw Error.missingValues } - var c1 = CGPoint() - c1.x = currentPoint.x + (currentPoint.x - lastControlPoint.x) - c1.y = currentPoint.y + (currentPoint.y - lastControlPoint.y) - let c2 = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1]) - let to = CGPoint(x: currentPoint.x + values[2], y: currentPoint.y + values[3]) - path.addCurve(to: to, control1: c1, control2: c2) - lastControlPoint = c2 - currentPoint = to - values.removeFirst(4) - - case "Q": - if values.count < 4 { throw Error.missingValues } - let control = CGPoint(x: values[0], y: values[1]) - let to = CGPoint(x: values[2], y: values[3]) - path.addQuadCurve(to: to, control: control) - lastControlPoint = control - currentPoint = to - values.removeFirst(4) - - case "q": - if values.count < 4 { throw Error.missingValues } - let control = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1]) - let to = CGPoint(x: currentPoint.x + values[2], y: currentPoint.y + values[3]) - path.addQuadCurve(to: to, control: control) - lastControlPoint = control - currentPoint = to - values.removeFirst(4) - - case "T": - if values.count < 2 { throw Error.missingValues } - var control = CGPoint() - control.x = currentPoint.x + (currentPoint.x - lastControlPoint.x) - control.y = currentPoint.y + (currentPoint.y - lastControlPoint.y) - let to = CGPoint(x: values[0], y: values[1]) - path.addQuadCurve(to: to, control: control) - lastControlPoint = control - currentPoint = to - values.removeFirst(2) - - case "t": - if values.count < 2 { throw Error.missingValues } - var control = CGPoint() - control.x = currentPoint.x + (currentPoint.x - lastControlPoint.x) - control.y = currentPoint.y + (currentPoint.y - lastControlPoint.y) - let to = CGPoint(x: currentPoint.x + values[0], y: currentPoint.y + values[1]) - path.addQuadCurve(to: to, control: control) - lastControlPoint = control - currentPoint = to - values.removeFirst(2) - - case "Z", "z": - path.closeSubpath() - self.command = nil - - default: - throw Error.invalidSyntax - } - } -} - -class SVGPathStringTokenizer { - enum Token { - case command(UnicodeScalar) - case value(CGFloat) - } - - let separatorCharacterSet = CharacterSet(charactersIn: " \t\r\n,") - let commandCharacterSet = CharacterSet(charactersIn: "mMLlHhVvzZCcSsQqTt") - let numberStartCharacterSet = CharacterSet(charactersIn: "-+.0123456789") - let numberCharacterSet = CharacterSet(charactersIn: ".0123456789eE") - - var string: String - var range: Range - - init(string: String) { - self.string = string - range = string.unicodeScalars.startIndex.. [Token] { - var array = [Token]() - while let token = nextToken() { - array.append(token) - } - return array - } - - func nextToken() -> Token? { - skipSeparators() - - guard let c = get() else { - return nil - } - - if commandCharacterSet.isMember(c) { - return .command(c) - } - - if numberStartCharacterSet.isMember(c) { - var numberString = String(c) - while let c = peek(), numberCharacterSet.isMember(c) { - numberString += String(c) - get() - } - - if let value = Double(numberString) { - return .value(CGFloat(value)) - } - } - - return nil - } - - @discardableResult - func get() -> UnicodeScalar? { - guard range.lowerBound != range.upperBound else { - return nil - } - let c = string.unicodeScalars[range.lowerBound] - range = string.unicodeScalars.index(after: range.lowerBound).. UnicodeScalar? { - guard range.lowerBound != range.upperBound else { - return nil - } - return string.unicodeScalars[range.lowerBound] - } - - func skipSeparators() { - while range.lowerBound != range.upperBound && separatorCharacterSet.isMember(string.unicodeScalars[range.lowerBound]) { - range = string.unicodeScalars.index(after: range.lowerBound).. Bool { - return contains(UnicodeScalar(c.value)!) - } -} diff --git a/Riot/Modules/Common/Flow/NSMutableParagraphStyle+Extension.swift b/Riot/Modules/Common/Flow/NSMutableParagraphStyle+Extension.swift deleted file mode 100644 index d7d80ae71..000000000 --- a/Riot/Modules/Common/Flow/NSMutableParagraphStyle+Extension.swift +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -extension NSMutableParagraphStyle { - convenience init(alignment: NSTextAlignment, - firstLineHeadIndent: CGFloat, - headIndent: CGFloat, - tailIndent: CGFloat, - lineHeightMultiple: CGFloat, - maximumLineHeight: CGFloat, - minimumLineHeight: CGFloat, - lineSpacing: CGFloat, - paragraphSpacing: CGFloat, - paragraphSpacingBefore: CGFloat) { - self.init() - self.alignment = alignment - self.firstLineHeadIndent = firstLineHeadIndent - self.headIndent = headIndent - self.tailIndent = tailIndent - self.lineHeightMultiple = lineHeightMultiple - self.maximumLineHeight = maximumLineHeight - self.minimumLineHeight = minimumLineHeight - self.lineSpacing = lineSpacing - self.paragraphSpacing = paragraphSpacing - self.paragraphSpacingBefore = paragraphSpacingBefore - } -} diff --git a/Riot/Modules/Common/Flow/NSShadow+Extension.swift b/Riot/Modules/Common/Flow/NSShadow+Extension.swift deleted file mode 100644 index 555f5f7ab..000000000 --- a/Riot/Modules/Common/Flow/NSShadow+Extension.swift +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -extension NSShadow { - convenience init(blurRadius: CGFloat, offset: CGSize, color: UIColor) { - self.init() - shadowBlurRadius = blurRadius - shadowOffset = offset - shadowColor = color - } -} diff --git a/Riot/Modules/Common/Flow/ShapeView.swift b/Riot/Modules/Common/Flow/ShapeView.swift deleted file mode 100644 index 9f6d82aa4..000000000 --- a/Riot/Modules/Common/Flow/ShapeView.swift +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright © 2016-2019 JABT -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -open class ShapeView: UIView { - open var shapeLayer: CAShapeLayer { - return (layer as? CAShapeLayer)! - } - - /// A sublayer which can be used to apply a gradient fill to `self`. - open var gradientLayer: CAGradientLayer? { - set { - // Remove old gradient layer - if let gradientLayer = gradientLayer { - gradientLayer.removeFromSuperlayer() - } - // Replace old gradient with new one - if let newGradientLayer = newValue { - layer.addSublayer(newGradientLayer) - } - } - - get { - return layer.sublayers?.first(where: { $0 is CAGradientLayer }) as? CAGradientLayer - } - } - - public func addGradient(type: CAGradientLayerType, startPoint: CGPoint, endPoint: CGPoint, stops: [(color: CGColor, location: NSNumber)]) { - let gradientLayer = CAGradientLayer() - gradientLayer.frame = shapeLayer.bounds - self.gradientLayer = gradientLayer - - - let mask = CAShapeLayer() - mask.path = shapeLayer.path - mask.fillColor = UIColor.black.cgColor - mask.strokeColor = nil - - gradientLayer.startPoint = startPoint - gradientLayer.endPoint = endPoint - gradientLayer.colors = stops.map { $0.color } - gradientLayer.locations = stops.map { $0.location } - gradientLayer.type = type - gradientLayer.frame = shapeLayer.bounds - gradientLayer.mask = mask - } - - open var path: CGPath? { - get { - return shapeLayer.path - } - set { - shapeLayer.path = newValue - } - } - - override open class var layerClass: AnyClass { - return CAShapeLayer.self - } -} diff --git a/Riot/Modules/Common/Flow/Sound.swift b/Riot/Modules/Common/Flow/Sound.swift deleted file mode 100644 index fb8f91239..000000000 --- a/Riot/Modules/Common/Flow/Sound.swift +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import AVFoundation - -public final class Sound { - - static func playAudio(_ audio: AVAudioPlayer, delay: TimeInterval) { - audio.prepareToPlay() - let time = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) - DispatchQueue.main.asyncAfter(deadline: time) { - audio.play() - } - } -} diff --git a/Riot/Modules/Common/Flow/TextView.swift b/Riot/Modules/Common/Flow/TextView.swift deleted file mode 100644 index 07feda92e..000000000 --- a/Riot/Modules/Common/Flow/TextView.swift +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright © 2016-2019 JABT -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -open class TextView: UILabel { - open var textLayer: CATextLayer { - return (layer as? CATextLayer)! - } - - override open class var layerClass: AnyClass { - return CATextLayer.self - } -} diff --git a/Riot/Modules/Common/Flow/Timeline.swift b/Riot/Modules/Common/Flow/Timeline.swift deleted file mode 100644 index de6279fd4..000000000 --- a/Riot/Modules/Common/Flow/Timeline.swift +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import Foundation -import UIKit -import AVFoundation - -open class Timeline { - public var view: UIView - public var duration: TimeInterval - public let animations: [Animation] - public let sounds: [(sound: AVAudioPlayer, delay: TimeInterval)] - - /// Specifies whether or not the timeline's animations autoreverse. - public let autoreverses: Bool - - /// Determines the number of times the timeline's animations will repeat. - /// - /// May be fractional. If the repeatCount is 0, it is ignored. - /// Setting this property to greatestFiniteMagnitude will cause the timeline to repeat forever. - public let repeatCount: Float - - public var time: TimeInterval { - return animations.first?.time ?? 0 - } - - public var playing: Bool { - return animations.first?.playing ?? false - } - - public weak var delegate: TimelineDelegate? - - // MARK: - Initializers - - public convenience init(view: UIView, animationsByLayer: [CALayer: [CAKeyframeAnimation]], sounds: [(sound: AVAudioPlayer, delay: TimeInterval)], duration: TimeInterval, autoreverses: Bool = false, repeatCount: Float = 0) { - - let animations = animationsByLayer.map { - Animation(layer: $0.0, keyframeAnimations: $0.1, autoreverses: autoreverses, repeatCount: repeatCount) - } - - self.init(view: view, animations: animations, sounds: sounds, duration: duration, autoreverses: autoreverses, repeatCount: repeatCount) - } - - init(view: UIView, animations: [Animation], sounds: [(sound: AVAudioPlayer, delay: TimeInterval)], duration: TimeInterval, autoreverses: Bool, repeatCount: Float) { - self.view = view - self.duration = duration - self.sounds = sounds - self.autoreverses = autoreverses - self.repeatCount = repeatCount - self.animations = animations - self.animations.first?.delegate = self - } - - // MARK: - Timeline Playback controls - - /// Reset to the initial state of the timeline - public func reset() { - for animation in animations { - animation.reset() - } - delegate?.didReset(timeline: self) - } - - /// Resume playing the timeline. - public func play() { - playSounds() - for animation in animations { - animation.play() - } - delegate?.didPlay(timeline: self) - } - - private func playSounds() { - for (sound, delay) in sounds { - Sound.playAudio(sound, delay: delay) - } - } - - /// Pause playing of timeline. - public func pause() { - for animation in animations { - animation.pause() - } - delegate?.didPause(timeline: self) - } - - /// Show timeline at time `time`. - public func offset(to time: TimeInterval) { - let time = max(min(time, duration), 0) - for animation in animations { - animation.offset(to: time) - } - delegate?.didOffset(timeline: self, to: time) - } - - /// Returns a reverses version of `self`. - var reversed: Timeline { - let reversedAnimations = animations.map { $0.reversed } - return Timeline(view: view, animations: reversedAnimations, sounds: sounds, duration: duration, autoreverses: autoreverses, repeatCount: repeatCount) - } -} - -extension Timeline: AnimationDelegate { - func didStop(animation: Animation) { - delegate?.didStop(timeline: self) - } -} - -public protocol TimelineDelegate: class { - /// Informs the delegate that the timeline `timeline` was reset. - func didReset(timeline: Timeline) - - /// Informs the delegate that the timeline `timeline` did start playing. - func didPlay(timeline: Timeline) - - /// Informs the delegate that the timeline `timeline` was paused. - func didPause(timeline: Timeline) - - /// Informs the delegate that the timeline `timeline` was offset. - /// - /// - Parameters: - /// - timeline: The timeline which was offset. - /// - time: The time to which `timeline` was offset to. - func didOffset(timeline: Timeline, to time: TimeInterval) - - /// Informs the delegate that the timeline `timeline` was stopped because it completed its active duration. - func didStop(timeline: Timeline) -} diff --git a/Riot/Modules/Common/Flow/UIImage+Extension.swift b/Riot/Modules/Common/Flow/UIImage+Extension.swift deleted file mode 100644 index 3b012aa04..000000000 --- a/Riot/Modules/Common/Flow/UIImage+Extension.swift +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -extension UIImage { - func resized(to size: CGSize) -> UIImage { - let rect = CGRect(origin: .zero, size: size) - let vertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height) - return UIGraphicsImageRenderer(size: size).image { _ in - let ctx = UIGraphicsGetCurrentContext() - ctx?.saveGState() - ctx?.concatenate(vertical) - draw(in: rect) - ctx?.restoreGState() - UIGraphicsEndImageContext() - } - } -} diff --git a/Riot/Modules/Common/Flow/UIView+Extension.swift b/Riot/Modules/Common/Flow/UIView+Extension.swift deleted file mode 100644 index 717381454..000000000 --- a/Riot/Modules/Common/Flow/UIView+Extension.swift +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright © 2016-2019 JABT Labs Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: The above copyright -// notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -import UIKit - -extension UIView { - func setTransform(scaleX: CGFloat, scaleY: CGFloat, rotationAngle: CGFloat) { - var transform = CGAffineTransform.identity - transform = transform.concatenating(CGAffineTransform(scaleX: scaleX, y: 1.0)) - transform = transform.concatenating(CGAffineTransform(scaleX: 1.0, y: scaleY)) - transform = transform.concatenating(CGAffineTransform(rotationAngle: rotationAngle)) - self.transform = transform - } -} diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 8106f176a..c2f5a88a2 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -1610,14 +1610,9 @@ [plusButtonImageView.widthAnchor constraintEqualToConstant:side].active = YES; [plusButtonImageView.heightAnchor constraintEqualToConstant:side].active = YES; - if (@available(iOS 11.0, *)) { - // align to safe area - [plusButtonImageView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor].active = YES; - [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:plusButtonImageView.bottomAnchor constant:9].active = YES; - } else { - [plusButtonImageView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; - [self.bottomLayoutGuide.topAnchor constraintEqualToAnchor:plusButtonImageView.bottomAnchor constant:9].active = YES; - } + // align to safe area + [plusButtonImageView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor].active = YES; + [self.view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:plusButtonImageView.bottomAnchor constant:9].active = YES; plusButtonImageView.userInteractionEnabled = YES; diff --git a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m b/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m index 4ae21935f..855c4e2c0 100644 --- a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m +++ b/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m @@ -100,11 +100,9 @@ static const CGFloat kInterItemsSpaceHorizontal = 8.0; [super layoutSubviews]; CGFloat _leftInset = 0.0, _rightInset = 0.0; - if (@available(iOS 11, *)) - { - _leftInset += self.safeAreaInsets.left; - _rightInset += self.safeAreaInsets.right; - } + + _leftInset += self.safeAreaInsets.left; + _rightInset += self.safeAreaInsets.right; CGFloat leftMargin = MAX(_leftInset, _minimumLeftInset); CGFloat rightMargin = MAX(_rightInset, _minimumRightInset); diff --git a/Riot/Modules/Contacts/Details/ContactDetailsViewController.m b/Riot/Modules/Contacts/Details/ContactDetailsViewController.m index a27a3128b..a9fca81da 100644 --- a/Riot/Modules/Contacts/Details/ContactDetailsViewController.m +++ b/Riot/Modules/Contacts/Details/ContactDetailsViewController.m @@ -138,50 +138,9 @@ self.contactAvatar.contentMode = UIViewContentModeScaleAspectFill; self.contactAvatar.defaultBackgroundColor = [UIColor clearColor]; - - if (@available(iOS 11.0, *)) - { - // Define directly the navigation titleView with the custom title view instance. Do not use anymore a container. - self.navigationItem.titleView = contactTitleView; - } - else - { - self.navigationItem.titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 40)]; - // Add the title view and define edge constraints - contactTitleView.translatesAutoresizingMaskIntoConstraints = NO; - [self.navigationItem.titleView addSubview:contactTitleView]; - - NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView - attribute:NSLayoutAttributeTop - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeTop - multiplier:1.0f - constant:0.0f]; - NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView - attribute:NSLayoutAttributeBottom - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeBottom - multiplier:1.0f - constant:0.0f]; - NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView - attribute:NSLayoutAttributeLeading - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeLeading - multiplier:1.0f - constant:0.0f]; - NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:contactTitleView - attribute:NSLayoutAttributeTrailing - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeTrailing - multiplier:1.0f - constant:0.0f]; - [NSLayoutConstraint activateConstraints:@[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]]; - } + // Define directly the navigation titleView with the custom title view instance. Do not use anymore a container. + self.navigationItem.titleView = contactTitleView; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; [tap setNumberOfTouchesRequired:1]; diff --git a/Riot/Modules/Home/HomeViewController.m b/Riot/Modules/Home/HomeViewController.m index 1160aba1e..5725705fa 100644 --- a/Riot/Modules/Home/HomeViewController.m +++ b/Riot/Modules/Home/HomeViewController.m @@ -399,14 +399,7 @@ CGSize fittingSize = UILayoutFittingCompressedSize; CGFloat tableViewWidth = CGRectGetWidth(tableView.frame); - CGFloat safeAreaWidth; - - if (@available(iOS 11.0, *)) { - // Take safe area into account - safeAreaWidth = MAX(tableView.safeAreaInsets.left, tableView.safeAreaInsets.right); - } else { - safeAreaWidth = 0; - } + CGFloat safeAreaWidth = MAX(tableView.safeAreaInsets.left, tableView.safeAreaInsets.right); fittingSize.width = tableViewWidth - safeAreaWidth; diff --git a/Riot/Modules/Integrations/Widgets/WidgetViewController.m b/Riot/Modules/Integrations/Widgets/WidgetViewController.m index 6380fbcaf..c299243cb 100644 --- a/Riot/Modules/Integrations/Widgets/WidgetViewController.m +++ b/Riot/Modules/Integrations/Widgets/WidgetViewController.m @@ -411,8 +411,15 @@ NSString *const kJavascriptSendResponseToPostMessageAPI = @"riotIOS.sendResponse if (navigationAction.navigationType == WKNavigationTypeLinkActivated) { + NSURL *linkURL = navigationAction.request.URL; + // Open links outside the app - [[UIApplication sharedApplication] openURL:navigationAction.request.URL]; + [[UIApplication sharedApplication] vc_open:linkURL completionHandler:^(BOOL success) { + if (!success) + { + NSLog(@"[WidgetVC] webView:decidePolicyForNavigationAction:decisionHandler fail to open external link: %@", linkURL); + } + }]; decisionHandler(WKNavigationActionPolicyCancel); return; } diff --git a/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromPassphraseViewController.swift b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromPassphraseViewController.swift index c7e15b64d..57fe04ba9 100644 --- a/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromPassphraseViewController.swift +++ b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromPassphraseViewController.swift @@ -122,9 +122,12 @@ final class KeyBackupSetupSuccessFromPassphraseViewController: UIViewController } private func shareRecoveryKey() { + guard let recoveryKey = self.recoveryKey else { + return + } // Set up activity view controller - let activityItems: [Any] = [ self.recoveryKey ] + let activityItems: [Any] = [ recoveryKey ] let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) // Configure source view when activity view controller is presented with a popover diff --git a/Riot/Modules/LaunchLoading/ElementView.swift b/Riot/Modules/LaunchLoading/LoadingAnimation/ElementView.swift similarity index 100% rename from Riot/Modules/LaunchLoading/ElementView.swift rename to Riot/Modules/LaunchLoading/LoadingAnimation/ElementView.swift diff --git a/Riot/Modules/LaunchLoading/ElementViewController.swift b/Riot/Modules/LaunchLoading/LoadingAnimation/ElementViewController.swift similarity index 100% rename from Riot/Modules/LaunchLoading/ElementViewController.swift rename to Riot/Modules/LaunchLoading/LoadingAnimation/ElementViewController.swift diff --git a/Riot/Modules/LaunchLoading/Timeline_1.swift b/Riot/Modules/LaunchLoading/LoadingAnimation/Timeline_1.swift similarity index 100% rename from Riot/Modules/LaunchLoading/Timeline_1.swift rename to Riot/Modules/LaunchLoading/LoadingAnimation/Timeline_1.swift diff --git a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m index 161dcc35a..3ee3e4844 100644 --- a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m +++ b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m @@ -146,51 +146,9 @@ memberTitleView = [RoomMemberTitleView roomMemberTitleView]; memberTitleView.delegate = self; - - if (@available(iOS 11.0, *)) - { - // Define directly the navigation titleView with the custom title view instance. Do not use anymore a container. - self.navigationItem.titleView = memberTitleView; - } - else - { - self.navigationItem.titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 40)]; - // Add the title view and define edge constraints - memberTitleView.translatesAutoresizingMaskIntoConstraints = NO; - [self.navigationItem.titleView addSubview:memberTitleView]; - - NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView - attribute:NSLayoutAttributeTop - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeTop - multiplier:1.0f - constant:0.0f]; - NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView - attribute:NSLayoutAttributeBottom - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeBottom - multiplier:1.0f - constant:0.0f]; - NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView - attribute:NSLayoutAttributeLeading - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeLeading - multiplier:1.0f - constant:0.0f]; - NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView - attribute:NSLayoutAttributeTrailing - relatedBy:NSLayoutRelationEqual - toItem:self.navigationItem.titleView - attribute:NSLayoutAttributeTrailing - multiplier:1.0f - constant:0.0f]; - - [NSLayoutConstraint activateConstraints:@[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]]; - } + // Define directly the navigation titleView with the custom title view instance. Do not use anymore a container. + self.navigationItem.titleView = memberTitleView; // Add tap gesture on member's name UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; diff --git a/Riot/Modules/Room/Members/Detail/Views/RoomMemberTitleView.m b/Riot/Modules/Room/Members/Detail/Views/RoomMemberTitleView.m index 573537398..226aa7749 100644 --- a/Riot/Modules/Room/Members/Detail/Views/RoomMemberTitleView.m +++ b/Riot/Modules/Room/Members/Detail/Views/RoomMemberTitleView.m @@ -40,54 +40,26 @@ if (self.superview) { - if (@available(iOS 11.0, *)) - { - // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. - NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeTop + // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. + NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:self.superview + attribute:NSLayoutAttributeTop + multiplier:1.0f + constant:0.0f]; + NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview - attribute:NSLayoutAttributeTop + attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]; - NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self.superview - attribute:NSLayoutAttributeCenterX - multiplier:1.0f - constant:0.0f]; - - [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; - - // Do not crop the avatar - self.superview.clipsToBounds = NO; - } - else - { - // Center horizontally the avatar into the navigation bar - CGRect frame = self.superview.frame; - UINavigationBar *navigationBar; - UIView *superView = self; - while (superView.superview) - { - if ([superView.superview isKindOfClass:[UINavigationBar class]]) - { - navigationBar = (UINavigationBar*)superView.superview; - break; - } - - superView = superView.superview; - } - - if (navigationBar) - { - CGSize navBarSize = navigationBar.frame.size; - CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2); - - self.memberAvatarMaskCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX; - } - } + + [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; + + // Do not crop the avatar + self.superview.clipsToBounds = NO; } if (_delegate && [_delegate respondsToSelector:@selector(roomMemberTitleViewDidLayoutSubview:)]) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 942e65ec7..f4fef13e3 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -4438,15 +4438,13 @@ if ([self.roomDataSource.mxSession.syncError.errcode isEqualToString:kMXErrCodeStringResourceLimitExceeded]) { - [roomActivitiesView showResourceLimitExceededError:self.roomDataSource.mxSession.syncError.userInfo onAdminContactTapped:^(NSURL *adminContact) { - if ([[UIApplication sharedApplication] canOpenURL:adminContact]) - { - [[UIApplication sharedApplication] openURL:adminContact]; - } - else - { - NSLog(@"[RoomVC] refreshActivitiesViewDisplay: adminContact(%@) cannot be opened", adminContact); - } + [roomActivitiesView showResourceLimitExceededError:self.roomDataSource.mxSession.syncError.userInfo onAdminContactTapped:^(NSURL *adminContactURL) { + [[UIApplication sharedApplication] vc_open:adminContactURL completionHandler:^(BOOL success) { + if (!success) + { + NSLog(@"[RoomVC] refreshActivitiesViewDisplay: adminContact(%@) cannot be opened", adminContactURL); + } + }]; }]; } else if ([AppDelegate theDelegate].isOffline) @@ -4613,16 +4611,13 @@ } else if (serverNotices.usageLimit && serverNotices.usageLimit.isServerNoticeUsageLimit) { - [roomActivitiesView showResourceUsageLimitNotice:serverNotices.usageLimit onAdminContactTapped:^(NSURL *adminContact) { - - if ([[UIApplication sharedApplication] canOpenURL:adminContact]) - { - [[UIApplication sharedApplication] openURL:adminContact]; - } - else - { - NSLog(@"[RoomVC] refreshActivitiesViewDisplay: adminContact(%@) cannot be opened", adminContact); - } + [roomActivitiesView showResourceUsageLimitNotice:serverNotices.usageLimit onAdminContactTapped:^(NSURL *adminContactURL) { + [[UIApplication sharedApplication] vc_open:adminContactURL completionHandler:^(BOOL success) { + if (!success) + { + NSLog(@"[RoomVC] refreshActivitiesViewDisplay: adminContact(%@) cannot be opened", adminContactURL); + } + }]; }]; } else diff --git a/Riot/Modules/Room/Views/Title/Avatar/RoomAvatarTitleView.m b/Riot/Modules/Room/Views/Title/Avatar/RoomAvatarTitleView.m index 9e7bc5a07..bcf743533 100644 --- a/Riot/Modules/Room/Views/Title/Avatar/RoomAvatarTitleView.m +++ b/Riot/Modules/Room/Views/Title/Avatar/RoomAvatarTitleView.m @@ -40,54 +40,26 @@ if (self.superview) { - if (@available(iOS 11.0, *)) - { - // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. - NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeTop + // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. + NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:self.superview + attribute:NSLayoutAttributeTop + multiplier:1.0f + constant:0.0f]; + NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview - attribute:NSLayoutAttributeTop + attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]; - NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self.superview - attribute:NSLayoutAttributeCenterX - multiplier:1.0f - constant:0.0f]; - - [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; - - // Do not crop the avatar - self.superview.clipsToBounds = NO; - } - else - { - // Center horizontally the avatar into the navigation bar - CGRect frame = self.superview.frame; - UINavigationBar *navigationBar; - UIView *superView = self; - while (superView.superview) - { - if ([superView.superview isKindOfClass:[UINavigationBar class]]) - { - navigationBar = (UINavigationBar*)superView.superview; - break; - } - - superView = superView.superview; - } - - if (navigationBar) - { - CGSize navBarSize = navigationBar.frame.size; - CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2); - - self.roomAvatarMaskCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX; - } - } + + [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; + + // Do not crop the avatar + self.superview.clipsToBounds = NO; } } diff --git a/Riot/Modules/Room/Views/Title/RoomTitleView.m b/Riot/Modules/Room/Views/Title/RoomTitleView.m index 40e5ca003..3be6437d3 100644 --- a/Riot/Modules/Room/Views/Title/RoomTitleView.m +++ b/Riot/Modules/Room/Views/Title/RoomTitleView.m @@ -78,59 +78,23 @@ if (self.superview) { - if (@available(iOS 11.0, *)) - { - // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. - NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeTop + // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. + NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:self.superview + attribute:NSLayoutAttributeTop + multiplier:1.0f + constant:0.0f]; + NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview - attribute:NSLayoutAttributeTop + attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]; - NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self.superview - attribute:NSLayoutAttributeCenterX - multiplier:1.0f - constant:0.0f]; - - [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; - - } - else - { - // Center horizontally the display name into the navigation bar - CGRect frame = self.superview.frame; - - // Look for the navigation bar. - UINavigationBar *navigationBar; - UIView *superView = self; - while (superView.superview) - { - if ([superView.superview isKindOfClass:[UINavigationBar class]]) - { - navigationBar = (UINavigationBar*)superView.superview; - break; - } - - superView = superView.superview; - } - - if (navigationBar) - { - CGSize navBarSize = navigationBar.frame.size; - CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2); - - // Check whether the view is not moving away (see navigation between view controllers). - if (superviewCenterX < navBarSize.width) - { - // Center the display name - self.displayNameCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX; - } - } - } + + [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; } } diff --git a/Riot/Modules/Room/Views/Title/Simple/SimpleRoomTitleView.m b/Riot/Modules/Room/Views/Title/Simple/SimpleRoomTitleView.m index db5fcc5e7..3118f1359 100644 --- a/Riot/Modules/Room/Views/Title/Simple/SimpleRoomTitleView.m +++ b/Riot/Modules/Room/Views/Title/Simple/SimpleRoomTitleView.m @@ -38,52 +38,23 @@ if (self.superview) { - if (@available(iOS 11.0, *)) - { - // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. - NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeTop + // Force the title view layout by adding 2 new constraints on the UINavigationBarContentView instance. + NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:self.superview + attribute:NSLayoutAttributeTop + multiplier:1.0f + constant:0.0f]; + NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview - attribute:NSLayoutAttributeTop + attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]; - NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self.superview - attribute:NSLayoutAttributeCenterX - multiplier:1.0f - constant:0.0f]; - - [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; - } - else - { - // Center horizontally the display name into the navigation bar - CGRect frame = self.superview.frame; - UINavigationBar *navigationBar; - UIView *superView = self; - while (superView.superview) - { - if ([superView.superview isKindOfClass:[UINavigationBar class]]) - { - navigationBar = (UINavigationBar*)superView.superview; - break; - } - - superView = superView.superview; - } - - if (navigationBar) - { - CGSize navBarSize = navigationBar.frame.size; - CGFloat superviewCenterX = frame.origin.x + (frame.size.width / 2); - - // Center the display name - self.displayNameCenterXConstraint.constant = (navBarSize.width / 2) - superviewCenterX; - } - } + + [NSLayoutConstraint activateConstraints:@[topConstraint, centerXConstraint]]; } } diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index e56fd7180..4bd8ef304 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -1947,16 +1947,7 @@ TableViewSectionsDelegate> if (!theme) { - if (@available(iOS 11.0, *)) - { - // "auto" is used the default value from iOS 11 - theme = @"auto"; - } - else - { - // Use "light" for older version - theme = @"light"; - } + theme = @"auto"; } theme = [NSString stringWithFormat:@"settings_ui_theme_%@", theme]; @@ -3506,17 +3497,14 @@ TableViewSectionsDelegate> } } }; - - if (@available(iOS 11.0, *)) - { - // Show "auto" only from iOS 11 - autoAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"settings_ui_theme_auto", @"Vector", nil) - style:UIAlertActionStyleDefault - handler:actionBlock]; - - // Explain what is "auto" - themePickerMessage = NSLocalizedStringFromTable(@"settings_ui_theme_picker_message", @"Vector", nil); - } + + // Show "auto" only from iOS 11 + autoAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"settings_ui_theme_auto", @"Vector", nil) + style:UIAlertActionStyleDefault + handler:actionBlock]; + + // Explain what is "auto" + themePickerMessage = NSLocalizedStringFromTable(@"settings_ui_theme_picker_message", @"Vector", nil); lightAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"settings_ui_theme_light", @"Vector", nil) style:UIAlertActionStyleDefault diff --git a/Riot/Utils/AvatarGenerator.m b/Riot/Utils/AvatarGenerator.m index dc0162ef3..efbf42b59 100644 --- a/Riot/Utils/AvatarGenerator.m +++ b/Riot/Utils/AvatarGenerator.m @@ -28,7 +28,7 @@ @implementation AvatarGenerator static NSMutableDictionary *imageByKeyDict = nil; -static NSMutableArray* colorsList = nil; +static NSArray* colorsList = nil; static UILabel* backgroundLabel = nil; /** diff --git a/Riot/Utils/DataProtectionHelper.swift b/Riot/Utils/DataProtectionHelper.swift index 686ffb98e..fd8f23626 100644 --- a/Riot/Utils/DataProtectionHelper.swift +++ b/Riot/Utils/DataProtectionHelper.swift @@ -22,11 +22,14 @@ final class DataProtectionHelper { /// - Parameter appGroupIdentifier: App-group identifier to be used when deciding where it'll try to write the file. /// - Returns: true if the state detected static func isDeviceInRebootedAndLockedState(appGroupIdentifier: String? = nil) -> Bool { + + let dummyString = String.unique + guard let dummyData = dummyString.data(using: .utf8) else { + return true + } + do { - let dummyString = String.unique - let dummyData = dummyString.data(using: .utf8)! - - var url: URL! + var url: URL if let identifier = appGroupIdentifier, let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: identifier) { url = containerURL diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 4b67927c4..f7f48cbe6 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -161,7 +161,7 @@ #pragma mark - INSendMessageIntentHandling -- (void)resolveRecipientsForSendMessage:(INSendMessageIntent *)intent withCompletion:(void (^)(NSArray * _Nonnull))completion +- (void)resolveRecipientsForSendMessage:(INSendMessageIntent *)intent completion:(void (^)(NSArray * _Nonnull))completion { [self resolveContacts:intent.recipients withCompletion:completion]; } diff --git a/Tools/Rageshakes/getlogs.sh b/Tools/Rageshakes/getlogs.sh deleted file mode 100644 index 1dc7a855b..000000000 --- a/Tools/Rageshakes/getlogs.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# ./getlogs.sh https://riot.im/bugreports/listing/2020-06-07/104229/ - -if [ ! $# -eq 1 ]; then - echo "Usage: ./getLogs.sh [http link]" - exit 1 -fi - -LOGS_URL=$1 - -ID=$( basename $LOGS_URL ) - -echo $ID -mkdir $ID -cd $ID - -wget -r -nd --user=matrix --password=a^njerkoo=les $LOGS_URL - -for f in *.log.gz; do - mv -- "$f" "${f%.log.gz}.log" -done - -rm *.html -