diff --git a/CHANGES.rst b/CHANGES.rst index 2a126c1e4..859414575 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,35 @@ -Changes in 1.0.3 (2020-xx-xx) +Changes to be released in next version +================================================= + +Features: + * + +Improvements: + * + +Bugfix: + * + +API Change: + * + +Translations: + * + +Others: + * + +Build: + * + +Test: + * + +Changes in 1.0.3 (2020-08-05) =============================================== Improvements: + * Upgrade MatrixKit version ([v0.12.10](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.10)). * Implement PIN protection (#3436). * Biometrics protection: Implement TouchID/FaceID protection (#3437). * Build: Make the app build if JitsiMeetSDK is not in the Podfile. @@ -10,9 +38,12 @@ Improvements: * BuildSettings: A new class that entralises build settings and exposes xcconfig variable. * AuthenticationVC: Make custom server options and register button configurable. * Xcconfig: Add product bundle identifiers for each target. + * BuildSettings: Namespace some settings. + * BuildSettings: Reuse base bundle identifier for various settings. Bug fix: * Rebranding: Remove Riot from app name (#3497). + * AuthenticationViewController: Fix custom homeserver textfield scroll issue (#3467). * Rebranding: Update provisioning universal link domain (#3483). Changes in 1.0.2 (2020-07-28) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 7aa8b4c0e..667c73527 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -30,6 +30,30 @@ final class BuildSettings: NSObject { Bundle.app.object(forInfoDictionaryKey: "applicationGroupIdentifier") as! String } + static var baseBundleIdentifier: String { + Bundle.app.object(forInfoDictionaryKey: "baseBundleIdentifier") as! String + } + + static var keychainAccessGroup: String { + Bundle.app.object(forInfoDictionaryKey: "keychainAccessGroup") as! String + } + + static var pushKitAppIdProd: String { + return baseBundleIdentifier + ".ios.voip.prod" + } + + static var pushKitAppIdDev: String { + return baseBundleIdentifier + ".ios.voip.dev" + } + + static var pusherAppIdProd: String { + return baseBundleIdentifier + ".ios.prod" + } + + static var pusherAppIdDev: String { + return baseBundleIdentifier + ".ios.dev" + } + // Element-Web instance for the app static let applicationWebAppUrlString = "https://app.element.io" @@ -37,10 +61,10 @@ final class BuildSettings: NSObject { // MARK: - Server configuration // Default servers proposed on the authentication screen - static let defaultHomeserverUrlString = "https://matrix.org" - static let defaultIdentityServerUrlString = "https://vector.im" + static let serverConfigDefaultHomeserverUrlString = "https://matrix.org" + static let serverConfigDefaultIdentityServerUrlString = "https://vector.im" - static let sygnalAPIUrlString = "https://matrix.org/_matrix/push/v1/notify" + static let serverConfigSygnalAPIUrlString = "https://matrix.org/_matrix/push/v1/notify" // MARK: - Legal URLs @@ -79,10 +103,10 @@ final class BuildSettings: NSObject { // MARK: - Public rooms Directory - static let showPublicRoomDirectory: Bool = true - static let allowRoomDirectoryServersChange: Bool = true + static let publicRoomsShowDirectory: Bool = true + static let publicRoomsAllowServerChange: Bool = true // List of homeservers for the public rooms directory - static let roomDirectoryServers = [ + static let publicRoomsDirectoryServers = [ "matrix.org" ] @@ -121,30 +145,31 @@ final class BuildSettings: NSObject { /// Force non-jailbroken app usage static let forceNonJailbrokenUsage: Bool = true + static let allowSendingStickers: Bool = true + + static let allowLocalContactsAccess: Bool = true + // MARK: - Screen settings - - static let showUserFirstNameInSettings: Bool = false - static let showUserSurnameInSettings: Bool = false - static let allowAddingEmailThreepids: Bool = true - static let allowAddingPhoneThreepids: Bool = true - static let showThreepidExplanatory: Bool = true - static let showDiscoverySettings: Bool = true - static let allowIdentityServerConfig: Bool = true - static let allowLocalContactsAccess: Bool = true - static let showAdvancedSettings: Bool = true - static let showLabSettings: Bool = true - static let allowChangingRageshakeSettings: Bool = true - static let allowChangingCrashUsageDataSettings: Bool = true - static let allowBugReportingManually: Bool = true - static let allowDeactivatingAccount: Bool = true - static let allowSendingStickers: Bool = true - + static let settingsScreenShowUserFirstName: Bool = false + static let settingsScreenShowUserSurname: Bool = false + static let settingsScreenAllowAddingEmailThreepids: Bool = true + static let settingsScreenAllowAddingPhoneThreepids: Bool = true + static let settingsScreenShowThreepidExplanatory: Bool = true + static let settingsScreenShowDiscoverySettings: Bool = true + static let settingsScreenAllowIdentityServerConfig: Bool = true + static let settingsScreenShowAdvancedSettings: Bool = true + static let settingsScreenShowLabSettings: Bool = true + static let settingsScreenAllowChangingRageshakeSettings: Bool = true + static let settingsScreenAllowChangingCrashUsageDataSettings: Bool = true + static let settingsScreenAllowBugReportingManually: Bool = true + static let settingsScreenAllowDeactivatingAccount: Bool = true // MARK: - Message - static let allowMessageDetailsShare: Bool = true - static let allowMessageDetailsPermalink: Bool = true - static let allowMessageDetailsViewSource: Bool = true + static let messageDetailsAllowShare: Bool = true + static let messageDetailsAllowPermalink: Bool = true + static let messageDetailsAllowViewSource: Bool = true // MARK: - Authentication Screen diff --git a/Config/Common.xcconfig b/Config/Common.xcconfig index 060ee8cdf..97b312442 100644 --- a/Config/Common.xcconfig +++ b/Config/Common.xcconfig @@ -22,3 +22,5 @@ BUNDLE_DISPLAY_NAME = Element APPLICATION_GROUP_IDENTIFIER = group.im.vector BASE_BUNDLE_IDENTIFIER = im.vector.app + +KEYCHAIN_ACCESS_GROUP = $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER).keychain.shared diff --git a/Gemfile.lock b/Gemfile.lock index b995d32b2..24cd9c970 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,27 +14,27 @@ GEM json (>= 1.5.1) atomos (0.1.3) aws-eventstream (1.1.0) - aws-partitions (1.337.0) - aws-sdk-core (3.102.1) + aws-partitions (1.351.0) + aws-sdk-core (3.104.3) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.35.0) + aws-sdk-kms (1.36.0) aws-sdk-core (~> 3, >= 3.99.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.72.0) - aws-sdk-core (~> 3, >= 3.102.1) + aws-sdk-s3 (1.75.0) + aws-sdk-core (~> 3, >= 3.104.1) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.1) aws-sigv4 (1.2.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.3) claide (1.0.3) - cocoapods (1.8.4) + cocoapods (1.9.3) activesupport (>= 4.0.2, < 5) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.8.4) + cocoapods-core (= 1.9.3) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 1.2.2, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -49,15 +49,17 @@ GEM molinillo (~> 0.6.6) nap (~> 1.0) ruby-macho (~> 1.4) - xcodeproj (>= 1.11.1, < 2.0) - cocoapods-core (1.8.4) + xcodeproj (>= 1.14.0, < 2.0) + cocoapods-core (1.9.3) activesupport (>= 4.0.2, < 6) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) fuzzy_match (~> 2.0.4) nap (~> 1.0) + netrc (~> 0.11) + typhoeus (~> 1.0) cocoapods-deintegrate (1.0.4) - cocoapods-downloader (1.3.0) + cocoapods-downloader (1.4.0) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.0) @@ -73,13 +75,16 @@ GEM concurrent-ruby (1.1.6) declarative (0.0.20) declarative-option (0.1.0) - digest-crc (0.5.1) + digest-crc (0.6.1) + rake (~> 13.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.5) - emoji_regex (1.0.1) + dotenv (2.7.6) + emoji_regex (3.0.0) escape (0.0.4) - excon (0.75.0) + ethon (0.12.0) + ffi (>= 1.3.0) + excon (0.76.0) faraday (1.0.1) multipart-post (>= 1.2, < 3) faraday-cookie_jar (0.0.6) @@ -87,34 +92,32 @@ GEM http-cookie (~> 1.0.0) faraday_middleware (1.0.0) faraday (~> 1.0) - fastimage (2.1.7) - fastlane (2.149.1) + fastimage (2.2.0) + fastlane (2.154.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) aws-sdk-s3 (~> 1.0) - babosa (>= 1.0.2, < 2.0.0) + babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) colored commander-fastlane (>= 4.4.6, < 5.0.0) dotenv (>= 2.1.1, < 3.0.0) - emoji_regex (>= 0.1, < 2.0) + emoji_regex (>= 0.1, < 4.0) excon (>= 0.71.0, < 1.0.0) - faraday (>= 0.17, < 2.0) + faraday (~> 1.0) faraday-cookie_jar (~> 0.0.6) - faraday_middleware (>= 0.13.1, < 2.0) + faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) gh_inspector (>= 1.1.2, < 2.0.0) google-api-client (>= 0.37.0, < 0.39.0) google-cloud-storage (>= 1.15.0, < 2.0.0) highline (>= 1.7.2, < 2.0.0) json (< 3.0.0) - jwt (~> 2.1.0) + jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) - multi_xml (~> 0.5) multipart-post (~> 2.0.0) plist (>= 3.1.0, < 4.0.0) - public_suffix (~> 2.0.0) - rubyzip (>= 1.3.0, < 2.0.0) + rubyzip (>= 2.0.0, < 3.0.0) security (= 0.1.3) simctl (~> 1.6.3) slack-notifier (>= 2.0.0, < 3.0.0) @@ -127,6 +130,7 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) fastlane-plugin-versioning (0.4.3) + ffi (1.13.1) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -141,17 +145,17 @@ GEM google-cloud-core (1.5.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) - google-cloud-env (1.3.2) + google-cloud-env (1.3.3) faraday (>= 0.17.3, < 2.0) google-cloud-errors (1.0.1) - google-cloud-storage (1.26.2) + google-cloud-storage (1.27.0) addressable (~> 2.5) digest-crc (~> 0.4) google-api-client (~> 0.33) google-cloud-core (~> 1.2) googleauth (~> 0.9) mini_mime (~> 1.0) - googleauth (0.13.0) + googleauth (0.13.1) faraday (>= 0.17.3, < 2.0) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -166,22 +170,22 @@ GEM concurrent-ruby (~> 1.0) jmespath (1.4.0) json (2.3.1) - jwt (2.1.0) + jwt (2.2.1) memoist (0.16.2) mini_magick (4.10.1) mini_mime (1.0.2) minitest (5.14.1) molinillo (0.6.6) - multi_json (1.14.1) - multi_xml (0.6.0) + multi_json (1.15.0) multipart-post (2.0.0) - nanaimo (0.2.6) + nanaimo (0.3.0) nap (1.1.0) naturally (2.2.0) netrc (0.11.0) - os (1.1.0) + os (1.1.1) plist (3.5.0) - public_suffix (2.0.5) + public_suffix (4.0.5) + rake (13.0.1) representable (3.0.4) declarative (< 0.1.0) declarative-option (< 0.2.0) @@ -189,7 +193,7 @@ GEM retriable (3.1.2) rouge (2.0.7) ruby-macho (1.4.0) - rubyzip (1.3.0) + rubyzip (2.3.0) security (0.1.3) signet (0.14.0) addressable (~> 2.3) @@ -205,9 +209,11 @@ GEM unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) tty-cursor (0.7.1) - tty-screen (0.8.0) + tty-screen (0.8.1) tty-spinner (0.9.3) tty-cursor (~> 0.7) + typhoeus (1.4.0) + ethon (>= 0.9.0) tzinfo (1.2.7) thread_safe (~> 0.1) uber (0.1.0) @@ -219,12 +225,12 @@ GEM xcode-install (2.6.6) claide (>= 0.9.1, < 1.1.0) fastlane (>= 2.1.0, < 3.0.0) - xcodeproj (1.17.0) + xcodeproj (1.17.1) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.2.6) + nanaimo (~> 0.3.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.0) @@ -234,7 +240,7 @@ PLATFORMS ruby DEPENDENCIES - cocoapods (~> 1.8.3) + cocoapods (~> 1.9.3) fastlane fastlane-plugin-versioning xcode-install diff --git a/Podfile b/Podfile index b138e1821..98f581bba 100644 --- a/Podfile +++ b/Podfile @@ -4,116 +4,108 @@ platform :ios, '11.0' # Use frameforks to allow usage of pod written in Swift (like PiwikTracker) use_frameworks! +# Different flavours of pods to MatrixKit. Can be one of: +# - a String indicating an official MatrixKit released version number +# - `:local` (to use Development Pods) +# - `{'kit branch name' => 'sdk branch name'}` to depend on specific branches of each repo +# - `{ {kit spec hash} => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for each repo. Used by Fastfile during CI +# +# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it +$matrixKitVersion = '0.12.10' +# $matrixKitVersion = :local +# $matrixKitVersion = {'develop' => 'develop'} -# Different flavours of pods to MatrixKit -# The current MatrixKit pod version -$matrixKitVersion = '0.12.9' - -# The specific branch version (supported: develop) -#$matrixKitVersion = 'develop' - -# The one used for developing both MatrixSDK and MatrixKit -# Note that MatrixSDK must be cloned into a folder called matrix-ios-sdk next to the MatrixKit folder -#$matrixKitVersion = 'local' +######################################## +case $matrixKitVersion +when :local +$matrixKitVersionSpec = { :path => '../matrix-ios-kit/MatrixKit.podspec' } +$matrixSDKVersionSpec = { :path => '../matrix-ios-sdk/MatrixSDK.podspec' } +when Hash # kit branch name => sdk branch name – or {kit spec Hash} => {sdk spec Hash} +kit_spec, sdk_spec = $matrixKitVersion.first # extract first and only key/value pair; key is kit_spec, value is sdk_spec +kit_spec = { :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => kit_spec.to_s } unless kit_spec.is_a?(Hash) +sdk_spec = { :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => sdk_spec.to_s } unless sdk_spec.is_a?(Hash) +$matrixKitVersionSpec = kit_spec +$matrixSDKVersionSpec = sdk_spec +when String # specific MatrixKit released version +$matrixKitVersionSpec = $matrixKitVersion +$matrixSDKVersionSpec = {} +end # Method to import the right MatrixKit flavour def import_MatrixKit - if $matrixKitVersion == 'local' - pod 'MatrixSDK', :path => '../matrix-ios-sdk/MatrixSDK.podspec' - pod 'MatrixSDK/SwiftSupport', :path => '../matrix-ios-sdk/MatrixSDK.podspec' - pod 'MatrixSDK/JingleCallStack', :path => '../matrix-ios-sdk/MatrixSDK.podspec' - pod 'MatrixKit', :path => '../matrix-ios-kit/MatrixKit.podspec' - else - if $matrixKitVersion == 'develop' - pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => $matrixKitVersion - pod 'MatrixSDK/SwiftSupport', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => $matrixKitVersion - pod 'MatrixSDK/JingleCallStack', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => $matrixKitVersion - pod 'MatrixKit', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => $matrixKitVersion - else - pod 'MatrixKit', $matrixKitVersion - pod 'MatrixSDK/SwiftSupport' - pod 'MatrixSDK/JingleCallStack' - end - end + pod 'MatrixSDK', $matrixSDKVersionSpec + pod 'MatrixSDK/SwiftSupport', $matrixSDKVersionSpec + pod 'MatrixSDK/JingleCallStack', $matrixSDKVersionSpec + pod 'MatrixKit', $matrixKitVersionSpec end # Method to import the right MatrixKit/AppExtension flavour def import_MatrixKitAppExtension - if $matrixKitVersion == 'local' - pod 'MatrixSDK', :path => '../matrix-ios-sdk/MatrixSDK.podspec' - pod 'MatrixSDK/SwiftSupport', :path => '../matrix-ios-sdk/MatrixSDK.podspec' - pod 'MatrixKit/AppExtension', :path => '../matrix-ios-kit/MatrixKit.podspec' - else - if $matrixKitVersion == 'develop' - pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => $matrixKitVersion - pod 'MatrixSDK/SwiftSupport', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => $matrixKitVersion - pod 'MatrixKit/AppExtension', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => $matrixKitVersion - else - pod 'MatrixKit/AppExtension', $matrixKitVersion - pod 'MatrixSDK/SwiftSupport' - end - end + pod 'MatrixSDK', $matrixSDKVersionSpec + pod 'MatrixSDK/SwiftSupport', $matrixSDKVersionSpec + pod 'MatrixKit/AppExtension', $matrixKitVersionSpec end +######################################## abstract_target 'RiotPods' do - pod 'GBDeviceInfo', '~> 6.3.0' - pod 'Reusable', '~> 4.1' - pod 'KeychainAccess', '~> 4.2' + pod 'GBDeviceInfo', '~> 6.3.0' + pod 'Reusable', '~> 4.1' + pod 'KeychainAccess', '~> 4.2' - # Piwik for analytics - pod 'MatomoTracker', '~> 7.2.0' + # Piwik for analytics + pod 'MatomoTracker', '~> 7.2.0' - # Remove warnings from "bad" pods - pod 'OLMKit', :inhibit_warnings => true - pod 'cmark', :inhibit_warnings => true - pod 'zxcvbn-ios' + # Remove warnings from "bad" pods + pod 'OLMKit', :inhibit_warnings => true + pod 'cmark', :inhibit_warnings => true + pod 'zxcvbn-ios' - # Tools - pod 'SwiftGen', '~> 6.1' - pod 'SwiftLint', '~> 0.36.0' + # Tools + pod 'SwiftGen', '~> 6.1' + pod 'SwiftLint', '~> 0.36.0' - target "Riot" do - import_MatrixKit - pod 'DGCollectionViewLeftAlignFlowLayout', '~> 1.0.4' - pod 'KTCenterFlowLayout', '~> 1.3.1' - pod 'ZXingObjC', '~> 3.6.5' - - target 'RiotTests' do - inherit! :search_paths - end - end - - target "RiotShareExtension" do - import_MatrixKitAppExtension - end + target "Riot" do + import_MatrixKit + pod 'DGCollectionViewLeftAlignFlowLayout', '~> 1.0.4' + pod 'KTCenterFlowLayout', '~> 1.3.1' + pod 'ZXingObjC', '~> 3.6.5' - target "SiriIntents" do - import_MatrixKitAppExtension + target 'RiotTests' do + inherit! :search_paths end - - target "RiotNSE" do - import_MatrixKitAppExtension - end - + end + + target "RiotShareExtension" do + import_MatrixKitAppExtension + end + + target "SiriIntents" do + import_MatrixKitAppExtension + end + + target "RiotNSE" do + import_MatrixKitAppExtension + end + end post_install do |installer| - installer.pods_project.targets.each do |target| + installer.pods_project.targets.each do |target| - # Disable bitcode for each pod framework - # 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 - end + # Disable bitcode for each pod framework + # 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 end + end end diff --git a/Podfile.lock b/Podfile.lock index ea423cac5..373f20df1 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -44,44 +44,45 @@ PODS: - GZIP (1.2.3) - HPGrowingTextView (1.1) - JitsiMeetSDK (2.8.1) + - KeychainAccess (4.2.0) - KTCenterFlowLayout (1.3.1) - libbase58 (0.1.4) - libPhoneNumber-iOS (0.9.15) - MatomoTracker (7.2.1): - MatomoTracker/Core (= 7.2.1) - MatomoTracker/Core (7.2.1) - - MatrixKit (0.12.9): + - MatrixKit (0.12.10): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.23) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixKit/Core (= 0.12.9) - - MatrixSDK (= 0.16.8) - - MatrixKit/AppExtension (0.12.9): + - MatrixKit/Core (= 0.12.10) + - MatrixSDK (= 0.16.9) + - MatrixKit/AppExtension (0.12.10): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.23) - DTCoreText/Extension - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.16.8) - - MatrixKit/Core (0.12.9): + - MatrixSDK (= 0.16.9) + - MatrixKit/Core (0.12.10): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.23) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.16.8) - - MatrixSDK (0.16.8): - - MatrixSDK/Core (= 0.16.8) - - MatrixSDK/Core (0.16.8): + - MatrixSDK (= 0.16.9) + - MatrixSDK (0.16.9): + - MatrixSDK/Core (= 0.16.9) + - MatrixSDK/Core (0.16.9): - AFNetworking (~> 4.0.0) - GZIP (~> 1.2.2) - libbase58 (~> 0.1.4) - OLMKit (~> 3.1.0) - Realm (~> 4.4.0) - - MatrixSDK/JingleCallStack (0.16.8): + - MatrixSDK/JingleCallStack (0.16.9): - JitsiMeetSDK (~> 2.8.1) - MatrixSDK/Core - - MatrixSDK/SwiftSupport (0.16.8): + - MatrixSDK/SwiftSupport (0.16.9): - MatrixSDK/Core - OLMKit (3.1.0): - OLMKit/olmc (= 3.1.0) @@ -107,10 +108,12 @@ DEPENDENCIES: - cmark - DGCollectionViewLeftAlignFlowLayout (~> 1.0.4) - GBDeviceInfo (~> 6.3.0) + - KeychainAccess (~> 4.2) - KTCenterFlowLayout (~> 1.3.1) - MatomoTracker (~> 7.2.0) - - MatrixKit (= 0.12.9) - - MatrixKit/AppExtension (= 0.12.9) + - MatrixKit (= 0.12.10) + - MatrixKit/AppExtension (= 0.12.10) + - MatrixSDK - MatrixSDK/JingleCallStack - MatrixSDK/SwiftSupport - OLMKit @@ -131,6 +134,7 @@ SPEC REPOS: - GZIP - HPGrowingTextView - JitsiMeetSDK + - KeychainAccess - KTCenterFlowLayout - libbase58 - libPhoneNumber-iOS @@ -155,12 +159,13 @@ SPEC CHECKSUMS: GZIP: af5c90ef903776a7e9afe6ebebd794a84a2929d4 HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19 JitsiMeetSDK: 2984eac1343690bf1c0c72bde75b48b0148d0f79 + KeychainAccess: 3f760109aa99b05d0f231e28b22642da7153e38a KTCenterFlowLayout: 6e02b50ab2bd865025ae82fe266ed13b6d9eaf97 libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 MatomoTracker: 246b6b0693cf39b356134dec7561f719d3538b96 - MatrixKit: 1de12cd41057284fe4594ebc08073263ca28bca3 - MatrixSDK: 4800841d0fe5eb8a5534daf8873582b367e4f2ca + MatrixKit: 6937446581f1c71011e47db8b302dc912433edb2 + MatrixSDK: 007988f3ef43983a6b1c1f0087a18c7e2598abfa OLMKit: 4ee0159d63feeb86d836fdcfefe418e163511639 Realm: 4eb04d7487bd43c0581256f40b424eafb711deff Reusable: 53a9acf5c536f229b31b5865782414b508252ddb @@ -169,6 +174,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 0f7f169726d2d7737bb2ca4020afd5534edbe9c9 +PODFILE CHECKSUM: 44306ac00e0905967588b3035b5494bc26836188 COCOAPODS: 1.9.3 diff --git a/README.rst b/README.rst index d5fecff30..e0da5d35f 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ Build instructions Before opening the Element Xcode workspace, you need to build it with the CocoaPods command:: - $ cd Riot + $ cd Element $ bundle install $ bundle exec pod install diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index d4b4ca8a8..f8d059dc8 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -178,7 +178,6 @@ B108932323AB908A00802670 /* KeyVerificationRequestStatusViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932223AB908A00802670 /* KeyVerificationRequestStatusViewData.swift */; }; B108932523AB93A200802670 /* KeyVerificationConclusionViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932423AB93A200802670 /* KeyVerificationConclusionViewData.swift */; }; B108932823ABEE6800802670 /* BubbleCellReadReceiptsDisplayable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932723ABEE6700802670 /* BubbleCellReadReceiptsDisplayable.swift */; }; - B108932A23ACBA0B00802670 /* SizingViewHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = B108932923ACBA0B00802670 /* SizingViewHeight.swift */; }; B1098BDF21ECE09F000DDA48 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDA21ECE09E000DDA48 /* Strings.swift */; }; B1098BE121ECE09F000DDA48 /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDC21ECE09E000DDA48 /* Images.swift */; }; B1098BE321ECE09F000DDA48 /* RiotDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098BDE21ECE09E000DDA48 /* RiotDefaults.swift */; }; @@ -354,6 +353,13 @@ B1B336C3242B933700F95EC4 /* KeyVerificationSelfVerifyStartCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B336BB242B933500F95EC4 /* KeyVerificationSelfVerifyStartCoordinator.swift */; }; B1B336C4242B933700F95EC4 /* KeyVerificationSelfVerifyStartViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B336BC242B933600F95EC4 /* KeyVerificationSelfVerifyStartViewAction.swift */; }; B1B336C5242B933700F95EC4 /* KeyVerificationSelfVerifyStartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B336BD242B933600F95EC4 /* KeyVerificationSelfVerifyStartViewModel.swift */; }; + B1B4E9B924D46EB3004D5C33 /* SizingViewHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B4E9B624D46EB3004D5C33 /* SizingViewHeight.swift */; }; + B1B4E9BA24D46EB4004D5C33 /* SizableBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B4E9B724D46EB3004D5C33 /* SizableBubbleCell.swift */; }; + B1B4E9BB24D46EB4004D5C33 /* SizingViewHeightStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B4E9B824D46EB3004D5C33 /* SizingViewHeightStore.swift */; }; + B1B4E9BD24D4701F004D5C33 /* BubbleCellReactionsDisplayable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B4E9BC24D4701F004D5C33 /* BubbleCellReactionsDisplayable.swift */; }; + B1B4E9BF24D4703E004D5C33 /* BaseBubbleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B4E9BE24D4703E004D5C33 /* BaseBubbleCell.swift */; }; + B1B4E9C224D471FD004D5C33 /* BubbleReactionsViewSizer.m in Sources */ = {isa = PBXBuildFile; fileRef = B1B4E9C024D471FD004D5C33 /* BubbleReactionsViewSizer.m */; }; + B1B4E9C424D47207004D5C33 /* BubbleReactionsViewModelBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1B4E9C324D47206004D5C33 /* BubbleReactionsViewModelBuilder.swift */; }; B1B5571820EE6C4D00210D55 /* CountryPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1B5567A20EE6C4C00210D55 /* CountryPickerViewController.m */; }; B1B5571920EE6C4D00210D55 /* LanguagePickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1B5567C20EE6C4C00210D55 /* LanguagePickerViewController.m */; }; B1B5571A20EE6C4D00210D55 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1B5567E20EE6C4C00210D55 /* SettingsViewController.m */; }; @@ -769,6 +775,7 @@ EC3B066A24AC6ADE000DF9BF /* CrossSigningSetupBannerCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC3B066624AC6ADD000DF9BF /* CrossSigningSetupBannerCell.xib */; }; EC3B066B24AC6ADE000DF9BF /* CrossSigningBannerPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3B066724AC6ADD000DF9BF /* CrossSigningBannerPreferences.swift */; }; EC3B066C24AC6ADE000DF9BF /* CrossSigningSetupBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3B066824AC6ADD000DF9BF /* CrossSigningSetupBannerCell.swift */; }; + EC619C1924DAD96000663A80 /* UIScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC619C1824DAD96000663A80 /* UIScrollView.swift */; }; EC711B4624A63B13008F830C /* MXRecoveryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC711B4524A63B13008F830C /* MXRecoveryService.swift */; }; EC711B7424A63B37008F830C /* SecretsSetupRecoveryKeyViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC711B4A24A63B36008F830C /* SecretsSetupRecoveryKeyViewModelType.swift */; }; EC711B7524A63B37008F830C /* SecretsSetupRecoveryKeyCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC711B4B24A63B36008F830C /* SecretsSetupRecoveryKeyCoordinatorType.swift */; }; @@ -1107,7 +1114,6 @@ B108932223AB908A00802670 /* KeyVerificationRequestStatusViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationRequestStatusViewData.swift; sourceTree = ""; }; B108932423AB93A200802670 /* KeyVerificationConclusionViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationConclusionViewData.swift; sourceTree = ""; }; B108932723ABEE6700802670 /* BubbleCellReadReceiptsDisplayable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleCellReadReceiptsDisplayable.swift; sourceTree = ""; }; - B108932923ACBA0B00802670 /* SizingViewHeight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizingViewHeight.swift; sourceTree = ""; }; B1098BDA21ECE09E000DDA48 /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; B1098BDC21ECE09E000DDA48 /* Images.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Images.swift; sourceTree = ""; }; B1098BDE21ECE09E000DDA48 /* RiotDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RiotDefaults.swift; sourceTree = ""; }; @@ -1333,6 +1339,14 @@ B1B336BB242B933500F95EC4 /* KeyVerificationSelfVerifyStartCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationSelfVerifyStartCoordinator.swift; sourceTree = ""; }; B1B336BC242B933600F95EC4 /* KeyVerificationSelfVerifyStartViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationSelfVerifyStartViewAction.swift; sourceTree = ""; }; B1B336BD242B933600F95EC4 /* KeyVerificationSelfVerifyStartViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationSelfVerifyStartViewModel.swift; sourceTree = ""; }; + B1B4E9B624D46EB3004D5C33 /* SizingViewHeight.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizingViewHeight.swift; sourceTree = ""; }; + B1B4E9B724D46EB3004D5C33 /* SizableBubbleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizableBubbleCell.swift; sourceTree = ""; }; + B1B4E9B824D46EB3004D5C33 /* SizingViewHeightStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizingViewHeightStore.swift; sourceTree = ""; }; + B1B4E9BC24D4701F004D5C33 /* BubbleCellReactionsDisplayable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleCellReactionsDisplayable.swift; sourceTree = ""; }; + B1B4E9BE24D4703E004D5C33 /* BaseBubbleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseBubbleCell.swift; sourceTree = ""; }; + B1B4E9C024D471FD004D5C33 /* BubbleReactionsViewSizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BubbleReactionsViewSizer.m; sourceTree = ""; }; + B1B4E9C124D471FD004D5C33 /* BubbleReactionsViewSizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BubbleReactionsViewSizer.h; sourceTree = ""; }; + B1B4E9C324D47206004D5C33 /* BubbleReactionsViewModelBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionsViewModelBuilder.swift; sourceTree = ""; }; B1B5567920EE6C4C00210D55 /* CountryPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CountryPickerViewController.h; sourceTree = ""; }; B1B5567A20EE6C4C00210D55 /* CountryPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CountryPickerViewController.m; sourceTree = ""; }; B1B5567C20EE6C4C00210D55 /* LanguagePickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LanguagePickerViewController.m; sourceTree = ""; }; @@ -1898,6 +1912,7 @@ EC3B066624AC6ADD000DF9BF /* CrossSigningSetupBannerCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CrossSigningSetupBannerCell.xib; sourceTree = ""; }; EC3B066724AC6ADD000DF9BF /* CrossSigningBannerPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossSigningBannerPreferences.swift; sourceTree = ""; }; EC3B066824AC6ADD000DF9BF /* CrossSigningSetupBannerCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossSigningSetupBannerCell.swift; sourceTree = ""; }; + EC619C1824DAD96000663A80 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = ""; }; EC711B4524A63B13008F830C /* MXRecoveryService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXRecoveryService.swift; sourceTree = ""; }; EC711B4A24A63B36008F830C /* SecretsSetupRecoveryKeyViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewModelType.swift; sourceTree = ""; }; EC711B4B24A63B36008F830C /* SecretsSetupRecoveryKeyCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyCoordinatorType.swift; sourceTree = ""; }; @@ -2487,14 +2502,16 @@ path = Success; sourceTree = ""; }; - B108932623ABE82C00802670 /* BaseContentViews */ = { + B108932623ABE82C00802670 /* BaseBubbleCell */ = { isa = PBXGroup; children = ( - B108932723ABEE6700802670 /* BubbleCellReadReceiptsDisplayable.swift */, + B1B4E9BE24D4703E004D5C33 /* BaseBubbleCell.swift */, B14084C523BF76890010F692 /* BubbleCellContentView.swift */, B14084C723BF76CB0010F692 /* BubbleCellContentView.xib */, + B108932723ABEE6700802670 /* BubbleCellReadReceiptsDisplayable.swift */, + B1B4E9BC24D4701F004D5C33 /* BubbleCellReactionsDisplayable.swift */, ); - path = BaseContentViews; + path = BaseBubbleCell; sourceTree = ""; }; B1098BD921ECE09E000DDA48 /* Generated */ = { @@ -3052,11 +3069,14 @@ 329E746422CD02EA006F9797 /* BubbleReactionActionViewCell.xib */, B1963B31228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift */, B1963B27228F1C4800CBA17F /* BubbleReactionsViewModel.swift */, + B1B4E9C324D47206004D5C33 /* BubbleReactionsViewModelBuilder.swift */, B1963B25228F1C4800CBA17F /* BubbleReactionsView.swift */, B1963B2A228F1C4800CBA17F /* BubbleReactionsView.xib */, B1963B28228F1C4800CBA17F /* BubbleReactionViewData.swift */, B1963B29228F1C4800CBA17F /* BubbleReactionViewCell.swift */, B1963B26228F1C4800CBA17F /* BubbleReactionViewCell.xib */, + B1B4E9C124D471FD004D5C33 /* BubbleReactionsViewSizer.h */, + B1B4E9C024D471FD004D5C33 /* BubbleReactionsViewSizer.m */, ); path = BubbleReactions; sourceTree = ""; @@ -3080,7 +3100,6 @@ B1A12C65239ABBDB00AA2B86 /* KeyVerification */ = { isa = PBXGroup; children = ( - B108932923ACBA0B00802670 /* SizingViewHeight.swift */, B1C543A3239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift */, B1C543A5239E999700DCA1FA /* KeyVerificationCellInnerContentView.xib */, B1C543AF23A2871300DCA1FA /* KeyVerificationBaseBubbleCell.swift */, @@ -3162,6 +3181,16 @@ path = SelfVerifyStart; sourceTree = ""; }; + B1B4E9B524D46EB3004D5C33 /* SizableCell */ = { + isa = PBXGroup; + children = ( + B1B4E9B624D46EB3004D5C33 /* SizingViewHeight.swift */, + B1B4E9B724D46EB3004D5C33 /* SizableBubbleCell.swift */, + B1B4E9B824D46EB3004D5C33 /* SizingViewHeightStore.swift */, + ); + path = SizableCell; + sourceTree = ""; + }; B1B5567620EE6C4C00210D55 /* Modules */ = { isa = PBXGroup; children = ( @@ -4018,7 +4047,8 @@ B1B5583F20EF768E00210D55 /* BubbleCells */ = { isa = PBXGroup; children = ( - B108932623ABE82C00802670 /* BaseContentViews */, + B108932623ABE82C00802670 /* BaseBubbleCell */, + B1B4E9B524D46EB3004D5C33 /* SizableCell */, B1A12C65239ABBDB00AA2B86 /* KeyVerification */, B1B5584220EF768E00210D55 /* Encryption */, B1B5589220EF768E00210D55 /* RoomEmptyBubbleCell.h */, @@ -4964,6 +4994,7 @@ B1CA3A2821EF692B000D1D89 /* UIView.swift */, B140B4A121F87F7100E3F5FE /* OperationQueue.swift */, B1E5368821FB1E20001F3AFF /* UIButton.swift */, + EC619C1824DAD96000663A80 /* UIScrollView.swift */, 3281BCF62201FA4200F4A383 /* UIControl.swift */, B109D6F0222D8C400061B6D9 /* UIApplication.swift */, B1DB4F05223015080065DBFA /* Character.swift */, @@ -5742,12 +5773,14 @@ B1FDF56021F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift in Sources */, B1B5573120EE6C4D00210D55 /* BugReportViewController.m in Sources */, 324A2051225FC571004FE8B0 /* DeviceVerificationIncomingViewState.swift in Sources */, + B1B4E9BF24D4703E004D5C33 /* BaseBubbleCell.swift in Sources */, B16932A520F3A21C00746532 /* empty.mm in Sources */, 3232AB4A2256558300AD6A5C /* FlowTemplateCoordinator.swift in Sources */, B19EFA3B21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift in Sources */, B1B9DEDE22E9D9890065E677 /* EmojiServiceType.swift in Sources */, EC1CA89724C9C9A200DE9EBF /* SetupBiometricsViewModelType.swift in Sources */, 3232ABA9225730E100AD6A5C /* DeviceVerificationStartViewModel.swift in Sources */, + B1B4E9BB24D46EB4004D5C33 /* SizingViewHeightStore.swift in Sources */, 32DB557C22FDADE50016329E /* ServiceTermsModalScreenViewModelType.swift in Sources */, B16932FA20F3C51A00746532 /* RecentCellData.m in Sources */, EC85D72B2477DCF2002C44C9 /* KeyVerificationManuallyVerifyCoordinatorType.swift in Sources */, @@ -5910,6 +5943,7 @@ 32DB557722FDADE50016329E /* ServiceTermsModalCoordinator.swift in Sources */, B185145B24B8C98200EE19EA /* MajorUpdateViewController.swift in Sources */, 32DB557922FDADE50016329E /* ServiceTermsModalScreenViewModel.swift in Sources */, + B1B4E9BA24D46EB4004D5C33 /* SizableBubbleCell.swift in Sources */, 39D49C7E24B8D42A00FEDBC8 /* TextView.swift in Sources */, 32891D75226728EE00C82226 /* KeyVerificationDataLoadingViewController.swift in Sources */, F083BDEF1E7009ED00A9B29C /* UINavigationController+Riot.m in Sources */, @@ -6048,10 +6082,10 @@ B1B5599320EFC5E400210D55 /* DecryptionFailure.m in Sources */, 39D49C7D24B8D42A00FEDBC8 /* Timeline.swift in Sources */, B1CE83E12422817200D07506 /* KeyVerificationVerifyBySASCoordinator.swift in Sources */, + EC619C1924DAD96000663A80 /* UIScrollView.swift in Sources */, B125FE1F231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift in Sources */, EC85D7162477DCD7002C44C9 /* KeyVerificationScanConfirmationViewAction.swift in Sources */, EC711BAF24A63B58008F830C /* SecureBackupSetupCoordinatorType.swift in Sources */, - B108932A23ACBA0B00802670 /* SizingViewHeight.swift in Sources */, EC1CA89C24C9C9A200DE9EBF /* SetupBiometricsViewModel.swift in Sources */, B157FAA323264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewState.swift in Sources */, B1098BF921ECFE65000DDA48 /* KeyBackupSetupCoordinator.swift in Sources */, @@ -6133,6 +6167,7 @@ 32A6001A22C661100042C1D9 /* EditHistoryCoordinator.swift in Sources */, F083BD1E1E7009ED00A9B29C /* AppDelegate.m in Sources */, B1B558E620EF768F00210D55 /* RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, + B1B4E9BD24D4701F004D5C33 /* BubbleCellReactionsDisplayable.swift in Sources */, 329E746722CD02EA006F9797 /* BubbleReactionActionViewCell.swift in Sources */, B1098BFB21ECFE65000DDA48 /* KeyBackupSetupCoordinatorType.swift in Sources */, B1098BF721ECFE65000DDA48 /* PasswordStrength.swift in Sources */, @@ -6168,6 +6203,7 @@ B1D211E622C194A200D939BD /* ReactionsMenuViewState.swift in Sources */, B17982FF2119FED2001FD722 /* GDPRConsentViewController.swift in Sources */, B1098BE121ECE09F000DDA48 /* Images.swift in Sources */, + B1B4E9C424D47207004D5C33 /* BubbleReactionsViewModelBuilder.swift in Sources */, EC85D72A2477DCF2002C44C9 /* KeyVerificationManuallyVerifyViewModel.swift in Sources */, B1BEE74A23E093260003A4CB /* UserVerificationSessionStatusCoordinatorType.swift in Sources */, 3232ABA4225730E100AD6A5C /* DeviceVerificationStartViewAction.swift in Sources */, @@ -6200,6 +6236,7 @@ EC85D71A2477DCD7002C44C9 /* KeyVerificationScanConfirmationCoordinator.swift in Sources */, EC85D754247C0F5B002C44C9 /* Constants.swift in Sources */, B1B336C4242B933700F95EC4 /* KeyVerificationSelfVerifyStartViewAction.swift in Sources */, + B1B4E9B924D46EB3004D5C33 /* SizingViewHeight.swift in Sources */, B1B5590920EF768F00210D55 /* RoomEmptyBubbleCell.m in Sources */, 324A2054225FC571004FE8B0 /* DeviceVerificationIncomingCoordinatorType.swift in Sources */, B139C21F21FE5D6600BB68EC /* KeyBackupRecoverFromPassphraseViewAction.swift in Sources */, @@ -6310,6 +6347,7 @@ B1CE83DA2422817200D07506 /* KeyVerificationVerifyByScanningViewModel.swift in Sources */, 32242F0921E8B05F00725742 /* UIColor.swift in Sources */, B16932E720F3C37100746532 /* HomeMessagesSearchDataSource.m in Sources */, + B1B4E9C224D471FD004D5C33 /* BubbleReactionsViewSizer.m in Sources */, B12D79FF23E2462200FACEDC /* UserVerificationStartViewState.swift in Sources */, B1B558CE20EF768F00210D55 /* RoomOutgoingEncryptedAttachmentBubbleCell.m in Sources */, B1B5577D20EE84BF00210D55 /* CircleButton.m in Sources */, @@ -6727,7 +6765,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1.0.2; + CURRENT_PROJECT_VERSION = 1.0.4; DEFINES_MODULE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -6747,7 +6785,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.0.2; + MARKETING_VERSION = 1.0.4; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -6785,7 +6823,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 1.0.2; + CURRENT_PROJECT_VERSION = 1.0.4; DEFINES_MODULE = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -6798,7 +6836,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.0.2; + MARKETING_VERSION = 1.0.4; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 0b2ba08d0..2980dfc88 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1939,7 +1939,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni account.mxSession.roomSummaryUpdateDelegate = eventFormatter; // Set the push gateway URL. - account.pushGatewayURL = BuildSettings.sygnalAPIUrlString; + account.pushGatewayURL = BuildSettings.serverConfigSygnalAPIUrlString; BOOL isPushRegistered = self.pushNotificationService.isPushRegistered; @@ -2055,7 +2055,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Set this url in the existing accounts when it is undefined. if (!account.pushGatewayURL) { - account.pushGatewayURL = BuildSettings.sygnalAPIUrlString; + account.pushGatewayURL = BuildSettings.serverConfigSygnalAPIUrlString; } } @@ -4533,7 +4533,14 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Register "Riot-Defaults.plist" default values NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"]; NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"]; - NSDictionary *defaults = [NSDictionary dictionaryWithContentsOfFile:defaultsPathFromApp]; + NSMutableDictionary *defaults = [[NSDictionary dictionaryWithContentsOfFile:defaultsPathFromApp] mutableCopy]; + + // add pusher ids, as they don't belong to plist anymore + defaults[@"pushKitAppIdProd"] = BuildSettings.pushKitAppIdProd; + defaults[@"pushKitAppIdDev"] = BuildSettings.pushKitAppIdDev; + defaults[@"pusherAppIdProd"] = BuildSettings.pusherAppIdProd; + defaults[@"pusherAppIdDev"] = BuildSettings.pusherAppIdDev; + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; if (!RiotSettings.shared.isUserDefaultsMigrated) diff --git a/Riot/Assets/Riot-Defaults.plist b/Riot/Assets/Riot-Defaults.plist index 31fffdc9f..28d0d04b8 100644 --- a/Riot/Assets/Riot-Defaults.plist +++ b/Riot/Assets/Riot-Defaults.plist @@ -6,14 +6,6 @@ pinRoomsWithUnread - pushKitAppIdProd - im.vector.app.ios.voip.prod - pushKitAppIdDev - im.vector.app.ios.voip.dev - pusherAppIdDev - im.vector.app.ios.dev - pusherAppIdProd - im.vector.app.ios.prod matrixApps showAllEventsInRoomHistory diff --git a/Riot/Categories/UIScrollView.swift b/Riot/Categories/UIScrollView.swift new file mode 100644 index 000000000..ff4548c5a --- /dev/null +++ b/Riot/Categories/UIScrollView.swift @@ -0,0 +1,34 @@ +// +// Copyright 2020 Vector Creations Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +extension UIScrollView { + + /// Scroll to the given view, which must be a view in the scrollView. + /// - Parameters: + /// - view: The view to scroll + /// - insets: Insets for the scroll area. Provide negative values for more visible area than the view's frame + /// - animated: animate the scroll + @objc func vc_scroll(to view: UIView, with insets: UIEdgeInsets = .zero, animated: Bool = true) { + // find the view's frame in the scrollView with given insets + let rect = view.convert(view.frame, to: self).inset(by: insets) + DispatchQueue.main.async { + self.scrollRectToVisible(rect, animated: animated) + } + } + +} diff --git a/Riot/Generated/InfoPlist.swift b/Riot/Generated/InfoPlist.swift index f91383fff..95bdbe12c 100644 --- a/Riot/Generated/InfoPlist.swift +++ b/Riot/Generated/InfoPlist.swift @@ -44,6 +44,8 @@ internal enum InfoPlist { internal static let uiViewControllerBasedStatusBarAppearance: Bool = _document["UIViewControllerBasedStatusBarAppearance"] internal static let userDefaults: String = _document["UserDefaults"] internal static let applicationGroupIdentifier: String = _document["applicationGroupIdentifier"] + internal static let baseBundleIdentifier: String = _document["baseBundleIdentifier"] + internal static let keychainAccessGroup: String = _document["keychainAccessGroup"] } // swiftlint:enable identifier_name line_length type_body_length diff --git a/Riot/Generated/RiotDefaults.swift b/Riot/Generated/RiotDefaults.swift index fc3e4c799..28973433c 100644 --- a/Riot/Generated/RiotDefaults.swift +++ b/Riot/Generated/RiotDefaults.swift @@ -12,45 +12,22 @@ import Foundation internal enum RiotDefaults { private static let _document = PlistDocument(path: "Riot-Defaults.plist") - internal static let bugReportApp: String = _document["bugReportApp"] - internal static let bugReportEndpointUrl: String = _document["bugReportEndpointUrl"] internal static let createConferenceCallsWithJitsi: Bool = _document["createConferenceCallsWithJitsi"] internal static let enableBotCreation: Bool = _document["enableBotCreation"] internal static let enableRageShake: Bool = _document["enableRageShake"] - internal static let homeserver: String = _document["homeserver"] - internal static let homeserverurl: String = _document["homeserverurl"] - internal static let identityserverurl: String = _document["identityserverurl"] - internal static let integrationsRestUrl: String = _document["integrationsRestUrl"] - internal static let integrationsUiUrl: String = _document["integrationsUiUrl"] - internal static let integrationsWidgetsUrls: [String] = _document["integrationsWidgetsUrls"] - internal static let jitsiServerURL: String = _document["jitsiServerURL"] internal static let matrixApps: Bool = _document["matrixApps"] internal static let maxAllowedMediaCacheSize: Int = _document["maxAllowedMediaCacheSize"] internal static let pinRoomsWithMissedNotif: Bool = _document["pinRoomsWithMissedNotif"] internal static let pinRoomsWithUnread: Bool = _document["pinRoomsWithUnread"] - internal static let piwik: [String: Any] = _document["piwik"] internal static let presenceColorForOfflineUser: Int = _document["presenceColorForOfflineUser"] internal static let presenceColorForOnlineUser: Int = _document["presenceColorForOnlineUser"] internal static let presenceColorForUnavailableUser: Int = _document["presenceColorForUnavailableUser"] - internal static let pushGatewayURL: String = _document["pushGatewayURL"] - internal static let pushKitAppIdDev: String = _document["pushKitAppIdDev"] - internal static let pushKitAppIdProd: String = _document["pushKitAppIdProd"] - internal static let pusherAppIdDev: String = _document["pusherAppIdDev"] - internal static let pusherAppIdProd: String = _document["pusherAppIdProd"] - internal static let roomDirectoryServers: [String: Any] = _document["roomDirectoryServers"] - internal static let settingsCopyrightUrl: String = _document["settingsCopyrightUrl"] - internal static let settingsPrivacyPolicyUrl: String = _document["settingsPrivacyPolicyUrl"] - internal static let settingsTermsConditionsUrl: String = _document["settingsTermsConditionsUrl"] internal static let showAllEventsInRoomHistory: Bool = _document["showAllEventsInRoomHistory"] internal static let showLeftMembersInRoomMemberList: Bool = _document["showLeftMembersInRoomMemberList"] internal static let showRedactionsInRoomHistory: Bool = _document["showRedactionsInRoomHistory"] internal static let showUnsupportedEventsInRoomHistory: Bool = _document["showUnsupportedEventsInRoomHistory"] internal static let sortRoomMembersUsingLastSeenTime: Bool = _document["sortRoomMembersUsingLastSeenTime"] - internal static let stunServerFallback: String = _document["stunServerFallback"] internal static let syncLocalContacts: Bool = _document["syncLocalContacts"] - internal static let webAppUrl: String = _document["webAppUrl"] - internal static let webAppUrlDev: String = _document["webAppUrlDev"] - internal static let webAppUrlStaging: String = _document["webAppUrlStaging"] } // swiftlint:enable identifier_name line_length type_body_length diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 69d509385..ff25ed412 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -51,7 +51,7 @@ final class RiotSettings: NSObject { var homeserverUrlString: String { get { - return defaults.string(forKey: UserDefaultsKeys.homeserverUrlString) ?? BuildSettings.defaultHomeserverUrlString + return defaults.string(forKey: UserDefaultsKeys.homeserverUrlString) ?? BuildSettings.serverConfigDefaultHomeserverUrlString } set { defaults.set(newValue, forKey: UserDefaultsKeys.homeserverUrlString) } @@ -59,7 +59,7 @@ final class RiotSettings: NSObject { var identityServerUrlString: String { get { - return defaults.string(forKey: UserDefaultsKeys.identityServerUrlString) ?? BuildSettings.defaultIdentityServerUrlString + return defaults.string(forKey: UserDefaultsKeys.identityServerUrlString) ?? BuildSettings.serverConfigDefaultIdentityServerUrlString } set { defaults.set(newValue, forKey: UserDefaultsKeys.identityServerUrlString) } diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index a1fa10105..f494903e5 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -59,6 +59,7 @@ @property (nonatomic, readonly) BOOL isIdentityServerConfigured; @property (nonatomic, strong) KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter; @property (nonatomic, strong) SetPinCoordinatorBridgePresenter *setPinCoordinatorBridgePresenter; +@property (nonatomic, strong) KeyboardAvoider *keyboardAvoider; @end @@ -168,6 +169,8 @@ [self userInterfaceThemeDidChange]; [self updateUniversalLink]; + + _keyboardAvoider = [[KeyboardAvoider alloc] initWithScrollViewContainerView:self.view scrollView:self.authenticationScrollView]; } - (void)userInterfaceThemeDidChange @@ -271,6 +274,8 @@ // Screen tracking [[Analytics sharedInstance] trackScreen:@"Authentication"]; + + [_keyboardAvoider startAvoiding]; } - (void)viewDidAppear:(BOOL)animated @@ -296,6 +301,13 @@ } } +- (void)viewDidDisappear:(BOOL)animated +{ + [_keyboardAvoider stopAvoiding]; + + [super viewDidDisappear:animated]; +} + - (void)destroy { [super destroy]; @@ -314,6 +326,7 @@ autoDiscovery = nil; _keyVerificationCoordinatorBridgePresenter = nil; + _keyboardAvoider = nil; } - (BOOL)isIdentityServerConfigured @@ -1021,6 +1034,10 @@ { constant += customServersContainerFrame.size.height; } + else + { + constant += self.customServersTickButton.frame.size.height; + } } } @@ -1124,6 +1141,13 @@ }]; } +#pragma mark - UITextFieldDelegate + +- (void)textFieldDidBeginEditing:(UITextField *)textField +{ + [self.authenticationScrollView vc_scrollTo:textField with:UIEdgeInsetsMake(-20, 0, -20, 0) animated:YES]; +} + #pragma mark - KVO - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context diff --git a/Riot/Modules/Authentication/AuthenticationViewController.xib b/Riot/Modules/Authentication/AuthenticationViewController.xib index 44d5623af..e388674d0 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.xib +++ b/Riot/Modules/Authentication/AuthenticationViewController.xib @@ -1,5 +1,5 @@ - + @@ -83,7 +83,7 @@ - + diff --git a/Riot/Modules/Common/KeyboardAvoiding/KeyboardAvoider.swift b/Riot/Modules/Common/KeyboardAvoiding/KeyboardAvoider.swift index 3413dabd6..90090723c 100644 --- a/Riot/Modules/Common/KeyboardAvoiding/KeyboardAvoider.swift +++ b/Riot/Modules/Common/KeyboardAvoiding/KeyboardAvoider.swift @@ -16,8 +16,9 @@ import Foundation +@objcMembers /// Avoid keyboard overlap with scroll view content -final class KeyboardAvoider { +final class KeyboardAvoider: NSObject { // MARK: - Constants @@ -40,6 +41,7 @@ final class KeyboardAvoider { init(scrollViewContainerView: UIView, scrollView: UIScrollView) { self.scrollViewContainerView = scrollViewContainerView self.scrollView = scrollView + super.init() } // MARK: - Public @@ -93,7 +95,7 @@ final class KeyboardAvoider { let keyboardFrameInView = view.convert(keyboardFrame, from: nil) // Find how much the keyboard overlaps the scroll view - let scrollViewBottomInset = scrollView.frame.maxY - keyboardFrameInView.origin.y + let scrollViewBottomInset = max(scrollView.frame.maxY - keyboardFrameInView.origin.y - view.safeAreaInsets.bottom, 0) UIView.animate(withDuration: animationDuration, delay: 0.0, diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index 52d468954..c867a6825 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -425,7 +425,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou } if (_recentsDataSourceMode == RecentsDataSourceModeRooms - && BuildSettings.showPublicRoomDirectory) + && BuildSettings.publicRoomsShowDirectory) { // Add the directory section after "ROOMS" directorySection = sectionsCount++; @@ -515,7 +515,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou } else if (section == directorySection && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_DIRECTORY) - && BuildSettings.allowRoomDirectoryServersChange) + && BuildSettings.publicRoomsAllowServerChange) { return RECENTSDATASOURCE_DIRECTORY_SECTION_HEADER_HEIGHT; } @@ -767,7 +767,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (section == directorySection && _recentsDataSourceMode == RecentsDataSourceModeRooms && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_DIRECTORY) - && BuildSettings.allowRoomDirectoryServersChange) + && BuildSettings.publicRoomsAllowServerChange) { if (!directorySectionContainer) { diff --git a/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewModel.swift b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewModel.swift index 8e362d736..1c7418133 100644 --- a/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewModel.swift +++ b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewModel.swift @@ -94,4 +94,14 @@ import Foundation self.viewDelegate?.bubbleReactionsViewModel(self, didUpdateViewState: .loaded(reactionsViewData: reactionsViewData, showAllButtonState: showAllButtonState)) } + + // MARK: - Hashable + + override var hash: Int { + var hasher = Hasher() + hasher.combine(self.aggregatedReactions) + hasher.combine(self.eventId) + hasher.combine(self.showAll) + return hasher.finalize() + } } diff --git a/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewModelBuilder.swift b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewModelBuilder.swift new file mode 100644 index 000000000..46b244e06 --- /dev/null +++ b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewModelBuilder.swift @@ -0,0 +1,60 @@ +/* +Copyright 2020 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation + +/// `BubbleReactionsViewModelBuilder` enables to build a BubbleReactionsViewModel for a given `RoomBubbleCellData` and `MXKRoomBubbleComponent` index. +@objcMembers +final class BubbleReactionsViewModelBuilder: NSObject { + + func buildForFirstVisibleComponent(of roomBubbleCellData: RoomBubbleCellData) -> BubbleReactionsViewModel? { + + guard roomBubbleCellData.firstVisibleComponentIndex() != NSNotFound else { + return nil + } + + return self.build(from: roomBubbleCellData, componentIndex: roomBubbleCellData.firstVisibleComponentIndex()) + } + + func build(from roomBubbleCellData: RoomBubbleCellData, componentIndex: Int) -> BubbleReactionsViewModel? { + + let isCollapsableCellCollapsed = roomBubbleCellData.collapsable && roomBubbleCellData.collapsed + + guard isCollapsableCellCollapsed == false else { + return nil + } + + guard let bubbleComponents = roomBubbleCellData.bubbleComponents, componentIndex < roomBubbleCellData.bubbleComponents.count else { + return nil + } + + let bubbleComponent: MXKRoomBubbleComponent = bubbleComponents[componentIndex] + + guard let bubbleComponentEvent = bubbleComponent.event, + bubbleComponentEvent.isRedactedEvent() == false, + let componentEventId = bubbleComponentEvent.eventId, + let cellDataReactions = roomBubbleCellData.reactions, + let componentReactions = cellDataReactions[componentEventId] as? MXAggregatedReactions, + let aggregatedReactions = componentReactions.withNonZeroCount() else { + return nil + } + + let showAllReactions = roomBubbleCellData.showAllReactions(forEvent: componentEventId) + return BubbleReactionsViewModel(aggregatedReactions: aggregatedReactions, + eventId: componentEventId, + showAll: showAllReactions) + } +} diff --git a/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewSizer.h b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewSizer.h new file mode 100644 index 000000000..5234e4ba2 --- /dev/null +++ b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewSizer.h @@ -0,0 +1,33 @@ +/* +Copyright 2020 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#import +#import + +@class BubbleReactionsViewModel; + +NS_ASSUME_NONNULL_BEGIN + +// `BubbleReactionsViewSizer` allows to determine reactions view height for a given viewModel and width. +@interface BubbleReactionsViewSizer : NSObject + +// Use Objective-C as workaround as there is an issue affecting UICollectionView sizing. See https://developer.apple.com/forums/thread/105523 for more information. +- (CGFloat)heightForViewModel:(BubbleReactionsViewModel*)viewModel + fittingWidth:(CGFloat)fittingWidth; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewSizer.m b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewSizer.m new file mode 100644 index 000000000..21caa32e5 --- /dev/null +++ b/Riot/Modules/Room/BubbleReactions/BubbleReactionsViewSizer.m @@ -0,0 +1,46 @@ +/* +Copyright 2020 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#import "BubbleReactionsViewSizer.h" +#import + +#import "Riot-Swift.h" + +@implementation BubbleReactionsViewSizer + +- (CGFloat)heightForViewModel:(BubbleReactionsViewModel*)viewModel + fittingWidth:(CGFloat)fittingWidth +{ + + CGSize fittingSize = UILayoutFittingCompressedSize; + fittingSize.width = fittingWidth; + + static BubbleReactionsView *bubbleReactionsView; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bubbleReactionsView = [BubbleReactionsView new]; + }); + + bubbleReactionsView.frame = CGRectMake(0, 0, fittingWidth, 1.0); + bubbleReactionsView.viewModel = viewModel; + [bubbleReactionsView setNeedsLayout]; + [bubbleReactionsView layoutIfNeeded]; + + return [bubbleReactionsView systemLayoutSizeFittingSize:fittingSize withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel].height; +} + +@end diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index af30837de..0d0b599f5 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -21,6 +21,7 @@ #import "AvatarGenerator.h" #import "Tools.h" +#import "BubbleReactionsViewSizer.h" #import "Riot-Swift.h" @@ -406,42 +407,16 @@ static NSAttributedString *timestampVerticalWhitespace = nil; - (void)addVerticalWhitespaceToString:(NSMutableAttributedString *)attributedString forEvent:(NSString *)eventId { - // Add vertical whitespace in case of read receipts. - NSUInteger reactionCount = self.reactions[eventId].reactions.count; + CGFloat additionalVerticalHeight = 0; - MXAggregatedReactions *aggregatedReactions = self.reactions[eventId]; - - if (reactionCount) - { - CGFloat bubbleReactionsViewWidth = self.maxTextViewWidth - 4; - - CGSize fittingSize = UILayoutFittingCompressedSize; - fittingSize.width = bubbleReactionsViewWidth; - - static BubbleReactionsView *bubbleReactionsView; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - bubbleReactionsView = [BubbleReactionsView new]; - }); - - BOOL showAllReactions = [self.eventsToShowAllReactions containsObject:eventId]; - - bubbleReactionsView.frame = CGRectMake(0, 0, bubbleReactionsViewWidth, 1.0); - BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId showAll:showAllReactions]; - bubbleReactionsView.viewModel = viemModel; - [bubbleReactionsView setNeedsLayout]; - [bubbleReactionsView layoutIfNeeded]; - - CGFloat height = [bubbleReactionsView systemLayoutSizeFittingSize:fittingSize].height + RoomBubbleCellLayout.reactionsViewTopMargin; - - [attributedString appendAttributedString:[RoomBubbleCellData verticalWhitespaceForHeight: height]]; - } - + // Add vertical whitespace in case of reactions. + additionalVerticalHeight+= [self reactionHeightForEventId:eventId]; // Add vertical whitespace in case of read receipts. - if (self.readReceipts[eventId].count) + additionalVerticalHeight+= [self readReceiptHeightForEventId:eventId]; + + if (additionalVerticalHeight) { - [attributedString appendAttributedString:[RoomBubbleCellData verticalWhitespaceForHeight:RoomBubbleCellLayout.readReceiptsViewHeight + RoomBubbleCellLayout.readReceiptsViewTopMargin]]; + [attributedString appendAttributedString:[RoomBubbleCellData verticalWhitespaceForHeight: additionalVerticalHeight]]; } } @@ -504,25 +479,16 @@ static NSAttributedString *timestampVerticalWhitespace = nil; { CGFloat bubbleReactionsViewWidth = self.maxTextViewWidth - 4; - CGSize fittingSize = UILayoutFittingCompressedSize; - fittingSize.width = bubbleReactionsViewWidth; - - static BubbleReactionsView *bubbleReactionsView; + static BubbleReactionsViewSizer *bubbleReactionsViewSizer; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - bubbleReactionsView = [BubbleReactionsView new]; + bubbleReactionsViewSizer = [BubbleReactionsViewSizer new]; }); BOOL showAllReactions = [self.eventsToShowAllReactions containsObject:eventId]; - - bubbleReactionsView.frame = CGRectMake(0, 0, bubbleReactionsViewWidth, 1.0); BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId showAll:showAllReactions]; - bubbleReactionsView.viewModel = viemModel; - [bubbleReactionsView setNeedsLayout]; - [bubbleReactionsView layoutIfNeeded]; - - height = [bubbleReactionsView systemLayoutSizeFittingSize:fittingSize].height + RoomBubbleCellLayout.reactionsViewTopMargin; + height = [bubbleReactionsViewSizer heightForViewModel:viemModel fittingWidth:bubbleReactionsViewWidth] + RoomBubbleCellLayout.reactionsViewTopMargin; } return height; diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 72d78deff..bcf8fa536 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -316,7 +316,7 @@ BubbleReactionsView *reactionsView; if (!component.event.isRedactedEvent && reactions && !isCollapsableCellCollapsed) - { + { BOOL showAllReactions = [cellData showAllReactionsForEvent:componentEventId]; BubbleReactionsViewModel *bubbleReactionsViewModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:reactions eventId:componentEventId @@ -326,12 +326,9 @@ reactionsView.viewModel = bubbleReactionsViewModel; [reactionsView updateWithTheme:ThemeService.shared.theme]; - [temporaryViews addObject:reactionsView]; - bubbleReactionsViewModel.viewModelDelegate = self; - reactionsView.translatesAutoresizingMaskIntoConstraints = NO; - [bubbleCell.contentView addSubview:reactionsView]; + [temporaryViews addObject:reactionsView]; if (!bubbleCell.tmpSubviews) { @@ -339,23 +336,34 @@ } [bubbleCell.tmpSubviews addObject:reactionsView]; - CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin; - - if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge) + if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReactionsDisplayable)]) { - leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin; + id reactionsDisplayable = (id)bubbleCell; + [reactionsDisplayable addReactionsView:reactionsView]; + } + else + { + reactionsView.translatesAutoresizingMaskIntoConstraints = NO; + [bubbleCell.contentView addSubview:reactionsView]; + + CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin; + + if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge) + { + leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin; + } + + // Force receipts container size + [NSLayoutConstraint activateConstraints: + @[ + [reactionsView.leadingAnchor constraintEqualToAnchor:reactionsView.superview.leadingAnchor constant:leftMargin], + [reactionsView.trailingAnchor constraintEqualToAnchor:reactionsView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin], + [reactionsView.topAnchor constraintEqualToAnchor:reactionsView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.reactionsViewTopMargin] + ]]; } - - // Force receipts container size - [NSLayoutConstraint activateConstraints: - @[ - [reactionsView.leadingAnchor constraintEqualToAnchor:reactionsView.superview.leadingAnchor constant:leftMargin], - [reactionsView.trailingAnchor constraintEqualToAnchor:reactionsView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin], - [reactionsView.topAnchor constraintEqualToAnchor:reactionsView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.reactionsViewTopMargin] - ]]; } - MXKReceiptSendersContainer* avatarsContainer; + MXKReceiptSendersContainer* avatarsContainer; // Handle read receipts (if any) if (self.showBubbleReceipts && cellData.readReceipts.count && !isCollapsableCellCollapsed) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index e58d36c19..d65b87561 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -2578,7 +2578,7 @@ }]]; - if (BuildSettings.allowMessageDetailsShare) + if (BuildSettings.messageDetailsAllowShare) { [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_share", @"Vector", nil) style:UIAlertActionStyleDefault @@ -2691,7 +2691,7 @@ if (attachment.type != MXKAttachmentTypeSticker) { - if (BuildSettings.allowMessageDetailsShare) + if (BuildSettings.messageDetailsAllowShare) { [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_share", @"Vector", nil) style:UIAlertActionStyleDefault @@ -2802,7 +2802,7 @@ }]]; } - if (BuildSettings.allowMessageDetailsPermalink) + if (BuildSettings.messageDetailsAllowPermalink) { [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_permalink", @"Vector", nil) style:UIAlertActionStyleDefault @@ -2844,7 +2844,7 @@ }]]; } - if (BuildSettings.allowMessageDetailsViewSource) + if (BuildSettings.messageDetailsAllowViewSource) { [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_event_action_view_source", @"Vector", nil) style:UIAlertActionStyleDefault diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BaseBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BaseBubbleCell.swift new file mode 100644 index 000000000..51b47e9a3 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BaseBubbleCell.swift @@ -0,0 +1,283 @@ +/* +Copyright 2020 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import UIKit +import MatrixKit + +@objc protocol BaseBubbleCellType: Themable { + var bubbleCellContentView: BubbleCellContentView? { get } +} + +/// `BaseBubbleCell` allows a bubble cell that inherits from this class to embed and manage the default room message outer views and add an inner content view. +@objcMembers +class BaseBubbleCell: MXKRoomBubbleTableViewCell, BaseBubbleCellType { + + // MARK: - Constants + + // MARK: - Properties + + private var areViewsSetup: Bool = false + + // MARK: Public + + weak var bubbleCellContentView: BubbleCellContentView? + + // Overrides + + override var bubbleInfoContainer: UIView! { + get { + guard let infoContainer = self.bubbleCellContentView?.bubbleInfoContainer else { + fatalError("[BaseBubbleCell] bubbleInfoContainer should not be used before set") + } + return infoContainer + } + set { + super.bubbleInfoContainer = newValue + } + } + + override var bubbleOverlayContainer: UIView! { + get { + guard let overlayContainer = self.bubbleCellContentView?.bubbleOverlayContainer else { + fatalError("[BaseBubbleCell] bubbleOverlayContainer should not be used before set") + } + return overlayContainer + } + set { + super.bubbleInfoContainer = newValue + } + } + + override var bubbleInfoContainerTopConstraint: NSLayoutConstraint! { + get { + guard let infoContainerTopConstraint = self.bubbleCellContentView?.bubbleInfoContainerTopConstraint else { + fatalError("[BaseBubbleCell] bubbleInfoContainerTopConstraint should not be used before set") + } + return infoContainerTopConstraint + } + set { + super.bubbleInfoContainerTopConstraint = newValue + } + } + + override var pictureView: MXKImageView! { + get { + guard let bubbleCellContentView = self.bubbleCellContentView, + bubbleCellContentView.showSenderInfo else { + return nil + } + + guard let pictureView = self.bubbleCellContentView?.avatarImageView else { + fatalError("[BaseBubbleCell] pictureView should not be used before set") + } + return pictureView + } + set { + super.pictureView = newValue + } + } + + override var userNameLabel: UILabel! { + get { + guard let bubbleCellContentView = self.bubbleCellContentView, + bubbleCellContentView.showSenderInfo else { + return nil + } + + guard let userNameLabel = bubbleCellContentView.userNameLabel else { + fatalError("[BaseBubbleCell] userNameLabel should not be used before set") + } + return userNameLabel + } + set { + super.userNameLabel = newValue + } + } + + override var userNameTapGestureMaskView: UIView! { + get { + guard let bubbleCellContentView = self.bubbleCellContentView, + bubbleCellContentView.showSenderInfo else { + return nil + } + + guard let userNameTapGestureMaskView = self.bubbleCellContentView?.userNameTouchMaskView else { + fatalError("[BaseBubbleCell] userNameTapGestureMaskView should not be used before set") + } + return userNameTapGestureMaskView + } + set { + super.userNameTapGestureMaskView = newValue + } + } + + // MARK: - Setup + + required override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + private func commonInit() { + self.selectionStyle = .none + self.setupContentView() + self.update(theme: ThemeService.shared().theme) + } + + // MARK: - Public + + // MARK: - Overrides + + override func setupViews() { + super.setupViews() + + let showEncryptionStatus = bubbleCellContentView?.showEncryptionStatus ?? false + + if showEncryptionStatus { + self.setupEncryptionStatusViewTapGestureRecognizer() + } + } + + override class func defaultReuseIdentifier() -> String! { + return String(describing: self) + } + + override func didEndDisplay() { + super.didEndDisplay() + + if let bubbleCellReadReceiptsDisplayable = self as? BubbleCellReadReceiptsDisplayable { + bubbleCellReadReceiptsDisplayable.removeReadReceiptsView() + } + + if let bubbleCellReactionsDisplayable = self as? BubbleCellReactionsDisplayable { + bubbleCellReactionsDisplayable.removeReactionsView() + } + } + + override func render(_ cellData: MXKCellData!) { + // In `MXKRoomBubbleTableViewCell` setupViews() is called in awakeFromNib() that is not called here, so call it only on first render() call + self.setupViewsIfNeeded() + + super.render(cellData) + + guard let bubbleCellContentView = self.bubbleCellContentView else { + return + } + + if let bubbleData = self.bubbleData, + let paginationDate = bubbleData.date, + bubbleCellContentView.showPaginationTitle { + bubbleCellContentView.paginationLabel.text = bubbleData.eventFormatter.dateString(from: paginationDate, withTime: false)?.uppercased() + } + + if bubbleCellContentView.showEncryptionStatus { + self.updateEncryptionStatusViewImage() + } + + self.updateUserNameColor() + } + + override func customizeRendering() { + super.customizeRendering() + self.updateUserNameColor() + } + + // MARK: - Themable + + func update(theme: Theme) { + self.bubbleCellContentView?.update(theme: theme) + } + + // MARK: - Private + + private func setupViewsIfNeeded() { + guard self.areViewsSetup == false else { + return + } + self.setupViews() + self.areViewsSetup = true + } + + private func setupContentView() { + guard self.bubbleCellContentView == nil else { + return + } + let bubbleCellContentView = BubbleCellContentView.instantiate() + self.contentView.vc_addSubViewMatchingParent(bubbleCellContentView) + self.bubbleCellContentView = bubbleCellContentView + } + + // MARK: - BubbleCellReadReceiptsDisplayable + // Cannot use default implementation with ObjC protocol, if self conforms to BubbleCellReadReceiptsDisplayable method below will be used + + func addReadReceiptsView(_ readReceiptsView: UIView) { + self.bubbleCellContentView?.addReadReceiptsView(readReceiptsView) + } + + func removeReadReceiptsView() { + self.bubbleCellContentView?.removeReadReceiptsView() + } + + // MARK: - BubbleCellReactionsDisplayable + // Cannot use default implementation with ObjC protocol, if self conforms to BubbleCellReactionsDisplayable method below will be used + + func addReactionsView(_ reactionsView: UIView) { + self.bubbleCellContentView?.addReactionsView(reactionsView) + } + + func removeReactionsView() { + self.bubbleCellContentView?.removeReactionsView() + } + + // Encryption status + + private func updateEncryptionStatusViewImage() { + guard let component = self.bubbleData.getFirstBubbleComponentWithDisplay() else { + return + } + self.bubbleCellContentView?.encryptionImageView.image = RoomEncryptedDataBubbleCell.encryptionIcon(for: component) + } + + private func setupEncryptionStatusViewTapGestureRecognizer() { + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleEncryptionStatusContainerViewTap(_:))) + tapGestureRecognizer.delegate = self + self.bubbleCellContentView?.encryptionImageView.isUserInteractionEnabled = true + } + + @objc private func handleEncryptionStatusContainerViewTap(_ gestureRecognizer: UITapGestureRecognizer) { + guard let delegate = self.delegate else { + return + } + + guard let component = self.bubbleData.getFirstBubbleComponentWithDisplay() else { + return + } + + let userInfo: [AnyHashable: Any]? + + if let tappedEvent = component.event { + userInfo = [kMXKRoomBubbleCellEventKey: tappedEvent] + } else { + userInfo = nil + } + + delegate.cell(self, didRecognizeAction: kRoomEncryptedDataBubbleCellTapOnEncryptionIcon, userInfo: userInfo) + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.swift b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.swift similarity index 59% rename from Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.swift rename to Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.swift index 158df123c..22597a4f2 100644 --- a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.swift +++ b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.swift @@ -17,6 +17,7 @@ import UIKit import Reusable +/// `BubbleCellContentView` is a container view that display the default room message outer views and enables to manage them. Like pagination title, sender info, read receipts, reactions, encryption status. @objcMembers final class BubbleCellContentView: UIView, NibLoadable { @@ -24,19 +25,30 @@ final class BubbleCellContentView: UIView, NibLoadable { // MARK: Outlets - @IBOutlet weak var bubbleInfoContainer: UIView! - @IBOutlet weak var bubbleInfoContainerTopConstraint: NSLayoutConstraint! + @IBOutlet weak var paginationTitleContainerView: UIView! + @IBOutlet weak var paginationLabel: UILabel! + @IBOutlet weak var paginationSeparatorView: UIView! + + @IBOutlet weak var senderInfoContainerView: UIView! + @IBOutlet weak var avatarImageView: MXKImageView! + @IBOutlet weak var userNameLabel: UILabel! + @IBOutlet weak var userNameTouchMaskView: UIView! @IBOutlet weak var innerContentView: UIView! + @IBOutlet weak var encryptionStatusContainerView: UIView! + @IBOutlet weak var encryptionImageView: UIImageView! + + @IBOutlet weak var bubbleInfoContainer: UIView! + @IBOutlet weak var bubbleInfoContainerTopConstraint: NSLayoutConstraint! + @IBOutlet weak var readReceiptsContainerView: UIView! @IBOutlet weak var readReceiptsContentView: UIView! - @IBOutlet weak var bubbleOverlayContainer: UIView! + @IBOutlet weak var reactionsContainerView: UIView! + @IBOutlet weak var reactionsContentView: UIView! - @IBOutlet weak var paginationTitleContainerView: UIView! - @IBOutlet weak var paginationLabel: UILabel! - @IBOutlet weak var paginationSeparatorView: UIView! + @IBOutlet weak var bubbleOverlayContainer: UIView! // MARK: Private @@ -49,6 +61,15 @@ final class BubbleCellContentView: UIView, NibLoadable { } } + private var showReactions: Bool { + get { + return !self.reactionsContainerView.isHidden + } + set { + self.reactionsContainerView.isHidden = !newValue + } + } + // MARK: Public var showPaginationTitle: Bool { @@ -56,7 +77,25 @@ final class BubbleCellContentView: UIView, NibLoadable { return !self.paginationTitleContainerView.isHidden } set { - self.paginationTitleContainerView.isHidden = !newValue + self.paginationTitleContainerView.isHidden = !newValue + } + } + + var showSenderInfo: Bool { + get { + return !self.senderInfoContainerView.isHidden + } + set { + self.senderInfoContainerView.isHidden = !newValue + } + } + + var showEncryptionStatus: Bool { + get { + return !self.encryptionStatusContainerView.isHidden + } + set { + self.encryptionStatusContainerView.isHidden = !newValue } } @@ -89,3 +128,18 @@ extension BubbleCellContentView: BubbleCellReadReceiptsDisplayable { self.readReceiptsContentView.vc_removeAllSubviews() } } + +// MARK: - BubbleCellReactionsDisplayable +extension BubbleCellContentView: BubbleCellReactionsDisplayable { + + func addReactionsView(_ reactionsView: UIView) { + self.reactionsContentView.vc_removeAllSubviews() + self.reactionsContentView.vc_addSubViewMatchingParent(reactionsView) + self.showReactions = true + } + + func removeReactionsView() { + self.showReactions = false + self.reactionsContentView.vc_removeAllSubviews() + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.xib b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.xib similarity index 51% rename from Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.xib rename to Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.xib index 774a36c25..47244effb 100644 --- a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellContentView.xib +++ b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.xib @@ -1,11 +1,9 @@ - - - - + + - + @@ -22,14 +20,14 @@ - @@ -132,17 +225,28 @@ + + + + + + + + - + + + + diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellReactionsDisplayable.swift b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellReactionsDisplayable.swift new file mode 100644 index 000000000..91eb3de41 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellReactionsDisplayable.swift @@ -0,0 +1,23 @@ +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +/// `BubbleCellReactionsDisplayable` is a protocol indicating that a cell support displaying reactions. +@objc protocol BubbleCellReactionsDisplayable { + func addReactionsView(_ reactionsView: UIView) + func removeReactionsView() +} diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellReadReceiptsDisplayable.swift b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellReadReceiptsDisplayable.swift similarity index 86% rename from Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellReadReceiptsDisplayable.swift rename to Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellReadReceiptsDisplayable.swift index e9b657a03..4184944fd 100644 --- a/Riot/Modules/Room/Views/BubbleCells/BaseContentViews/BubbleCellReadReceiptsDisplayable.swift +++ b/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellReadReceiptsDisplayable.swift @@ -16,6 +16,7 @@ import Foundation +/// `BubbleCellReadReceiptsDisplayable` is a protocol indicating that a cell support displaying read receipts. @objc protocol BubbleCellReadReceiptsDisplayable { func addReadReceiptsView(_ readReceiptsView: UIView) func removeReadReceiptsView() diff --git a/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizableBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizableBubbleCell.swift new file mode 100644 index 000000000..d7f00f0d7 --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizableBubbleCell.swift @@ -0,0 +1,136 @@ +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +@objc protocol SizableBaseBubbleCellType: BaseBubbleCellType { + static func sizingViewHeightHashValue(from bubbleCellData: MXKRoomBubbleCellData) -> Int +} + +/// `SizableBaseBubbleCell` allows a cell using Auto Layout that inherits from this class to automatically return the height of the cell and cache the result. +@objcMembers +class SizableBaseBubbleCell: BaseBubbleCell, SizableBaseBubbleCellType { + + // MARK: - Constants + + private static let sizingViewHeightStore = SizingViewHeightStore() + private static var sizingViews: [String: SizableBaseBubbleCell] = [:] + private static let sizingReactionsView = BubbleReactionsView() + + private static let reactionsViewSizer = BubbleReactionsViewSizer() + private static let reactionsViewModelBuilder = BubbleReactionsViewModelBuilder() + + private class var sizingView: SizableBaseBubbleCell { + let sizingView: SizableBaseBubbleCell + + let reuseIdentifier: String = self.defaultReuseIdentifier() + + if let cachedSizingView = self.sizingViews[reuseIdentifier] { + sizingView = cachedSizingView + } else { + sizingView = self.createSizingView() + self.sizingViews[reuseIdentifier] = sizingView + } + return sizingView + } + + // MARK: - Overrides + + override class func height(for cellData: MXKCellData!, withMaximumWidth maxWidth: CGFloat) -> CGFloat { + guard let cellData = cellData else { + return 0 + } + + guard let roomBubbleCellData = cellData as? MXKRoomBubbleCellData else { + return 0 + } + + return self.height(for: roomBubbleCellData, fitting: maxWidth) + } + + // MARK - SizableBaseBubbleCellType + + // Each sublcass should override this method, to indicate a unique identifier for a view height. + // This means that the value should change if there is some data that modify the cell height. + class func sizingViewHeightHashValue(from bubbleCellData: MXKRoomBubbleCellData) -> Int { + // TODO: Improve default hash value computation: + // - Implement RoomBubbleCellData hash + // - Handle reactions + return bubbleCellData.hashValue + } + + // MARK: - Private + + class func createSizingView() -> SizableBaseBubbleCell { + return self.init(style: .default, reuseIdentifier: self.defaultReuseIdentifier()) + } + + private class func height(for roomBubbleCellData: MXKRoomBubbleCellData, fitting width: CGFloat) -> CGFloat { + // FIXME: Size cache is disabled for the moment waiting for a better default `sizingViewHeightHashValue` implementation. + +// let height: CGFloat +// +// let sizingViewHeight = self.findOrCreateSizingViewHeight(from: roomBubbleCellData) +// +// if let cachedHeight = sizingViewHeight.heights[width] { +// height = cachedHeight +// } else { +// height = self.contentViewHeight(for: roomBubbleCellData, fitting: width) +// sizingViewHeight.heights[width] = height +// } +// +// return height + + return self.contentViewHeight(for: roomBubbleCellData, fitting: width) + } + + private static func findOrCreateSizingViewHeight(from bubbleData: MXKRoomBubbleCellData) -> SizingViewHeight { + let bubbleDataHashValue = self.sizingViewHeightHashValue(from: bubbleData) + return self.sizingViewHeightStore.findOrCreateSizingViewHeight(from: bubbleDataHashValue) + } + + private static func contentViewHeight(for cellData: MXKCellData, fitting width: CGFloat) -> CGFloat { + let sizingView = self.sizingView + + sizingView.didEndDisplay() + + sizingView.render(cellData) + + sizingView.setNeedsLayout() + sizingView.layoutIfNeeded() + + let fittingSize = CGSize(width: width, height: UIView.layoutFittingCompressedSize.height) + var height = sizingView.systemLayoutSizeFitting(fittingSize).height + + // Add read receipt height if needed + if let roomBubbleCellData = cellData as? RoomBubbleCellData, let readReceipts = roomBubbleCellData.readReceipts, readReceipts.count > 0, sizingView is BubbleCellReadReceiptsDisplayable { + height+=RoomBubbleCellLayout.readReceiptsViewHeight + } + + // Add reactions view height if needed + if sizingView is BubbleCellReactionsDisplayable, + let roomBubbleCellData = cellData as? RoomBubbleCellData, + let bubbleReactionsViewModel = self.reactionsViewModelBuilder.buildForFirstVisibleComponent(of: roomBubbleCellData) { + + let reactionWidth = sizingView.bubbleCellContentView?.reactionsContentView.frame.width ?? roomBubbleCellData.maxTextViewWidth + + let reactionsHeight = self.reactionsViewSizer.height(for: bubbleReactionsViewModel, fittingWidth: reactionWidth) + height+=reactionsHeight + } + + return height + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/SizingViewHeight.swift b/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizingViewHeight.swift similarity index 79% rename from Riot/Modules/Room/Views/BubbleCells/KeyVerification/SizingViewHeight.swift rename to Riot/Modules/Room/Views/BubbleCells/SizableCell/SizingViewHeight.swift index f1607fb4f..ba213d58d 100644 --- a/Riot/Modules/Room/Views/BubbleCells/KeyVerification/SizingViewHeight.swift +++ b/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizingViewHeight.swift @@ -16,13 +16,18 @@ import Foundation -final class SizingViewHeight: Hashable, Equatable { +/// `SizingViewHeight` allows to associate a height for a given width to a unique value. +final class SizingViewHeight: Hashable, Equatable, CustomStringConvertible { // MARK: - Properties let uniqueIdentifier: Int var heights: [CGFloat /* width */: CGFloat /* height */] = [:] + var description: String { + return "<\(type(of: self))> uniqueIdentifier: \(uniqueIdentifier) - heights: \(heights)" + } + // MARK: - Setup init(uniqueIdentifier: Int) { diff --git a/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizingViewHeightStore.swift b/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizingViewHeightStore.swift new file mode 100644 index 000000000..e015a4ebc --- /dev/null +++ b/Riot/Modules/Room/Views/BubbleCells/SizableCell/SizingViewHeightStore.swift @@ -0,0 +1,39 @@ +/* +Copyright 2020 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation + +/// `SizingViewHeightStore` allows to store `SizingViewHeight` for a given hash value +final class SizingViewHeightStore { + + private var sizes = Set() + + func findOrCreateSizingViewHeight(from viewHeightHashValue: Int) -> SizingViewHeight { + + let sizingViewHeight: SizingViewHeight + + if let foundSizingViewHeight = self.sizes.first(where: { (sizingViewHeight) -> Bool in + return sizingViewHeight.uniqueIdentifier == viewHeightHashValue + }) { + sizingViewHeight = foundSizingViewHeight + } else { + sizingViewHeight = SizingViewHeight(uniqueIdentifier: viewHeightHashValue) + self.sizes.insert(sizingViewHeight) + } + + return sizingViewHeight + } +} diff --git a/Riot/Modules/Rooms/RoomsViewController.m b/Riot/Modules/Rooms/RoomsViewController.m index ff7cb5175..23195cafe 100644 --- a/Riot/Modules/Rooms/RoomsViewController.m +++ b/Riot/Modules/Rooms/RoomsViewController.m @@ -156,7 +156,7 @@ [directoryServersDataSource finalizeInitialization]; // Add directory servers from the app settings - directoryServersDataSource.roomDirectoryServers = BuildSettings.roomDirectoryServers; + directoryServersDataSource.roomDirectoryServers = BuildSettings.publicRoomsDirectoryServers; __weak typeof(self) weakSelf = self; diff --git a/Riot/Modules/SetPinCode/PinCodePreferences.swift b/Riot/Modules/SetPinCode/PinCodePreferences.swift index 4b3768bfb..32015b077 100644 --- a/Riot/Modules/SetPinCode/PinCodePreferences.swift +++ b/Riot/Modules/SetPinCode/PinCodePreferences.swift @@ -25,7 +25,7 @@ final class PinCodePreferences: NSObject { // MARK: - Constants private struct PinConstants { - static let pinCodeKeychainService: String = "im.vector.app.pin-service" + static let pinCodeKeychainService: String = BuildSettings.baseBundleIdentifier + ".pin-service" } private struct StoreKeys { @@ -40,7 +40,7 @@ final class PinCodePreferences: NSObject { override init() { store = KeychainStore(withKeychain: Keychain(service: PinConstants.pinCodeKeychainService, - accessGroup: Constants.keychainAccessGroup)) + accessGroup: BuildSettings.keychainAccessGroup)) super.init() } diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index 49d0c0d16..3b9157c9b 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -291,11 +291,11 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate> [sectionUserSettings addRowWithTag:USER_SETTINGS_PROFILE_PICTURE_INDEX]; [sectionUserSettings addRowWithTag:USER_SETTINGS_DISPLAYNAME_INDEX]; [sectionUserSettings addRowWithTag:USER_SETTINGS_CHANGE_PASSWORD_INDEX]; - if (BuildSettings.showUserFirstNameInSettings) + if (BuildSettings.settingsScreenShowUserFirstName) { [sectionUserSettings addRowWithTag:USER_SETTINGS_FIRST_NAME_INDEX]; } - if (BuildSettings.showUserSurnameInSettings) + if (BuildSettings.settingsScreenShowUserSurname) { [sectionUserSettings addRowWithTag:USER_SETTINGS_SURNAME_INDEX]; } @@ -310,15 +310,15 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate> { [sectionUserSettings addRowWithTag: USER_SETTINGS_PHONENUMBERS_OFFSET + index]; } - if (BuildSettings.allowAddingEmailThreepids) + if (BuildSettings.settingsScreenAllowAddingEmailThreepids) { [sectionUserSettings addRowWithTag:USER_SETTINGS_ADD_EMAIL_INDEX]; } - if (BuildSettings.allowAddingPhoneThreepids) + if (BuildSettings.settingsScreenAllowAddingPhoneThreepids) { [sectionUserSettings addRowWithTag:USER_SETTINGS_ADD_PHONENUMBER_INDEX]; } - if (BuildSettings.showThreepidExplanatory) + if (BuildSettings.settingsScreenShowThreepidExplanatory) { [sectionUserSettings addRowWithTag:USER_SETTINGS_THREEPIDS_INFORMATION_INDEX]; } @@ -348,7 +348,7 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate> [tmpSections addObject:sectionCalls]; } - if (BuildSettings.showDiscoverySettings) + if (BuildSettings.settingsScreenShowDiscoverySettings) { Section *sectionDiscovery = [Section sectionWithTag:SECTION_TAG_DISCOVERY]; NSInteger count = self.settingsDiscoveryTableViewSection.numberOfRows; @@ -360,7 +360,7 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate> [tmpSections addObject:sectionDiscovery]; } - if (BuildSettings.allowIdentityServerConfig) + if (BuildSettings.settingsScreenAllowIdentityServerConfig) { Section *sectionIdentityServer = [Section sectionWithTag:SECTION_TAG_IDENTITY_SERVER]; [sectionIdentityServer addRowWithTag:IDENTITY_SERVER_INDEX]; @@ -408,7 +408,7 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate> sectionUserInterface.headerTitle = NSLocalizedStringFromTable(@"settings_user_interface", @"Vector", nil); [tmpSections addObject: sectionUserInterface]; - if (BuildSettings.showAdvancedSettings) + if (BuildSettings.settingsScreenShowAdvancedSettings) { Section *sectionAdvanced = [Section sectionWithTag:SECTION_TAG_ADVANCED]; [sectionAdvanced addRowWithTag:0]; @@ -423,24 +423,24 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate> [sectionOther addRowWithTag:OTHER_TERM_CONDITIONS_INDEX]; [sectionOther addRowWithTag:OTHER_PRIVACY_INDEX]; [sectionOther addRowWithTag:OTHER_THIRD_PARTY_INDEX]; - if (BuildSettings.allowChangingCrashUsageDataSettings) + if (BuildSettings.settingsScreenAllowChangingCrashUsageDataSettings) { [sectionOther addRowWithTag:OTHER_CRASH_REPORT_INDEX]; } - if (BuildSettings.allowChangingRageshakeSettings) + if (BuildSettings.settingsScreenAllowChangingRageshakeSettings) { [sectionOther addRowWithTag:OTHER_ENABLE_RAGESHAKE_INDEX]; } [sectionOther addRowWithTag:OTHER_MARK_ALL_AS_READ_INDEX]; [sectionOther addRowWithTag:OTHER_CLEAR_CACHE_INDEX]; - if (BuildSettings.allowBugReportingManually) + if (BuildSettings.settingsScreenAllowBugReportingManually) { [sectionOther addRowWithTag:OTHER_REPORT_BUG_INDEX]; } sectionOther.headerTitle = NSLocalizedStringFromTable(@"settings_other", @"Vector", nil); [tmpSections addObject:sectionOther]; - if (BuildSettings.showLabSettings) + if (BuildSettings.settingsScreenShowLabSettings) { Section *sectionLabs = [Section sectionWithTag:SECTION_TAG_LABS]; [sectionLabs addRowWithTag:LABS_USE_JITSI_WIDGET_INDEX]; @@ -461,7 +461,7 @@ SettingsIdentityServerCoordinatorBridgePresenterDelegate> [tmpSections addObject:sectionFlair]; } - if (BuildSettings.allowDeactivatingAccount) + if (BuildSettings.settingsScreenAllowDeactivatingAccount) { Section *sectionDeactivate = [Section sectionWithTag:SECTION_TAG_DEACTIVATE_ACCOUNT]; [sectionDeactivate addRowWithTag:0]; diff --git a/Riot/SupportingFiles/Info.plist b/Riot/SupportingFiles/Info.plist index b844071b8..28fe70e96 100644 --- a/Riot/SupportingFiles/Info.plist +++ b/Riot/SupportingFiles/Info.plist @@ -91,5 +91,9 @@ ${PRODUCT_NAME}-Defaults applicationGroupIdentifier $(APPLICATION_GROUP_IDENTIFIER) + baseBundleIdentifier + $(BASE_BUNDLE_IDENTIFIER) + keychainAccessGroup + $(KEYCHAIN_ACCESS_GROUP) diff --git a/Riot/SupportingFiles/Riot-Bridging-Header.h b/Riot/SupportingFiles/Riot-Bridging-Header.h index 5aeadc7d1..3c4bdb528 100644 --- a/Riot/SupportingFiles/Riot-Bridging-Header.h +++ b/Riot/SupportingFiles/Riot-Bridging-Header.h @@ -18,3 +18,5 @@ #import "RoomBubbleCellData.h" #import "MXKRoomBubbleTableViewCell+Riot.h" #import "UserEncryptionTrustLevel.h" +#import "BubbleReactionsViewSizer.h" +#import "RoomEncryptedDataBubbleCell.h" diff --git a/Riot/SupportingFiles/Riot.entitlements b/Riot/SupportingFiles/Riot.entitlements index c99d17157..965a767d4 100644 --- a/Riot/SupportingFiles/Riot.entitlements +++ b/Riot/SupportingFiles/Riot.entitlements @@ -40,7 +40,7 @@ keychain-access-groups - $(AppIdentifierPrefix)im.vector.app.keychain.shared + $(KEYCHAIN_ACCESS_GROUP) diff --git a/Riot/Utils/Constants.swift b/Riot/Utils/Constants.swift index 97578fa0f..200c52cdd 100644 --- a/Riot/Utils/Constants.swift +++ b/Riot/Utils/Constants.swift @@ -19,6 +19,5 @@ import Foundation enum Constants { static let toBeRemovedNotificationCategoryIdentifier = "TO_BE_REMOVED" - static let keychainAccessGroup = "7J4U792NQT.im.vector.app.keychain.shared" } diff --git a/RiotNSE/RiotNSE.entitlements b/RiotNSE/RiotNSE.entitlements index caae6ed94..ced577af8 100644 --- a/RiotNSE/RiotNSE.entitlements +++ b/RiotNSE/RiotNSE.entitlements @@ -8,7 +8,7 @@ keychain-access-groups - $(AppIdentifierPrefix)im.vector.app.keychain.shared + $(KEYCHAIN_ACCESS_GROUP) diff --git a/RiotShareExtension/SupportingFiles/RiotShareExtension.entitlements b/RiotShareExtension/SupportingFiles/RiotShareExtension.entitlements index caae6ed94..ced577af8 100644 --- a/RiotShareExtension/SupportingFiles/RiotShareExtension.entitlements +++ b/RiotShareExtension/SupportingFiles/RiotShareExtension.entitlements @@ -8,7 +8,7 @@ keychain-access-groups - $(AppIdentifierPrefix)im.vector.app.keychain.shared + $(KEYCHAIN_ACCESS_GROUP) diff --git a/SiriIntents/SiriIntents.entitlements b/SiriIntents/SiriIntents.entitlements index caae6ed94..ced577af8 100644 --- a/SiriIntents/SiriIntents.entitlements +++ b/SiriIntents/SiriIntents.entitlements @@ -8,7 +8,7 @@ keychain-access-groups - $(AppIdentifierPrefix)im.vector.app.keychain.shared + $(KEYCHAIN_ACCESS_GROUP) diff --git a/Tools/Release/buildRelease.sh b/Tools/Release/buildRelease.sh index 78a4c1264..108f34453 100755 --- a/Tools/Release/buildRelease.sh +++ b/Tools/Release/buildRelease.sh @@ -37,9 +37,11 @@ bundle update # Checkout the source to build mkdir -p $BUILD_DIR cd $BUILD_DIR -git clone https://github.com/vector-im/riot-ios.git -cd riot-ios -git checkout -b $TAG $TAG +REPO_URL=$(git ls-remote --get-url origin) +git clone $REPO_URL +REPO_NAME=$(basename -s .git $REPO_URL) +cd $REPO_NAME +git checkout $TAG $TAG # Develop branch special case