From 6e278e92edf52b1d1eb985371e246b4af4e34a26 Mon Sep 17 00:00:00 2001 From: David Langley Date: Tue, 3 Jan 2023 16:52:25 +0000 Subject: [PATCH 001/160] Fix both issues as outlined in 7222 --- .../LocationSharing/LocationManager.swift | 21 +++++++++++++++---- changelog.d/7222.bugfix | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 changelog.d/7222.bugfix diff --git a/Riot/Modules/LocationSharing/LocationManager.swift b/Riot/Modules/LocationSharing/LocationManager.swift index 5fb222493b..3b41e126a5 100644 --- a/Riot/Modules/LocationSharing/LocationManager.swift +++ b/Riot/Modules/LocationSharing/LocationManager.swift @@ -43,6 +43,7 @@ class LocationManager: NSObject { private let locationManager: CLLocationManager private var authorizationHandler: LocationAuthorizationHandler? + private var authorizationReturnedSinceRequestingAlways = false // MARK: Public @@ -144,14 +145,16 @@ class LocationManager: NSObject { // See https://developer.apple.com/documentation/corelocation/cllocationmanager/1620551-requestalwaysauthorization?changes=_6_6 private func tryToRequestAlwaysAuthorization(handler: @escaping LocationAuthorizationHandler) { self.authorizationHandler = handler + self.authorizationReturnedSinceRequestingAlways = false + self.locationManager.delegate = self self.locationManager.requestAlwaysAuthorization() Timer.scheduledTimer(withTimeInterval: Constants.waitForAuthorizationStatusDelay, repeats: false) { [weak self] _ in - guard let self = self else { + guard let self = self, !self.authorizationReturnedSinceRequestingAlways else { return } - self.authorizationRequestDidComplete(with: self.locationManager.authorizationStatus) + self.authorizationAlwaysRequestDidComplete(with: self.locationManager.authorizationStatus) } } @@ -175,7 +178,10 @@ class LocationManager: NSObject { return status } - private func authorizationRequestDidComplete(with status: CLAuthorizationStatus) { + private func checkShouldCompleteAuthorizationCheck(with status: CLAuthorizationStatus) { + } + + private func authorizationAlwaysRequestDidComplete(with status: CLAuthorizationStatus) { guard let authorizationHandler = self.authorizationHandler else { return } @@ -191,7 +197,14 @@ extension LocationManager: CLLocationManagerDelegate { func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { let status = self.locationManager.authorizationStatus - self.authorizationRequestDidComplete(with: status) + authorizationReturnedSinceRequestingAlways = true + if status == .authorizedAlways { + // LocationManager can call locationManagerDidChangeAuthorization multiple times. + // For example it calls it at initialisation of LocationManager manager and we are also seeing it called + // after requestAlwaysAuthorization but before the user has actually selected on option on the prompt. + // Therefore we should only call `authorizationAlwaysRequestDidComplete` once on the success of authorizedAlways being granted. + self.authorizationAlwaysRequestDidComplete(with: status) + } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { diff --git a/changelog.d/7222.bugfix b/changelog.d/7222.bugfix new file mode 100644 index 0000000000..e1402cb0da --- /dev/null +++ b/changelog.d/7222.bugfix @@ -0,0 +1 @@ +Live Location Sharing does not work on first selection after granting "Allow always" location permission. From 16650b40841d613f818893aa90e304af286ba484 Mon Sep 17 00:00:00 2001 From: David Langley Date: Tue, 3 Jan 2023 16:54:03 +0000 Subject: [PATCH 002/160] remove unnecessary function --- Podfile | 4 +- Podfile.lock | 33 ++++++++++------- .../xcshareddata/xcschemes/Riot.xcscheme | 37 ++++++++----------- .../LocationSharing/LocationManager.swift | 3 -- 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/Podfile b/Podfile index 14443360b2..04ffe7c782 100644 --- a/Podfile +++ b/Podfile @@ -16,9 +16,9 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK 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 -$matrixSDKVersion = '= 0.24.6' +# $matrixSDKVersion = '= 0.24.6' # $matrixSDKVersion = :local -# $matrixSDKVersion = { :branch => 'develop'} +$matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } ######################################## diff --git a/Podfile.lock b/Podfile.lock index 5244de7b2c..6ef48596d6 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -55,9 +55,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.24.5): - - MatrixSDK/Core (= 0.24.5) - - MatrixSDK/Core (0.24.5): + - MatrixSDK (0.24.6): + - MatrixSDK/Core (= 0.24.6) + - MatrixSDK/Core (0.24.6): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -65,12 +65,12 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/CryptoSDK (0.24.5): - - MatrixSDKCrypto (= 0.1.5) - - MatrixSDK/JingleCallStack (0.24.5): + - MatrixSDK/CryptoSDK (0.24.6): + - MatrixSDKCrypto (= 0.1.7) + - MatrixSDK/JingleCallStack (0.24.6): - JitsiMeetSDK (= 5.0.2) - MatrixSDK/Core - - MatrixSDKCrypto (0.1.5) + - MatrixSDKCrypto (0.1.7) - OLMKit (3.2.12): - OLMKit/olmc (= 3.2.12) - OLMKit/olmcpp (= 3.2.12) @@ -122,8 +122,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.24.5) - - MatrixSDK/JingleCallStack (= 0.24.5) + - MatrixSDK (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `develop`) + - MatrixSDK/JingleCallStack (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `develop`) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -165,7 +165,6 @@ SPEC REPOS: - libPhoneNumber-iOS - LoggerAPI - Logging - - MatrixSDK - MatrixSDKCrypto - OLMKit - PostHog @@ -190,11 +189,17 @@ EXTERNAL SOURCES: AnalyticsEvents: :branch: release/swift :git: https://github.com/matrix-org/matrix-analytics-events.git + MatrixSDK: + :branch: develop + :git: https://github.com/matrix-org/matrix-ios-sdk.git CHECKOUT OPTIONS: AnalyticsEvents: :commit: 53ad46ba1ea1ee8f21139dda3c351890846a202f :git: https://github.com/matrix-org/matrix-analytics-events.git + MatrixSDK: + :commit: 8ae45d250cf0714b37aa6abdb8bffa8c2a438606 + :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce @@ -220,8 +225,8 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 1557b3ed0a211db43a865cfdad93f07c2be92c9e - MatrixSDKCrypto: dcab554bc7157cad31c01fc1137cf5acb01959a4 + MatrixSDK: 3c245333328e6ed91f7b660f4b6159e203d615d3 + MatrixSDKCrypto: 2bd9ca41b2c644839f4e680a64897d56b3f95392 OLMKit: da115f16582e47626616874e20f7bb92222c7a51 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -241,6 +246,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: c93b326deaf9de3916d42a49d39d737612ab1d94 +PODFILE CHECKSUM: 3a48e44323e1b4ff13a7ed214461c825c588dc53 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme index 012a5a109b..e1775adc47 100644 --- a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme +++ b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme @@ -1,11 +1,10 @@ + version = "1.3"> + buildImplicitDependencies = "YES"> @@ -35,11 +34,20 @@ + + + + @@ -52,17 +60,6 @@ - - - - - - - - - - diff --git a/Riot/Modules/LocationSharing/LocationManager.swift b/Riot/Modules/LocationSharing/LocationManager.swift index 3b41e126a5..ee9ddb103d 100644 --- a/Riot/Modules/LocationSharing/LocationManager.swift +++ b/Riot/Modules/LocationSharing/LocationManager.swift @@ -177,9 +177,6 @@ class LocationManager: NSObject { return status } - - private func checkShouldCompleteAuthorizationCheck(with status: CLAuthorizationStatus) { - } private func authorizationAlwaysRequestDidComplete(with status: CLAuthorizationStatus) { guard let authorizationHandler = self.authorizationHandler else { From 20dfdb1881ddc7db2f4fc9df2fa264f73bb9db99 Mon Sep 17 00:00:00 2001 From: David Langley Date: Tue, 3 Jan 2023 16:54:41 +0000 Subject: [PATCH 003/160] Revert "remove unnecessary function" This reverts commit 16650b40841d613f818893aa90e304af286ba484. --- Podfile | 4 +- Podfile.lock | 33 +++++++---------- .../xcshareddata/xcschemes/Riot.xcscheme | 37 +++++++++++-------- .../LocationSharing/LocationManager.swift | 3 ++ 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/Podfile b/Podfile index 04ffe7c782..14443360b2 100644 --- a/Podfile +++ b/Podfile @@ -16,9 +16,9 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK 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 -# $matrixSDKVersion = '= 0.24.6' +$matrixSDKVersion = '= 0.24.6' # $matrixSDKVersion = :local -$matrixSDKVersion = { :branch => 'develop'} +# $matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } ######################################## diff --git a/Podfile.lock b/Podfile.lock index 6ef48596d6..5244de7b2c 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -55,9 +55,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.24.6): - - MatrixSDK/Core (= 0.24.6) - - MatrixSDK/Core (0.24.6): + - MatrixSDK (0.24.5): + - MatrixSDK/Core (= 0.24.5) + - MatrixSDK/Core (0.24.5): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -65,12 +65,12 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/CryptoSDK (0.24.6): - - MatrixSDKCrypto (= 0.1.7) - - MatrixSDK/JingleCallStack (0.24.6): + - MatrixSDK/CryptoSDK (0.24.5): + - MatrixSDKCrypto (= 0.1.5) + - MatrixSDK/JingleCallStack (0.24.5): - JitsiMeetSDK (= 5.0.2) - MatrixSDK/Core - - MatrixSDKCrypto (0.1.7) + - MatrixSDKCrypto (0.1.5) - OLMKit (3.2.12): - OLMKit/olmc (= 3.2.12) - OLMKit/olmcpp (= 3.2.12) @@ -122,8 +122,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `develop`) - - MatrixSDK/JingleCallStack (from `https://github.com/matrix-org/matrix-ios-sdk.git`, branch `develop`) + - MatrixSDK (= 0.24.5) + - MatrixSDK/JingleCallStack (= 0.24.5) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -165,6 +165,7 @@ SPEC REPOS: - libPhoneNumber-iOS - LoggerAPI - Logging + - MatrixSDK - MatrixSDKCrypto - OLMKit - PostHog @@ -189,17 +190,11 @@ EXTERNAL SOURCES: AnalyticsEvents: :branch: release/swift :git: https://github.com/matrix-org/matrix-analytics-events.git - MatrixSDK: - :branch: develop - :git: https://github.com/matrix-org/matrix-ios-sdk.git CHECKOUT OPTIONS: AnalyticsEvents: :commit: 53ad46ba1ea1ee8f21139dda3c351890846a202f :git: https://github.com/matrix-org/matrix-analytics-events.git - MatrixSDK: - :commit: 8ae45d250cf0714b37aa6abdb8bffa8c2a438606 - :git: https://github.com/matrix-org/matrix-ios-sdk.git SPEC CHECKSUMS: AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce @@ -225,8 +220,8 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 3c245333328e6ed91f7b660f4b6159e203d615d3 - MatrixSDKCrypto: 2bd9ca41b2c644839f4e680a64897d56b3f95392 + MatrixSDK: 1557b3ed0a211db43a865cfdad93f07c2be92c9e + MatrixSDKCrypto: dcab554bc7157cad31c01fc1137cf5acb01959a4 OLMKit: da115f16582e47626616874e20f7bb92222c7a51 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -246,6 +241,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 3a48e44323e1b4ff13a7ed214461c825c588dc53 +PODFILE CHECKSUM: c93b326deaf9de3916d42a49d39d737612ab1d94 -COCOAPODS: 1.11.3 +COCOAPODS: 1.11.2 diff --git a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme index e1775adc47..012a5a109b 100644 --- a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme +++ b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme @@ -1,10 +1,11 @@ + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> @@ -34,20 +35,11 @@ - - - - @@ -60,6 +52,17 @@ + + + + + + + + + + diff --git a/Riot/Modules/LocationSharing/LocationManager.swift b/Riot/Modules/LocationSharing/LocationManager.swift index ee9ddb103d..3b41e126a5 100644 --- a/Riot/Modules/LocationSharing/LocationManager.swift +++ b/Riot/Modules/LocationSharing/LocationManager.swift @@ -177,6 +177,9 @@ class LocationManager: NSObject { return status } + + private func checkShouldCompleteAuthorizationCheck(with status: CLAuthorizationStatus) { + } private func authorizationAlwaysRequestDidComplete(with status: CLAuthorizationStatus) { guard let authorizationHandler = self.authorizationHandler else { From 16a75563b15e487b8ae78a4318d05f488a2ad8a7 Mon Sep 17 00:00:00 2001 From: David Langley Date: Tue, 3 Jan 2023 16:55:28 +0000 Subject: [PATCH 004/160] remove unnecessary function --- Riot/Modules/LocationSharing/LocationManager.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Riot/Modules/LocationSharing/LocationManager.swift b/Riot/Modules/LocationSharing/LocationManager.swift index 3b41e126a5..ee9ddb103d 100644 --- a/Riot/Modules/LocationSharing/LocationManager.swift +++ b/Riot/Modules/LocationSharing/LocationManager.swift @@ -177,9 +177,6 @@ class LocationManager: NSObject { return status } - - private func checkShouldCompleteAuthorizationCheck(with status: CLAuthorizationStatus) { - } private func authorizationAlwaysRequestDidComplete(with status: CLAuthorizationStatus) { guard let authorizationHandler = self.authorizationHandler else { From 0d2baf60fb8ceb2492576bc94553c4d19d8a673e Mon Sep 17 00:00:00 2001 From: David Langley Date: Tue, 3 Jan 2023 17:54:02 +0000 Subject: [PATCH 005/160] Update Riot/Modules/LocationSharing/LocationManager.swift Co-authored-by: Alfonso Grillo --- Riot/Modules/LocationSharing/LocationManager.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Riot/Modules/LocationSharing/LocationManager.swift b/Riot/Modules/LocationSharing/LocationManager.swift index ee9ddb103d..857a595974 100644 --- a/Riot/Modules/LocationSharing/LocationManager.swift +++ b/Riot/Modules/LocationSharing/LocationManager.swift @@ -177,7 +177,6 @@ class LocationManager: NSObject { return status } - private func authorizationAlwaysRequestDidComplete(with status: CLAuthorizationStatus) { guard let authorizationHandler = self.authorizationHandler else { return From b8465ebd618de16d8f68a88811534ccb7c088b07 Mon Sep 17 00:00:00 2001 From: Phl-Pro Date: Tue, 10 Jan 2023 15:24:46 +0100 Subject: [PATCH 006/160] Handle VoIP buttons when VB is used (#7225) --- Riot/Assets/en.lproj/Vector.strings | 38 ++++++++++--------- Riot/Generated/Strings.swift | 8 ++++ Riot/Modules/Room/RoomViewController.m | 19 +++++++++- .../VoiceBroadcastRecorderCoordinator.swift | 4 ++ .../VoiceBroadcastRecorderProvider.swift | 8 ++++ .../VoiceBroadcastRecorderService.swift | 3 ++ ...oiceBroadcastRecorderServiceProtocol.swift | 3 ++ changelog.d/pr-7225.change | 1 + 8 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 changelog.d/pr-7225.change diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 04d0cd6931..c1b97f7913 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1522,7 +1522,7 @@ Tap the + to start adding people."; "device_verification_cancelled_by_me" = "The verification has been cancelled. Reason: %@"; "device_verification_error_cannot_load_device" = "Cannot load session information."; -// Mark: Incoming +// MARK: Incoming "device_verification_incoming_title" = "Incoming Verification Request"; "device_verification_incoming_description_1" = "Verify this session to mark it as trusted. Trusting sessions of partners gives you extra peace of mind when using end-to-end encrypted messages."; "device_verification_incoming_description_2" = "Verifying this session will mark it as trusted, and also mark your session as trusted to the partner."; @@ -2011,12 +2011,12 @@ Tap the + to start adding people."; "share_invite_link_room_text" = "Hey, join this room on %@"; "share_invite_link_space_text" = "Hey, join this space on %@"; -// Mark: - Room avatar view +// MARK: - Room avatar view "room_avatar_view_accessibility_label" = "avatar"; "room_avatar_view_accessibility_hint" = "Change room avatar"; -// Mark: - Room creation introduction cell +// MARK: - Room creation introduction cell "room_intro_cell_add_participants_action" = "Add people"; @@ -2033,7 +2033,7 @@ Tap the + to start adding people."; "room_intro_cell_information_dm_sentence2" = "Only the two of you are in this conversation, no one else can join."; "room_intro_cell_information_multiple_dm_sentence2" = "Only you are in this conversation, unless any of you invites someone to join."; -// Mark: - Room invite +// MARK: - Room invite "room_invite_to_space_option_title" = "To %@"; "room_invite_to_space_option_detail" = "They can explore %@, but won’t be a member of %@."; @@ -2042,7 +2042,7 @@ Tap the + to start adding people."; "room_invite_not_enough_permission" = "You do not have permission to invite people to this room"; "space_invite_not_enough_permission" = "You do not have permission to invite people to this space"; -// Mark: - Spaces +// MARK: - Spaces "space_feature_unavailable_title" = "Spaces aren’t here yet"; "space_feature_unavailable_subtitle" = "Spaces aren't on iOS yet, but you can use them now on Web and Desktop"; @@ -2099,7 +2099,7 @@ Tap the + to start adding people."; "spaces_feature_not_available" = "This feature isn't available here. For now, you can do this with %@ on your computer."; -// Mark: - Space Creation +// MARK: - Space Creation "spaces_creation_hint" = "Spaces are a new way to group rooms and people."; "spaces_creation_visibility_title" = "What type of space do you want to create?"; @@ -2158,7 +2158,7 @@ Tap the + to start adding people."; "spaces_add_room_missing_permission_message" = "You do not have permissions to add rooms to this space."; -// Mark: Leave space +// MARK: Leave space "leave_space_action" = "Leave space"; "leave_space_and_one_room" = "Leave space and 1 room"; @@ -2171,17 +2171,17 @@ Tap the + to start adding people."; "room_event_action_reaction_more" = "%@ more"; -// Mark: Avatar +// MARK: Avatar "space_avatar_view_accessibility_label" = "avatar"; "space_avatar_view_accessibility_hint" = "Change space avatar"; -// Mark: - User avatar view +// MARK: - User avatar view "user_avatar_view_accessibility_label" = "avatar"; "user_avatar_view_accessibility_hint" = "Change user avatar"; -// Mark: - Side menu +// MARK: - Side menu "side_menu_reveal_action_accessibility_label" = "Left panel"; "side_menu_action_invite_friends" = "Invite friends"; @@ -2191,7 +2191,7 @@ Tap the + to start adding people."; "side_menu_app_version" = "Version %@"; "side_menu_coach_message" = "Swipe right or tap to see all rooms"; -// Mark: - Voice Messages +// MARK: - Voice Messages "voice_message_release_to_send" = "Hold to record, release to send"; "voice_message_remaining_recording_time" = "%@s left"; @@ -2200,7 +2200,7 @@ Tap the + to start adding people."; "voice_message_broadcast_in_progress_title" = "Can't start voice message"; "voice_message_broadcast_in_progress_message" = "You can't start a voice message as you are currently recording a live broadcast. Please end your live broadcast in order to start recording a voice message"; -// Mark: - Voice broadcast +// MARK: - Voice Broadcast "voice_broadcast_unauthorized_title" = "Can't start a new voice broadcast"; "voice_broadcast_permission_denied_message" = "You don't have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions."; "voice_broadcast_blocked_by_someone_else_message" = "Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one."; @@ -2213,8 +2213,10 @@ Tap the + to start adding people."; "voice_broadcast_stop_alert_title" = "Stop live broadcasting?"; "voice_broadcast_stop_alert_description" = "Are you sure you want to stop your live broadcast? This will end the broadcast, and the full recording will be available in the room."; "voice_broadcast_stop_alert_agree_button" = "Yes, stop"; +"voice_broadcast_voip_cannot_start_title" = "Can’t start a call"; +"voice_broadcast_voip_cannot_start_description" = "You can’t start a call as you are currently recording a live broadcast. Please end your live broadcast in order to start a call."; -// Mark: - Version check +// MARK: - Version check "version_check_banner_title_supported" = "We’re ending support for iOS %@"; "version_check_banner_subtitle_supported" = "We will soon be ending support for %@ on iOS %@. To continue using %@ to its full potential, we advise you to upgrade your version of iOS."; @@ -2230,7 +2232,7 @@ Tap the + to start adding people."; "version_check_modal_subtitle_deprecated" = "We've been working on enhancing %@ for a faster and more polished experience. Unfortunately your current version of iOS is not compatible with some of those fixes and is no longer supported.\nWe're advising you to upgrade your operating system to use %@ to its full potential."; "version_check_modal_action_title_deprecated" = "Find out how"; -// Mark: - All Chats +// MARK: - All Chats "all_chats_title" = "All chats"; "all_chats_section_title" = "Chats"; @@ -2274,12 +2276,12 @@ Tap the + to start adding people."; "all_chats_onboarding_title" = "What's new"; "all_chats_onboarding_try_it" = "Try it out"; -// Mark: - Room invites +// MARK: - Room invites "room_invites_empty_view_title" = "Nothing new."; "room_invites_empty_view_information" = "This is where your invites appear."; -// Mark: - Space Selector +// MARK: - Space Selector "space_selector_title" = "My spaces"; "space_selector_empty_view_title" = "No spaces yet."; @@ -2289,7 +2291,7 @@ Tap the + to start adding people."; "space_detail_nav_title" = "Space detail"; "space_invite_nav_title" = "Space invite"; -// Mark: - Polls +// MARK: - Polls "poll_edit_form_create_poll" = "Create poll"; @@ -2538,7 +2540,7 @@ To enable access, tap Settings> Location and select Always"; "user_session_overview_session_details_button_title" = "Session details"; -// Mark: - WYSIWYG Composer +// MARK: - WYSIWYG Composer // Send Media Actions "wysiwyg_composer_start_action_media_picker" = "Photo Library"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 1dde36ec4f..5730a63056 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -9215,6 +9215,14 @@ public class VectorL10n: NSObject { public static var voiceBroadcastUnauthorizedTitle: String { return VectorL10n.tr("Vector", "voice_broadcast_unauthorized_title") } + /// You can’t start a call as you are currently recording a live broadcast. Please end your live broadcast in order to start a call. + public static var voiceBroadcastVoipCannotStartDescription: String { + return VectorL10n.tr("Vector", "voice_broadcast_voip_cannot_start_description") + } + /// Can’t start a call + public static var voiceBroadcastVoipCannotStartTitle: String { + return VectorL10n.tr("Vector", "voice_broadcast_voip_cannot_start_title") + } /// You can't start a voice message as you are currently recording a live broadcast. Please end your live broadcast in order to start recording a voice message public static var voiceMessageBroadcastInProgressMessage: String { return VectorL10n.tr("Vector", "voice_message_broadcast_in_progress_message") diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index ca6daf5e07..7e98732090 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -5187,7 +5187,14 @@ - (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)ro - (IBAction)onVoiceCallPressed:(id)sender { - if (self.isCallActive) + // Manage case of a Voice broadcast listening -> Pause Voice broadcast playback + [VoiceBroadcastPlaybackProvider.shared pausePlaying]; + + if (VoiceBroadcastRecorderProvider.shared.isVoiceBroadcastRecording) { + [[AppDelegate theDelegate] showAlertWithTitle:VectorL10n.voiceBroadcastVoipCannotStartTitle + message:VectorL10n.voiceBroadcastVoipCannotStartDescription]; + } + else if (self.isCallActive) { [self hangupCall]; } @@ -5199,7 +5206,15 @@ - (IBAction)onVoiceCallPressed:(id)sender - (IBAction)onVideoCallPressed:(id)sender { - [self placeCallWithVideo:YES]; + // Manage case of a Voice broadcast listening -> Pause Voice broadcast playback + [VoiceBroadcastPlaybackProvider.shared pausePlaying]; + + if (VoiceBroadcastRecorderProvider.shared.isVoiceBroadcastRecording) { + [[AppDelegate theDelegate] showAlertWithTitle:VectorL10n.voiceBroadcastVoipCannotStartTitle + message:VectorL10n.voiceBroadcastVoipCannotStartDescription]; + } else { + [self placeCallWithVideo:YES]; + } } - (IBAction)onThreadListTapped:(id)sender diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift index 2a9fe90b8b..77d4c394a7 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift @@ -68,6 +68,10 @@ final class VoiceBroadcastRecorderCoordinator: Coordinator, Presentable { func pauseRecording() { voiceBroadcastRecorderViewModel.context.send(viewAction: .pause) } + + func isVoiceBroadcastRecording() -> Bool { + return voiceBroadcastRecorderService.isRecording + } // MARK: - Private } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift index e7f9987160..7b82429cb5 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift @@ -85,6 +85,14 @@ import Foundation voiceBroadcastRecorderCoordinatorForCurrentEvent()?.pauseRecording() } + @objc public func isVoiceBroadcastRecording() -> Bool { + guard let coordinator = voiceBroadcastRecorderCoordinatorForCurrentEvent() else { + return false + } + + return coordinator.isVoiceBroadcastRecording() + } + // MARK: - Private /// Retrieve the voiceBroadcast recorder coordinator for the current event or nil if it hasn't been created yet diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift index 437abbe3cb..fd8fc664dd 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift @@ -44,6 +44,9 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol { // MARK: Public weak var serviceDelegate: VoiceBroadcastRecorderServiceDelegate? + var isRecording: Bool { + return audioEngine.isRunning + } // MARK: - Setup diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift index 9e48e2e9af..1b3e77878e 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift @@ -25,6 +25,9 @@ protocol VoiceBroadcastRecorderServiceProtocol { /// Service delegate var serviceDelegate: VoiceBroadcastRecorderServiceDelegate? { get set } + /// Returns if a voice broadcast is currently recording. + var isRecording: Bool { get } + /// Start voice broadcast recording. func startRecordingVoiceBroadcast() diff --git a/changelog.d/pr-7225.change b/changelog.d/pr-7225.change new file mode 100644 index 0000000000..df6cfd7a70 --- /dev/null +++ b/changelog.d/pr-7225.change @@ -0,0 +1 @@ +Labs: VoiceBroadcast: Handle VoIP buttons when VB is used From b54453cee19134f14418de36087b7243432fcc23 Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 10 Jan 2023 16:50:20 +0000 Subject: [PATCH 007/160] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index ea1f94f28e..7271fabb83 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.9.15 -CURRENT_PROJECT_VERSION = 1.9.15 +MARKETING_VERSION = 1.9.16 +CURRENT_PROJECT_VERSION = 1.9.16 From d7985006161bef91bc6cd07334aea129b480f758 Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 10 Jan 2023 16:37:48 +0000 Subject: [PATCH 008/160] Fix Element Alpha workflow set-output is deprecated and the warning fails the secret check. Instead match ElementX by comparing the pull request repo to make sure it matches the workflow's repo. --- .github/workflows/release-alpha.yml | 16 ++-------------- changelog.d/pr-7256.build | 1 + 2 files changed, 3 insertions(+), 14 deletions(-) create mode 100644 changelog.d/pr-7256.build diff --git a/.github/workflows/release-alpha.yml b/.github/workflows/release-alpha.yml index f8d03f08b9..e4f4671dee 100644 --- a/.github/workflows/release-alpha.yml +++ b/.github/workflows/release-alpha.yml @@ -13,22 +13,10 @@ env: MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }} jobs: - check-secret: - runs-on: macos-12 - outputs: - out-key: ${{ steps.out-key.outputs.defined }} - steps: - - id: out-key - env: - P12_KEY: ${{ secrets.ALPHA_CERTIFICATES_P12 }} - P12_PASSWORD_KEY: ${{ secrets.ALPHA_CERTIFICATES_P12 }} - if: "${{ env.P12_KEY != '' || env.P12_PASSWORD_KEY != '' }}" - run: echo "::set-output name=defined::true" build: - # Run job if secrets are available (not available for forks). - needs: [check-secret] + # Don't run for forks as secrets are unavailable. if: | - needs.check-secret.outputs.out-key == 'true' && + github.event.pull_request.head.repo.full_name == github.repository && (github.event_name == 'push' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'Trigger-PR-Build'))) diff --git a/changelog.d/pr-7256.build b/changelog.d/pr-7256.build new file mode 100644 index 0000000000..9a2cd140b7 --- /dev/null +++ b/changelog.d/pr-7256.build @@ -0,0 +1 @@ +Fix Element Alpha workflow not being able to run. From 3174da6991660d8c2a625189d49b0293e5fa980d Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 15:20:18 +0100 Subject: [PATCH 009/160] default link color in the RTE --- .../Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift index 7956ad107e..b47215c25b 100644 --- a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift +++ b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift @@ -44,7 +44,6 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp private var hostingViewController: VectorHostingController! private var wysiwygViewModel = WysiwygComposerViewModel( textColor: ThemeService.shared().theme.colors.primaryContent, - linkColor: ThemeService.shared().theme.colors.accent, codeBackgroundColor: ThemeService.shared().theme.selectedBackgroundColor ) private var viewModel: ComposerViewModelProtocol! @@ -299,7 +298,7 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp private func update(theme: Theme) { hostingViewController.view.backgroundColor = theme.colors.background wysiwygViewModel.textColor = theme.colors.primaryContent - wysiwygViewModel.linkColor = theme.colors.accent + wysiwygViewModel.linkColor = .link wysiwygViewModel.codeBackgroundColor = theme.selectedBackgroundColor } From 4dec1cef86adc88c554376545e90ed0630e73d28 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Tue, 10 Jan 2023 16:57:13 +0100 Subject: [PATCH 010/160] Fixe the now playing info center while a voice broadcast is played --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++++ .../VoiceMessageMediaServiceProvider.swift | 19 +++++++++++++---- .../VoiceMessageNowPlayingInfoProvider.swift | 21 +++++++++++++++++++ .../VoiceBroadcastPlaybackViewModel.swift | 18 ++++++++++++++++ 5 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoProvider.swift diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index c1b97f7913..7ba0e41cd0 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2215,6 +2215,7 @@ Tap the + to start adding people."; "voice_broadcast_stop_alert_agree_button" = "Yes, stop"; "voice_broadcast_voip_cannot_start_title" = "Can’t start a call"; "voice_broadcast_voip_cannot_start_description" = "You can’t start a call as you are currently recording a live broadcast. Please end your live broadcast in order to start a call."; +"voice_broadcast_playback_lock_screen_placeholder" = "Voice broadcast"; // MARK: - Version check diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 5730a63056..0e5553010a 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -9191,6 +9191,10 @@ public class VectorL10n: NSObject { public static var voiceBroadcastPlaybackLoadingError: String { return VectorL10n.tr("Vector", "voice_broadcast_playback_loading_error") } + /// Voice broadcast + public static var voiceBroadcastPlaybackLockScreenPlaceholder: String { + return VectorL10n.tr("Vector", "voice_broadcast_playback_lock_screen_placeholder") + } /// Yes, stop public static var voiceBroadcastStopAlertAgreeButton: String { return VectorL10n.tr("Vector", "voice_broadcast_stop_alert_agree_button") diff --git a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift index 54262f8289..f1b1b0e7c4 100644 --- a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift +++ b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift @@ -28,6 +28,7 @@ import MediaPlayer private var roomAvatarLoader: MXMediaLoader? private let audioPlayers: NSMapTable private let audioRecorders: NSHashTable + private let nowPlayingInfoProviders: NSMapTable private var displayLink: CADisplayLink! @@ -93,6 +94,7 @@ import MediaPlayer private override init() { audioPlayers = NSMapTable(valueOptions: .weakMemory) audioRecorders = NSHashTable(options: .weakMemory) + nowPlayingInfoProviders = NSMapTable(valueOptions: .weakMemory) activeAudioPlayers = Set() super.init() @@ -123,6 +125,10 @@ import MediaPlayer pauseAllServicesExcept(nil) } + func setNowPlayingInfoProvider(_ provider: VoiceMessageNowPlayingInfoProvider, forPlayer player: VoiceMessageAudioPlayer) { + nowPlayingInfoProviders.setObject(provider, forKey: player) + } + // MARK: - VoiceMessageAudioPlayerDelegate func audioPlayerDidStartPlaying(_ audioPlayer: VoiceMessageAudioPlayer) { @@ -256,9 +262,14 @@ import MediaPlayer return } - let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() - nowPlayingInfoCenter.nowPlayingInfo = [MPMediaItemPropertyTitle: VectorL10n.voiceMessageLockScreenPlaceholder, - MPMediaItemPropertyPlaybackDuration: audioPlayer.duration as Any, - MPNowPlayingInfoPropertyElapsedPlaybackTime: audioPlayer.currentTime as Any] + // If we have a NowPlayingInfoProvider for this player + if let nowPlayingInfoProvider = nowPlayingInfoProviders.object(forKey: audioPlayer) { + nowPlayingInfoProvider.updatePlayingInfoCenter(forPlayer: audioPlayer) + } else { + let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() + nowPlayingInfoCenter.nowPlayingInfo = [MPMediaItemPropertyTitle: VectorL10n.voiceMessageLockScreenPlaceholder, + MPMediaItemPropertyPlaybackDuration: audioPlayer.duration as Any, + MPNowPlayingInfoPropertyElapsedPlaybackTime: audioPlayer.currentTime as Any] + } } } diff --git a/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoProvider.swift b/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoProvider.swift new file mode 100644 index 0000000000..c6ab193a9a --- /dev/null +++ b/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoProvider.swift @@ -0,0 +1,21 @@ +// +// Copyright 2023 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 + +@objc protocol VoiceMessageNowPlayingInfoProvider { + func updatePlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) +} diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift index 1f5ac98721..1393e85293 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift @@ -16,6 +16,7 @@ import Combine import SwiftUI +import MediaPlayer // TODO: VoiceBroadcastPlaybackViewModel must be revisited in order to not depend on MatrixSDK // We need a VoiceBroadcastPlaybackServiceProtocol and VoiceBroadcastAggregatorProtocol @@ -302,6 +303,7 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic // Init and start the player on the first chunk let audioPlayer = self.mediaServiceProvider.audioPlayerForIdentifier(result.eventIdentifier) audioPlayer.registerDelegate(self) + self.mediaServiceProvider.setNowPlayingInfoProvider(self, forPlayer: audioPlayer) audioPlayer.loadContentFromURL(result.url, displayName: chunk.attachment.originalFileName) self.audioPlayer = audioPlayer @@ -482,3 +484,19 @@ extension VoiceBroadcastPlaybackViewModel: VoiceMessageAudioPlayerDelegate { stopIfVoiceBroadcastOver() } } + +// MARK: - NowPlayingInfoProvider + +extension VoiceBroadcastPlaybackViewModel: VoiceMessageNowPlayingInfoProvider { + func updatePlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) { + guard audioPlayer != nil, audioPlayer === player else { + return + } + + let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() + nowPlayingInfoCenter.nowPlayingInfo = [MPMediaItemPropertyTitle: VectorL10n.voiceBroadcastPlaybackLockScreenPlaceholder, + MPMediaItemPropertyPlaybackDuration: (state.playingState.duration / 1000.0) as Any, + MPNowPlayingInfoPropertyElapsedPlaybackTime: (state.bindings.progress / 1000.0) as Any, + MPNowPlayingInfoPropertyPlaybackRate: state.playbackState == .playing ? 1 : 0] + } +} From 7a53a825a4cf9c745daa1bfb8d16e5f1649cc046 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Tue, 10 Jan 2023 18:13:22 +0100 Subject: [PATCH 011/160] Add Towncrier file --- changelog.d/pr-7257.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-7257.bugfix diff --git a/changelog.d/pr-7257.bugfix b/changelog.d/pr-7257.bugfix new file mode 100644 index 0000000000..c83bd783df --- /dev/null +++ b/changelog.d/pr-7257.bugfix @@ -0,0 +1 @@ +Voice Broacast: The Now Playing Info Center now displays a voice broadcast instead of a voice message when a user is listening to a voice broadcast. From 11008835bd57064bc8bc9a23af75f714c629baa7 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 18:45:03 +0100 Subject: [PATCH 012/160] the behaviour is now the same as android for links, except for the the "(edited)" button which should be grey and this fix has made it blue, will check how to solve this but it might also need some design inputs regarding the "reply" label (which as android is blue, but both are very different from the ) --- Riot/Categories/MXKTableViewCellWithTextView.swift | 1 - .../Views/MessagesSearchResultAttachmentBubbleCell.m | 4 +--- .../Views/MessagesSearchResultTextMsgBubbleCell.m | 2 -- .../RoomCreation/RoomCreationCollapsedBubbleCell.m | 2 -- .../RoomMembership/RoomMembershipBubbleCell.m | 7 ------- .../RoomMembership/RoomMembershipCollapsedBubbleCell.m | 7 ------- .../TextMessage/Common/TextMessageBaseBubbleCell.swift | 8 -------- .../Incoming/Clear/RoomIncomingAttachmentBubbleCell.m | 2 -- .../RoomIncomingAttachmentWithPaginationTitleBubbleCell.m | 1 - .../RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m | 7 ------- .../Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.m | 2 -- .../RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m | 1 - ...chmentWithPaginationTitleWithoutSenderNameBubbleCell.m | 6 ------ .../RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m | 7 ------- .../Incoming/Clear/RoomIncomingTextMsgBubbleCell.m | 2 -- .../RoomIncomingTextMsgWithPaginationTitleBubbleCell.m | 1 - ...extMsgWithPaginationTitleWithoutSenderNameBubbleCell.m | 7 ------- .../RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m | 2 -- .../RoomIncomingTextMsgWithoutSenderNameBubbleCell.m | 2 -- .../Outgoing/Clear/RoomOutgoingTextMsgBubbleCell.m | 2 -- .../RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m | 2 -- 21 files changed, 1 insertion(+), 74 deletions(-) diff --git a/Riot/Categories/MXKTableViewCellWithTextView.swift b/Riot/Categories/MXKTableViewCellWithTextView.swift index 9331b5fd6e..03288d377e 100644 --- a/Riot/Categories/MXKTableViewCellWithTextView.swift +++ b/Riot/Categories/MXKTableViewCellWithTextView.swift @@ -24,7 +24,6 @@ extension MXKTableViewCellWithTextView: Themable { func update(theme: Theme) { mxkTextView.backgroundColor = .clear mxkTextView.textColor = theme.textPrimaryColor - mxkTextView.tintColor = theme.tintColor backgroundColor = theme.backgroundColor contentView.backgroundColor = .clear } diff --git a/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultAttachmentBubbleCell.m b/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultAttachmentBubbleCell.m index 561b0aac59..32e8edcd95 100644 --- a/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultAttachmentBubbleCell.m +++ b/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultAttachmentBubbleCell.m @@ -28,9 +28,7 @@ - (void)customizeTableViewCellRendering [super customizeTableViewCellRendering]; self.roomNameLabel.textColor = ThemeService.shared.theme.textSecondaryColor; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; - + [self updateUserNameColor]; } diff --git a/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultTextMsgBubbleCell.m b/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultTextMsgBubbleCell.m index 40818f8a00..780d11efe2 100644 --- a/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultTextMsgBubbleCell.m +++ b/Riot/Modules/GlobalSearch/Messages/Views/MessagesSearchResultTextMsgBubbleCell.m @@ -30,8 +30,6 @@ - (void)customizeTableViewCellRendering [self updateUserNameColor]; self.roomNameLabel.textColor = ThemeService.shared.theme.textSecondaryColor; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } - (void)render:(MXKCellData *)cellData diff --git a/Riot/Modules/Room/TimelineCells/RoomCreation/RoomCreationCollapsedBubbleCell.m b/Riot/Modules/Room/TimelineCells/RoomCreation/RoomCreationCollapsedBubbleCell.m index c06b34016f..34e292dc3c 100644 --- a/Riot/Modules/Room/TimelineCells/RoomCreation/RoomCreationCollapsedBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/RoomCreation/RoomCreationCollapsedBubbleCell.m @@ -26,8 +26,6 @@ @implementation RoomCreationCollapsedBubbleCell - (void)customizeTableViewCellRendering { [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } @end diff --git a/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipBubbleCell.m b/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipBubbleCell.m index 2fe69ff5fb..21ae1b2ade 100644 --- a/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipBubbleCell.m @@ -37,13 +37,6 @@ - (void)awakeFromNib xibPictureViewTopConstraintConstant = self.pictureViewTopConstraint.constant; } -- (void)customizeTableViewCellRendering -{ - [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; -} - - (void)prepareForReuse { [super prepareForReuse]; diff --git a/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipCollapsedBubbleCell.m b/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipCollapsedBubbleCell.m index eac1df9234..558ef70503 100644 --- a/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipCollapsedBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipCollapsedBubbleCell.m @@ -26,13 +26,6 @@ @implementation RoomMembershipCollapsedBubbleCell -- (void)customizeTableViewCellRendering -{ - [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; -} - - (void)layoutSubviews { [super layoutSubviews]; diff --git a/Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/TextMessage/Common/TextMessageBaseBubbleCell.swift b/Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/TextMessage/Common/TextMessageBaseBubbleCell.swift index 5a7d8984b1..d38b5cb3cb 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/TextMessage/Common/TextMessageBaseBubbleCell.swift +++ b/Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/TextMessage/Common/TextMessageBaseBubbleCell.swift @@ -51,14 +51,6 @@ class TextMessageBaseBubbleCell: SizableBaseRoomCell, RoomCellURLPreviewDisplaya override func setupMessageTextViewLongPressGesture() { // Do nothing, otherwise default setup prevent link tap } - - override func update(theme: Theme) { - super.update(theme: theme) - - if let messageTextView = self.messageTextView { - messageTextView.tintColor = theme.tintColor - } - } } // MARK: - RoomCellTimestampDisplayable diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentBubbleCell.m index 3dd06a1d81..6da4b9db19 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentBubbleCell.m @@ -28,8 +28,6 @@ - (void)customizeTableViewCellRendering [super customizeTableViewCellRendering]; [self updateUserNameColor]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } - (void)render:(MXKCellData *)cellData diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m index 2a7a96788e..d40aea21c4 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m @@ -30,7 +30,6 @@ - (void)customizeTableViewCellRendering [self updateUserNameColor]; self.paginationLabel.textColor = ThemeService.shared.theme.tintColor; self.paginationSeparatorView.backgroundColor = ThemeService.shared.theme.tintColor; - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } - (void)render:(MXKCellData *)cellData diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m index 30b096e915..2ca4816738 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m @@ -23,13 +23,6 @@ @implementation RoomIncomingAttachmentWithoutSenderInfoBubbleCell -- (void)customizeTableViewCellRendering -{ - [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; -} - + (CGFloat)heightForCellData:(MXKCellData*)cellData withMaximumWidth:(CGFloat)maxWidth { CGFloat rowHeight = [self attachmentBubbleCellHeightForCellData:cellData withMaximumWidth:maxWidth]; diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.m index 456305e9cb..716e15c315 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.m @@ -28,8 +28,6 @@ - (void)customizeTableViewCellRendering [super customizeTableViewCellRendering]; [self updateUserNameColor]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } - (void)render:(MXKCellData *)cellData diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m index d78362a655..4cb4f3761d 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m @@ -30,7 +30,6 @@ - (void)customizeTableViewCellRendering [self updateUserNameColor]; self.paginationLabel.textColor = ThemeService.shared.theme.tintColor; self.paginationSeparatorView.backgroundColor = ThemeService.shared.theme.tintColor; - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } - (void)render:(MXKCellData *)cellData diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.m index 46ea41861e..57cf006917 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.m @@ -22,11 +22,5 @@ @implementation RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell -- (void)customizeTableViewCellRendering -{ - [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; -} @end diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m index 7021df5f6b..ec91ee33d0 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m @@ -24,13 +24,6 @@ @implementation RoomOutgoingAttachmentWithoutSenderInfoBubbleCell -- (void)customizeTableViewCellRendering -{ - [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; -} - - (void)render:(MXKCellData *)cellData { [super render:cellData]; diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgBubbleCell.m index 28bbdb19c1..288e54d0a3 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgBubbleCell.m @@ -28,8 +28,6 @@ - (void)customizeTableViewCellRendering [super customizeTableViewCellRendering]; [self updateUserNameColor]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } - (void)render:(MXKCellData *)cellData diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m index c66531dcef..9e7bc37c3d 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m @@ -30,7 +30,6 @@ - (void)customizeTableViewCellRendering [self updateUserNameColor]; self.paginationLabel.textColor = ThemeService.shared.theme.tintColor; self.paginationSeparatorView.backgroundColor = ThemeService.shared.theme.tintColor; - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } - (void)render:(MXKCellData *)cellData diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m index ae41260493..86862a0d01 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m @@ -22,11 +22,4 @@ @implementation RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell -- (void)customizeTableViewCellRendering -{ - [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; -} - @end diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m index db4370dc59..245b17e77b 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m @@ -25,8 +25,6 @@ @implementation RoomIncomingTextMsgWithoutSenderInfoBubbleCell - (void)customizeTableViewCellRendering { [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } @end diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderNameBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderNameBubbleCell.m index 8678dd8944..3f5d73475a 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderNameBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithoutSenderNameBubbleCell.m @@ -25,8 +25,6 @@ @implementation RoomIncomingTextMsgWithoutSenderNameBubbleCell - (void)customizeTableViewCellRendering { [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } @end diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgBubbleCell.m index a31a520291..fa50aa35f4 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgBubbleCell.m @@ -28,8 +28,6 @@ - (void)customizeTableViewCellRendering [super customizeTableViewCellRendering]; [self updateUserNameColor]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m index 0bc9f1de30..dfafa3df62 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m @@ -25,8 +25,6 @@ @implementation RoomOutgoingTextMsgWithoutSenderInfoBubbleCell - (void)customizeTableViewCellRendering { [super customizeTableViewCellRendering]; - - self.messageTextView.tintColor = ThemeService.shared.theme.tintColor; } @end From 5335515252ddf3a3235b44a63840dd5310c6193c Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 21:29:02 +0100 Subject: [PATCH 013/160] fix --- Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift | 1 + Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 1 + Riot/Modules/MatrixKit/Utils/MXKTools.m | 2 ++ .../Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift | 1 - Riot/Utils/EventFormatter.m | 2 -- 5 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift b/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift index de1b198217..e65f07ce19 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift @@ -51,6 +51,7 @@ class HTMLFormatter: NSObject { DTDefaultFontName: font.fontName, DTDefaultFontSize: font.pointSize, DTDefaultLinkDecoration: false, + DTDefaultLinkColor: UIColor.link, DTWillFlushBlockCallBack: sanitizeCallback ] options.merge(extraOptions) { (_, new) in new } diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index 21be58eb19..70c36ecd58 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -1749,6 +1749,7 @@ - (NSAttributedString*)renderString:(NSString*)string forEvent:(MXEvent*)event if (url.URL) { [str addAttribute:NSLinkAttributeName value:url.URL range:matchRange]; + [str addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:matchRange]; } } } diff --git a/Riot/Modules/MatrixKit/Utils/MXKTools.m b/Riot/Modules/MatrixKit/Utils/MXKTools.m index 10cf491a66..a1c9d702a7 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKTools.m +++ b/Riot/Modules/MatrixKit/Utils/MXKTools.m @@ -1083,6 +1083,7 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable // If the match is fully in the link, skip it if (NSIntersectionRange(match.range, linkMatch.range).length == match.range.length) { + [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:linkMatch.range]; hasAlreadyLink = YES; break; } @@ -1097,6 +1098,7 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable NSString *link = [mutableAttributedString.string substringWithRange:match.range]; link = [link stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; [mutableAttributedString addAttribute:NSLinkAttributeName value:link range:match.range]; + [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:match.range]; } }]; } diff --git a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift index b47215c25b..0fdfb16708 100644 --- a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift +++ b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift @@ -298,7 +298,6 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp private func update(theme: Theme) { hostingViewController.view.backgroundColor = theme.colors.background wysiwygViewModel.textColor = theme.colors.primaryContent - wysiwygViewModel.linkColor = .link wysiwygViewModel.codeBackgroundColor = theme.selectedBackgroundColor } diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 654fab329d..eb793b8115 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -384,8 +384,6 @@ - (NSAttributedString *)unsafeAttributedStringFromEvent:(MXEvent *)event [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" %@", [VectorL10n eventFormatterMessageEditedMention]] attributes:@{ NSLinkAttributeName: linkActionString, - // NOTE: Color is curretly overidden by UIText.tintColor as we use `NSLinkAttributeName`. - // If we use UITextView.linkTextAttributes to set link color we will also have the issue that color will be the same for all kind of links. NSForegroundColorAttributeName: self.editionMentionTextColor, NSFontAttributeName: self.editionMentionTextFont }]]; From e40a36e4626f72521537c73fc90222eafb304798 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 21:39:09 +0100 Subject: [PATCH 014/160] this is required to enable custom colors for specific links --- Riot/Modules/MatrixKit/Views/MXKMessageTextView.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Modules/MatrixKit/Views/MXKMessageTextView.m b/Riot/Modules/MatrixKit/Views/MXKMessageTextView.m index 74132c23f0..ca572733a0 100644 --- a/Riot/Modules/MatrixKit/Views/MXKMessageTextView.m +++ b/Riot/Modules/MatrixKit/Views/MXKMessageTextView.m @@ -67,6 +67,7 @@ - (void)setText:(NSString *)text - (void)setAttributedText:(NSAttributedString *)attributedText { + self.linkTextAttributes = @{}; if (@available(iOS 15.0, *)) { [self flushPills]; } From b1a10750ff38857628c64fd71bd03eca1bf13b65 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 23:40:35 +0100 Subject: [PATCH 015/160] done --- Riot/Modules/MatrixKit/Utils/MXKTools.m | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/MatrixKit/Utils/MXKTools.m b/Riot/Modules/MatrixKit/Utils/MXKTools.m index a1c9d702a7..d5722d961d 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKTools.m +++ b/Riot/Modules/MatrixKit/Utils/MXKTools.m @@ -46,6 +46,7 @@ static NSRegularExpression *httpLinksRegex; // A regex to find all HTML tags static NSRegularExpression *htmlTagsRegex; +static NSDataDetector *linkDetector; @implementation MXKTools @@ -60,7 +61,8 @@ + (void)initialize eventIdRegex = [NSRegularExpression regularExpressionWithPattern:kMXToolsRegexStringForMatrixEventIdentifier options:NSRegularExpressionCaseInsensitive error:nil]; httpLinksRegex = [NSRegularExpression regularExpressionWithPattern:@"(?i)\\b(https?://\\S*)\\b" options:NSRegularExpressionCaseInsensitive error:nil]; - htmlTagsRegex = [NSRegularExpression regularExpressionWithPattern:@"<(\\w+)[^>]*>" options:NSRegularExpressionCaseInsensitive error:nil]; + htmlTagsRegex = [NSRegularExpression regularExpressionWithPattern:@"<(\\w+)[^>]*>" options:NSRegularExpressionCaseInsensitive error:nil]; + linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil]; }); } @@ -1037,6 +1039,23 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable { [MXKTools createLinksInMutableAttributedString:mutableAttributedString matchingRegex:eventIdRegex]; } + + // This allows to check for normal url based links (like https://element.io) + // And set back the default link color + NSArray *matches = [linkDetector matchesInString: [mutableAttributedString string] options:0 range: NSMakeRange(0,mutableAttributedString.length)]; + if (matches && matches.count > 0) + { + for (NSTextCheckingResult *match in matches) + { + NSRange matchRange = [match range]; + NSURL *matchUrl = [match URL]; + NSURLComponents *url = [[NSURLComponents new] initWithURL:matchUrl resolvingAgainstBaseURL:NO]; + if (url.URL) + { + [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:matchRange]; + } + } + } } + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutableAttributedString matchingRegex:(NSRegularExpression*)regex @@ -1083,6 +1102,7 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable // If the match is fully in the link, skip it if (NSIntersectionRange(match.range, linkMatch.range).length == match.range.length) { + // but before we set the right color [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:linkMatch.range]; hasAlreadyLink = YES; break; From 2c7ff6a1fae35fb46d220bb03e489ae0b4ee916d Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 23:46:59 +0100 Subject: [PATCH 016/160] changelog part 1 --- changelog.d/5148.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5148.bugfix diff --git a/changelog.d/5148.bugfix b/changelog.d/5148.bugfix new file mode 100644 index 0000000000..7f1ddcb3e4 --- /dev/null +++ b/changelog.d/5148.bugfix @@ -0,0 +1 @@ +The (edited) tag for messages is now light grey like on web and Android. \ No newline at end of file From 3c8874c5c5f5887659220725309e43eafa6ab228 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 23:52:34 +0100 Subject: [PATCH 017/160] changelog --- changelog.d/5437.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5437.bugfix diff --git a/changelog.d/5437.bugfix b/changelog.d/5437.bugfix new file mode 100644 index 0000000000..59c6185c50 --- /dev/null +++ b/changelog.d/5437.bugfix @@ -0,0 +1 @@ +HTML links should now be displayed in default system blue. \ No newline at end of file From da49924dffd984014897358e1ac8f775d79cc52c Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 11 Jan 2023 23:56:46 +0100 Subject: [PATCH 018/160] changelog --- changelog.d/2292.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2292.change diff --git a/changelog.d/2292.change b/changelog.d/2292.change new file mode 100644 index 0000000000..b1d61e979d --- /dev/null +++ b/changelog.d/2292.change @@ -0,0 +1 @@ +Links are now in blue like on web and Android. \ No newline at end of file From fdd77a2ffe23cf3bd6d17a5d08df38f426e939b5 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 00:02:00 +0100 Subject: [PATCH 019/160] changelog --- changelog.d/2419.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2419.bugfix diff --git a/changelog.d/2419.bugfix b/changelog.d/2419.bugfix new file mode 100644 index 0000000000..900d2135c8 --- /dev/null +++ b/changelog.d/2419.bugfix @@ -0,0 +1 @@ +Hyperlinks are now blue and should now be distinguishable from unsent messages in encrypted rooms. \ No newline at end of file From dcac584a37213b473595ffe936128443a4c750d3 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 00:13:29 +0100 Subject: [PATCH 020/160] changelog --- changelog.d/7263.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7263.bugfix diff --git a/changelog.d/7263.bugfix b/changelog.d/7263.bugfix new file mode 100644 index 0000000000..061f8a6444 --- /dev/null +++ b/changelog.d/7263.bugfix @@ -0,0 +1 @@ +Timeline's tag and hyperlinks match now in colour Android and Web. \ No newline at end of file From b2ae0e78b206b2dc7671f34a0f87b9359fc52325 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Wed, 11 Jan 2023 14:56:40 +0100 Subject: [PATCH 021/160] Fix NowPlayingInfoCenter for a live voice broadcast --- .../VoiceMessageMediaServiceProvider.swift | 40 +++++++++++++------ ... VoiceMessageNowPlayingInfoDelegate.swift} | 7 +++- .../VoiceBroadcastPlaybackViewModel.swift | 32 +++++++++++---- 3 files changed, 57 insertions(+), 22 deletions(-) rename Riot/Modules/Room/VoiceMessages/{VoiceMessageNowPlayingInfoProvider.swift => VoiceMessageNowPlayingInfoDelegate.swift} (72%) diff --git a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift index f1b1b0e7c4..04a4ac7ec5 100644 --- a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift +++ b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift @@ -28,7 +28,7 @@ import MediaPlayer private var roomAvatarLoader: MXMediaLoader? private let audioPlayers: NSMapTable private let audioRecorders: NSHashTable - private let nowPlayingInfoProviders: NSMapTable + private let nowPlayingInfoDelegates: NSMapTable private var displayLink: CADisplayLink! @@ -94,7 +94,7 @@ import MediaPlayer private override init() { audioPlayers = NSMapTable(valueOptions: .weakMemory) audioRecorders = NSHashTable(options: .weakMemory) - nowPlayingInfoProviders = NSMapTable(valueOptions: .weakMemory) + nowPlayingInfoDelegates = NSMapTable(valueOptions: .weakMemory) activeAudioPlayers = Set() super.init() @@ -125,8 +125,12 @@ import MediaPlayer pauseAllServicesExcept(nil) } - func setNowPlayingInfoProvider(_ provider: VoiceMessageNowPlayingInfoProvider, forPlayer player: VoiceMessageAudioPlayer) { - nowPlayingInfoProviders.setObject(provider, forKey: player) + func registerNowPlayingInfoDelegate(_ delegate: VoiceMessageNowPlayingInfoDelegate, forPlayer player: VoiceMessageAudioPlayer) { + nowPlayingInfoDelegates.setObject(delegate, forKey: player) + } + + func deregisterNowPlayingInfoDelegate(forPlayer player: VoiceMessageAudioPlayer) { + nowPlayingInfoDelegates.removeObject(forKey: player) } // MARK: - VoiceMessageAudioPlayerDelegate @@ -140,16 +144,28 @@ import MediaPlayer func audioPlayerDidStopPlaying(_ audioPlayer: VoiceMessageAudioPlayer) { if currentlyPlayingAudioPlayer == audioPlayer { - currentlyPlayingAudioPlayer = nil - tearDownRemoteCommandCenter() + // If we have a NowPlayingInfoDelegate for this player + let nowPlayingInfoDelegate = nowPlayingInfoDelegates.object(forKey: audioPlayer) + + // ask the delegate if we should disconnect from NowPlayingInfoCenter (if there's no delegate, we consider it safe to disconnect it) + if nowPlayingInfoDelegate?.shouldDisconnectFromNowPlayingInfoCenter(audioPlayer: audioPlayer) ?? true { + currentlyPlayingAudioPlayer = nil + tearDownRemoteCommandCenter(for: audioPlayer) + } } activeAudioPlayers.remove(audioPlayer) } func audioPlayerDidFinishPlaying(_ audioPlayer: VoiceMessageAudioPlayer) { if currentlyPlayingAudioPlayer == audioPlayer { - currentlyPlayingAudioPlayer = nil - tearDownRemoteCommandCenter() + // If we have a NowPlayingInfoDelegate for this player + let nowPlayingInfoDelegate = nowPlayingInfoDelegates.object(forKey: audioPlayer) + + // ask the delegate if we should disconnect from NowPlayingInfoCenter (if there's no delegate, we consider it safe to disconnect it) + if nowPlayingInfoDelegate?.shouldDisconnectFromNowPlayingInfoCenter(audioPlayer: audioPlayer) ?? true { + currentlyPlayingAudioPlayer = nil + tearDownRemoteCommandCenter(for: audioPlayer) + } } activeAudioPlayers.remove(audioPlayer) } @@ -248,7 +264,7 @@ import MediaPlayer } } - private func tearDownRemoteCommandCenter() { + private func tearDownRemoteCommandCenter(for audioPlayer: VoiceMessageAudioPlayer) { displayLink.isPaused = true UIApplication.shared.endReceivingRemoteControlEvents() @@ -262,9 +278,9 @@ import MediaPlayer return } - // If we have a NowPlayingInfoProvider for this player - if let nowPlayingInfoProvider = nowPlayingInfoProviders.object(forKey: audioPlayer) { - nowPlayingInfoProvider.updatePlayingInfoCenter(forPlayer: audioPlayer) + // Checks if we have a delegate for this player, or if we should update the NowPlayingInfoCenter ourselves + if let nowPlayingInfoDelegate = nowPlayingInfoDelegates.object(forKey: audioPlayer) { + nowPlayingInfoDelegate.updateNowPlayingInfoCenter(forPlayer: audioPlayer) } else { let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() nowPlayingInfoCenter.nowPlayingInfo = [MPMediaItemPropertyTitle: VectorL10n.voiceMessageLockScreenPlaceholder, diff --git a/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoProvider.swift b/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoDelegate.swift similarity index 72% rename from Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoProvider.swift rename to Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoDelegate.swift index c6ab193a9a..6955b4c0f0 100644 --- a/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoProvider.swift +++ b/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoDelegate.swift @@ -16,6 +16,9 @@ import Foundation -@objc protocol VoiceMessageNowPlayingInfoProvider { - func updatePlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) +@objc protocol VoiceMessageNowPlayingInfoDelegate { + + func updateNowPlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) + + func shouldDisconnectFromNowPlayingInfoCenter(audioPlayer: VoiceMessageAudioPlayer) -> Bool } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift index 1393e85293..56e4357578 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift @@ -303,7 +303,7 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic // Init and start the player on the first chunk let audioPlayer = self.mediaServiceProvider.audioPlayerForIdentifier(result.eventIdentifier) audioPlayer.registerDelegate(self) - self.mediaServiceProvider.setNowPlayingInfoProvider(self, forPlayer: audioPlayer) + self.mediaServiceProvider.registerNowPlayingInfoDelegate(self, forPlayer: audioPlayer) audioPlayer.loadContentFromURL(result.url, displayName: chunk.attachment.originalFileName) self.audioPlayer = audioPlayer @@ -472,6 +472,7 @@ extension VoiceBroadcastPlaybackViewModel: VoiceMessageAudioPlayerDelegate { state.playbackState = .stopped state.playingState.isLive = false audioPlayer.deregisterDelegate(self) + self.mediaServiceProvider.deregisterNowPlayingInfoDelegate(forPlayer: audioPlayer) self.audioPlayer = nil } @@ -485,18 +486,33 @@ extension VoiceBroadcastPlaybackViewModel: VoiceMessageAudioPlayerDelegate { } } -// MARK: - NowPlayingInfoProvider +// MARK: - VoiceMessageNowPlayingInfoDelegate -extension VoiceBroadcastPlaybackViewModel: VoiceMessageNowPlayingInfoProvider { - func updatePlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) { +extension VoiceBroadcastPlaybackViewModel: VoiceMessageNowPlayingInfoDelegate { + + func shouldDisconnectFromNowPlayingInfoCenter(audioPlayer player: VoiceMessageAudioPlayer) -> Bool { + guard BuildSettings.allowBackgroundAudioMessagePlayback, audioPlayer != nil, audioPlayer === player else { + return true + } + + return state.broadcastState == .stopped + } + + func updateNowPlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) { guard audioPlayer != nil, audioPlayer === player else { return } let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() - nowPlayingInfoCenter.nowPlayingInfo = [MPMediaItemPropertyTitle: VectorL10n.voiceBroadcastPlaybackLockScreenPlaceholder, - MPMediaItemPropertyPlaybackDuration: (state.playingState.duration / 1000.0) as Any, - MPNowPlayingInfoPropertyElapsedPlaybackTime: (state.bindings.progress / 1000.0) as Any, - MPNowPlayingInfoPropertyPlaybackRate: state.playbackState == .playing ? 1 : 0] + nowPlayingInfoCenter.nowPlayingInfo = [ + // Title + MPMediaItemPropertyTitle: VectorL10n.voiceBroadcastPlaybackLockScreenPlaceholder, + // Buffering status (using the "artist" property to display it under the title) + MPMediaItemPropertyArtist: state.playbackState == .buffering ? VectorL10n.voiceBroadcastBuffering : "", + // Duration + MPMediaItemPropertyPlaybackDuration: (state.playingState.duration / 1000.0) as Any, + // Elapsed time + MPNowPlayingInfoPropertyElapsedPlaybackTime: (state.bindings.progress / 1000.0) as Any, + ] } } From 891ceb85464161b3aeef4e239dd822488083bccc Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 10:41:52 +0100 Subject: [PATCH 022/160] fixed a test and some code improvements --- Riot/Modules/MatrixKit/Utils/MXKTools.m | 2 +- RiotTests/MatrixKitTests/MXKEventFormatterTests.m | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Riot/Modules/MatrixKit/Utils/MXKTools.m b/Riot/Modules/MatrixKit/Utils/MXKTools.m index d5722d961d..fdb7f51f89 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKTools.m +++ b/Riot/Modules/MatrixKit/Utils/MXKTools.m @@ -1043,7 +1043,7 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable // This allows to check for normal url based links (like https://element.io) // And set back the default link color NSArray *matches = [linkDetector matchesInString: [mutableAttributedString string] options:0 range: NSMakeRange(0,mutableAttributedString.length)]; - if (matches && matches.count > 0) + if (matches) { for (NSTextCheckingResult *match in matches) { diff --git a/RiotTests/MatrixKitTests/MXKEventFormatterTests.m b/RiotTests/MatrixKitTests/MXKEventFormatterTests.m index fbe801665d..e08619d5d9 100644 --- a/RiotTests/MatrixKitTests/MXKEventFormatterTests.m +++ b/RiotTests/MatrixKitTests/MXKEventFormatterTests.m @@ -414,14 +414,16 @@ - (void)testLinkWithRoomAliasLink NSString *s = @"Matrix HQ room is at https://matrix.to/#/room/#matrix:matrix.org."; NSAttributedString *as = [eventFormatter renderString:s forEvent:anEvent]; - __block NSUInteger ranges = 0; + __block bool hasLink = false; [as enumerateAttributesInRange:NSMakeRange(0, as.length) options:(0) usingBlock:^(NSDictionary * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) { - - ranges++; + if (attrs[NSLinkAttributeName]) { + hasLink = true; + *stop = true; + } }]; - XCTAssertEqual(ranges, 1, @"There should be no link in this case. We let the UI manage the link"); + XCTAssertEqual(hasLink, false, @"There should be no link in this case. We let the UI manage the link"); } #pragma mark - Event sender/target info From a493d6fd62d76ed7360c23fdbec5a0dbce24fca2 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 11 Jan 2023 18:40:56 +0100 Subject: [PATCH 023/160] =?UTF-8?q?Add=20poll=20history=20in=20room?= =?UTF-8?q?=E2=80=99s=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Config/BuildSettings.swift | 7 +++++++ .../Room/pollHistory.imageset/Contents.json | 12 ++++++++++++ .../Room/pollHistory.imageset/pollHistory.svg | 3 +++ Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Images.swift | 1 + Riot/Generated/Strings.swift | 4 ++++ .../RoomInfoList/RoomInfoListViewController.swift | 10 ++++++++++ 7 files changed, 38 insertions(+) create mode 100644 Riot/Assets/Images.xcassets/Room/pollHistory.imageset/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Room/pollHistory.imageset/pollHistory.svg diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 2f85f3c131..0c23cdd207 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -399,6 +399,13 @@ final class BuildSettings: NSObject { // MARK: - Polls static let pollsEnabled = true + static var pollsHistoryEnabled: Bool { + #if DEBUG + true + #else + false + #endif + } // MARK: - Location Sharing diff --git a/Riot/Assets/Images.xcassets/Room/pollHistory.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/pollHistory.imageset/Contents.json new file mode 100644 index 0000000000..fcc0b57656 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/pollHistory.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "pollHistory.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Room/pollHistory.imageset/pollHistory.svg b/Riot/Assets/Images.xcassets/Room/pollHistory.imageset/pollHistory.svg new file mode 100644 index 0000000000..a0243252c4 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/pollHistory.imageset/pollHistory.svg @@ -0,0 +1,3 @@ + + + diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index c1b97f7913..b87d35a783 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -982,6 +982,7 @@ Tap the + to start adding people."; "room_details_title_for_dm" = "Details"; "room_details_people" = "Members"; "room_details_files" = "Uploads"; +"room_details_polls" = "Poll history"; "room_details_search" = "Search room"; "room_details_integrations" = "Integrations"; "room_details_settings" = "Settings"; diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index ed763a1710..6dc47703a9 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -285,6 +285,7 @@ internal class Asset: NSObject { internal static let modIcon = ImageAsset(name: "mod_icon") internal static let moreReactions = ImageAsset(name: "more_reactions") internal static let notifications = ImageAsset(name: "notifications") + internal static let pollHistory = ImageAsset(name: "pollHistory") internal static let reactionsMoreAction = ImageAsset(name: "reactions_more_action") internal static let roomAccessInfoHeaderIcon = ImageAsset(name: "room_access_info_header_icon") internal static let scrollup = ImageAsset(name: "scrollup") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 5730a63056..36fd6b67a6 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -5503,6 +5503,10 @@ public class VectorL10n: NSObject { public static var roomDetailsPhotoForDm: String { return VectorL10n.tr("Vector", "room_details_photo_for_dm") } + /// Poll history + public static var roomDetailsPolls: String { + return VectorL10n.tr("Vector", "room_details_polls") + } /// Suggest to space members public static var roomDetailsPromoteRoomSuggestTitle: String { return VectorL10n.tr("Vector", "room_details_promote_room_suggest_title") diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift index d55f674fe9..db245c1110 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift @@ -174,6 +174,11 @@ final class RoomInfoListViewController: UIViewController { let rowMembers = Row(type: .default, icon: Asset.Images.userIcon.image, text: text, accessoryType: .disclosureIndicator) { self.viewModel.process(viewAction: .navigate(target: .members)) } + + let rowPollHistory = Row(type: .default, icon: Asset.Images.pollHistory.image, text: VectorL10n.roomDetailsPolls, accessoryType: .disclosureIndicator) { + #warning("Add action") + } + let rowUploads = Row(type: .default, icon: Asset.Images.scrollup.image, text: VectorL10n.roomDetailsFiles, accessoryType: .disclosureIndicator) { self.viewModel.process(viewAction: .navigate(target: .uploads)) } @@ -193,6 +198,11 @@ final class RoomInfoListViewController: UIViewController { rows.append(rowIntegrations) } rows.append(rowMembers) + + if BuildSettings.pollsHistoryEnabled { + rows.append(rowPollHistory) + } + rows.append(rowUploads) if !viewData.isEncrypted { rows.append(rowSearch) From c8b20a79dc6b7d0b626e20930bd2c887e8555ecb Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 10:43:22 +0100 Subject: [PATCH 024/160] code improvement --- RiotTests/MatrixKitTests/MXKEventFormatterTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RiotTests/MatrixKitTests/MXKEventFormatterTests.m b/RiotTests/MatrixKitTests/MXKEventFormatterTests.m index e08619d5d9..b21f577150 100644 --- a/RiotTests/MatrixKitTests/MXKEventFormatterTests.m +++ b/RiotTests/MatrixKitTests/MXKEventFormatterTests.m @@ -414,7 +414,7 @@ - (void)testLinkWithRoomAliasLink NSString *s = @"Matrix HQ room is at https://matrix.to/#/room/#matrix:matrix.org."; NSAttributedString *as = [eventFormatter renderString:s forEvent:anEvent]; - __block bool hasLink = false; + __block BOOL hasLink = false; [as enumerateAttributesInRange:NSMakeRange(0, as.length) options:(0) usingBlock:^(NSDictionary * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) { if (attrs[NSLinkAttributeName]) { From 5ae59ea7d3dd72ece195f8e40b2639a68f7608a6 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 11:43:29 +0100 Subject: [PATCH 025/160] Add poll history scaffolding --- .../Room/RoomInfo/RoomInfoCoordinator.swift | 19 +++- .../RoomInfoList/RoomInfoListViewAction.swift | 1 + .../RoomInfoListViewController.swift | 2 +- .../Coordinator/PollHistoryCoordinator.swift | 76 +++++++++++++ .../MockPollHistoryScreenState.swift | 56 ++++++++++ .../Room/PollHistory/PollHistoryModels.swift | 67 ++++++++++++ .../PollHistory/PollHistoryViewModel.swift | 42 ++++++++ .../PollHistoryViewModelProtocol.swift | 22 ++++ .../Test/UI/PollHistoryUITests.swift | 38 +++++++ .../Test/Unit/PollHistoryViewModelTests.swift | 48 +++++++++ .../Room/PollHistory/View/PollHistory.swift | 102 ++++++++++++++++++ 11 files changed, 470 insertions(+), 3 deletions(-) create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModelProtocol.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index 44ddb735bf..6da39162a1 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -157,6 +157,10 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { return coordinator } + private func pollHistoryCoordinator() -> PollHistoryCoordinator { + return PollHistoryCoordinator(parameters: .init(promptType: .regular)) + } + private func showRoomDetails(with target: RoomInfoListTarget, animated: Bool) { switch target { case .integrations: @@ -174,8 +178,11 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { case .notifications: let coordinator = createRoomNotificationSettingsCoordinator() coordinator.start() - self.add(childCoordinator: coordinator) - self.navigationRouter.push(coordinator, animated: true, popCompletion: nil) + push(coordinator: coordinator) + case .pollHistory: + let coordinator = pollHistoryCoordinator() + coordinator.start() + push(coordinator: coordinator) default: guard let tabIndex = target.tabIndex else { fatalError("No settings tab index for this target.") @@ -189,6 +196,14 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { navigationRouter.push(segmentedViewController, animated: animated, popCompletion: nil) } } + + private func push(coordinator: Coordinator & Presentable, animated: Bool = true) { + coordinator.start() + self.add(childCoordinator: coordinator) + navigationRouter.push(coordinator, animated: animated) { + self.remove(childCoordinator: coordinator) + } + } } // MARK: - RoomInfoListCoordinatorDelegate diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift index c6e0c88876..6383d4fb5d 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift @@ -25,6 +25,7 @@ enum RoomInfoListTarget: Equatable { case integrations case search case notifications + case pollHistory var tabIndex: UInt? { switch self { diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift index db245c1110..fdb34304d0 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift @@ -176,7 +176,7 @@ final class RoomInfoListViewController: UIViewController { } let rowPollHistory = Row(type: .default, icon: Asset.Images.pollHistory.image, text: VectorL10n.roomDetailsPolls, accessoryType: .disclosureIndicator) { - #warning("Add action") + self.viewModel.process(viewAction: .navigate(target: .pollHistory)) } let rowUploads = Row(type: .default, icon: Asset.Images.scrollup.image, text: VectorL10n.roomDetailsFiles, accessoryType: .disclosureIndicator) { diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift new file mode 100644 index 0000000000..86b9149e7a --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift @@ -0,0 +1,76 @@ +// +// Copyright 2021 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 CommonKit +import SwiftUI + +struct PollHistoryCoordinatorParameters { + let promptType: PollHistoryPromptType +} + +final class PollHistoryCoordinator: Coordinator, Presentable { + private let parameters: PollHistoryCoordinatorParameters + private let pollHistoryHostingController: UIViewController + private var pollHistoryViewModel: PollHistoryViewModelProtocol + + private var indicatorPresenter: UserIndicatorTypePresenterProtocol + private var loadingIndicator: UserIndicator? + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + var completion: ((PollHistoryViewModelResult) -> Void)? + + init(parameters: PollHistoryCoordinatorParameters) { + self.parameters = parameters + + let viewModel = PollHistoryViewModel(promptType: parameters.promptType) + let view = PollHistory(viewModel: viewModel.context) + pollHistoryViewModel = viewModel + pollHistoryHostingController = VectorHostingController(rootView: view) + + indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: pollHistoryHostingController) + } + + // MARK: - Public + + func start() { + MXLog.debug("[PollHistoryCoordinator] did start.") + pollHistoryViewModel.completion = { [weak self] result in + guard let self = self else { return } + MXLog.debug("[PollHistoryCoordinator] PollHistoryViewModel did complete with result: \(result).") + self.completion?(result) + } + } + + func toPresentable() -> UIViewController { + pollHistoryHostingController + } + + // MARK: - Private + + /// Show an activity indicator whilst loading. + /// - Parameters: + /// - label: The label to show on the indicator. + /// - isInteractionBlocking: Whether the indicator should block any user interaction. + private func startLoading(label: String = VectorL10n.loading, isInteractionBlocking: Bool = true) { + loadingIndicator = indicatorPresenter.present(.loading(label: label, isInteractionBlocking: isInteractionBlocking)) + } + + /// Hide the currently displayed activity indicator. + private func stopLoading() { + loadingIndicator = nil + } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift new file mode 100644 index 0000000000..37d400e659 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift @@ -0,0 +1,56 @@ +// +// Copyright 2021 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 +import SwiftUI + +/// Using an enum for the screen allows you define the different state cases with +/// the relevant associated data for each case. +enum MockPollHistoryScreenState: MockScreenState, CaseIterable { + // A case for each state you want to represent + // with specific, minimal associated data that will allow you + // mock that screen. + case promptType(PollHistoryPromptType) + + /// The associated screen + var screenType: Any.Type { + PollHistory.self + } + + /// A list of screen state definitions + static var allCases: [MockPollHistoryScreenState] { + // Each of the presence statuses + PollHistoryPromptType.allCases.map(MockPollHistoryScreenState.promptType) + } + + /// Generate the view struct for the screen state. + var screenView: ([Any], AnyView) { + let promptType: PollHistoryPromptType + switch self { + case .promptType(let type): + promptType = type + } + let viewModel = PollHistoryViewModel(promptType: promptType) + + // can simulate service and viewModel actions here if needs be. + + return ( + [promptType, viewModel], + AnyView(PollHistory(viewModel: viewModel.context) + .addDependency(MockAvatarService.example)) + ) + } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift new file mode 100644 index 0000000000..7895fbcb21 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift @@ -0,0 +1,67 @@ +// +// Copyright 2021 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 + +// MARK: - Coordinator + +enum PollHistoryPromptType { + case regular + case upgrade +} + +extension PollHistoryPromptType: Identifiable, CaseIterable { + var id: Self { self } + + var title: String { + switch self { + case .regular: + return VectorL10n.roomCreationMakePublicPromptTitle + case .upgrade: + return VectorL10n.roomDetailsHistorySectionPromptTitle + } + } + + var image: ImageAsset { + switch self { + case .regular: + return Asset.Images.appSymbol + case .upgrade: + return Asset.Images.keyVerificationSuccessShield + } + } +} + +// MARK: View model + +enum PollHistoryViewModelResult { + case accept + case cancel +} + +// MARK: View + +struct PollHistoryViewState: BindableState { + var promptType: PollHistoryPromptType + var count: Int +} + +enum PollHistoryViewAction { + case incrementCount + case decrementCount + case accept + case cancel +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift new file mode 100644 index 0000000000..c7a78bbe5d --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift @@ -0,0 +1,42 @@ +// +// Copyright 2021 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 SwiftUI + +typealias PollHistoryViewModelType = StateStoreViewModel + +class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModelProtocol { + var completion: ((PollHistoryViewModelResult) -> Void)? + + init(promptType: PollHistoryPromptType, initialCount: Int = 0) { + super.init(initialViewState: PollHistoryViewState(promptType: promptType, count: 0)) + } + + // MARK: - Public + + override func process(viewAction: PollHistoryViewAction) { + switch viewAction { + case .accept: + completion?(.accept) + case .cancel: + completion?(.cancel) + case .incrementCount: + state.count += 1 + case .decrementCount: + state.count -= 1 + } + } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModelProtocol.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModelProtocol.swift new file mode 100644 index 0000000000..d116c02540 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModelProtocol.swift @@ -0,0 +1,22 @@ +// +// Copyright 2021 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 + +protocol PollHistoryViewModelProtocol { + var completion: ((PollHistoryViewModelResult) -> Void)? { get set } + var context: PollHistoryViewModelType.Context { get } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift new file mode 100644 index 0000000000..3b123c95dc --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift @@ -0,0 +1,38 @@ +// +// Copyright 2021 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 RiotSwiftUI +import XCTest + +class PollHistoryUITests: MockScreenTestCase { + func testPollHistoryPromptRegular() { + let promptType = PollHistoryPromptType.regular + app.goToScreenWithIdentifier(MockPollHistoryScreenState.promptType(promptType).title) + + let title = app.staticTexts["title"] + XCTAssert(title.exists) + XCTAssertEqual(title.label, promptType.title) + } + + func testPollHistoryPromptUpgrade() { + let promptType = PollHistoryPromptType.upgrade + app.goToScreenWithIdentifier(MockPollHistoryScreenState.promptType(promptType).title) + + let title = app.staticTexts["title"] + XCTAssert(title.exists) + XCTAssertEqual(title.label, promptType.title) + } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift b/RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift new file mode 100644 index 0000000000..a388d98235 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift @@ -0,0 +1,48 @@ +// +// Copyright 2021 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 XCTest + +@testable import RiotSwiftUI + +class PollHistoryViewModelTests: XCTestCase { + private enum Constants { + static let counterInitialValue = 0 + } + + var viewModel: PollHistoryViewModelProtocol! + var context: PollHistoryViewModelType.Context! + + override func setUpWithError() throws { + viewModel = PollHistoryViewModel(promptType: .regular, initialCount: Constants.counterInitialValue) + context = viewModel.context + } + + func testInitialState() { + XCTAssertEqual(context.viewState.count, Constants.counterInitialValue) + } + + func testCounter() throws { + context.send(viewAction: .incrementCount) + XCTAssertEqual(context.viewState.count, 1) + + context.send(viewAction: .incrementCount) + XCTAssertEqual(context.viewState.count, 2) + + context.send(viewAction: .decrementCount) + XCTAssertEqual(context.viewState.count, 1) + } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift new file mode 100644 index 0000000000..3ba8f1ed88 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -0,0 +1,102 @@ +// +// Copyright 2021 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 SwiftUI + +struct PollHistory: View { + @Environment(\.theme) private var theme + @Environment(\.horizontalSizeClass) private var horizontalSizeClass + + private var horizontalPadding: CGFloat { + horizontalSizeClass == .regular ? 50 : 16 + } + + @ObservedObject var viewModel: PollHistoryViewModel.Context + + var body: some View { + GeometryReader { geometry in + VStack { + ScrollView(showsIndicators: false) { + mainContent + .padding(.top, 50) + .padding(.horizontal, horizontalPadding) + } + + buttons + .padding(.horizontal, horizontalPadding) + .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 16) + } + } + .background(theme.colors.background.ignoresSafeArea()) + .accentColor(theme.colors.accent) + } + + /// The main content of the view to be shown in a scroll view. + var mainContent: some View { + VStack(spacing: 36) { + Text(viewModel.viewState.promptType.title) + .font(theme.fonts.title1B) + .foregroundColor(theme.colors.primaryContent) + .accessibilityIdentifier("title") + + Image(viewModel.viewState.promptType.image.name) + .resizable() + .scaledToFit() + .frame(width: 100) + .foregroundColor(theme.colors.accent) + + HStack { + Text("Counter: \(viewModel.viewState.count)") + .foregroundColor(theme.colors.primaryContent) + + Button("-") { + viewModel.send(viewAction: .decrementCount) + } + + Button("+") { + viewModel.send(viewAction: .incrementCount) + } + } + .font(theme.fonts.title3) + } + } + + /// The action buttons shown at the bottom of the view. + var buttons: some View { + VStack { + Button { viewModel.send(viewAction: .accept) } label: { + Text("Accept") + .font(theme.fonts.bodySB) + } + .buttonStyle(PrimaryActionButtonStyle()) + + Button { viewModel.send(viewAction: .cancel) } label: { + Text("Cancel") + .font(theme.fonts.body) + .padding(.vertical, 12) + } + } + } +} + +// MARK: - Previews + +struct PollHistory_Previews: PreviewProvider { + static let stateRenderer = MockPollHistoryScreenState.stateRenderer + static var previews: some View { + stateRenderer.screenGroup() + } +} From 29da649073f273e325d2ac4dd3515f05dc30656a Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 12:06:15 +0100 Subject: [PATCH 026/160] Cleanup scaffolding --- .../Room/RoomInfo/RoomInfoCoordinator.swift | 6 +- .../Coordinator/PollHistoryCoordinator.swift | 10 ++- .../MockPollHistoryScreenState.swift | 23 +++--- .../Room/PollHistory/PollHistoryModels.swift | 55 +++++---------- .../PollHistory/PollHistoryViewModel.swift | 15 +--- .../Room/PollHistory/View/PollHistory.swift | 70 +------------------ 6 files changed, 38 insertions(+), 141 deletions(-) diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index 6da39162a1..774e60f1ec 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -157,10 +157,6 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { return coordinator } - private func pollHistoryCoordinator() -> PollHistoryCoordinator { - return PollHistoryCoordinator(parameters: .init(promptType: .regular)) - } - private func showRoomDetails(with target: RoomInfoListTarget, animated: Bool) { switch target { case .integrations: @@ -180,7 +176,7 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { coordinator.start() push(coordinator: coordinator) case .pollHistory: - let coordinator = pollHistoryCoordinator() + let coordinator: PollHistoryCoordinator = .init(parameters: .init(mode: .active)) coordinator.start() push(coordinator: coordinator) default: diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift index 86b9149e7a..336f034eb1 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift @@ -18,7 +18,7 @@ import CommonKit import SwiftUI struct PollHistoryCoordinatorParameters { - let promptType: PollHistoryPromptType + let mode: PollHistoryMode } final class PollHistoryCoordinator: Coordinator, Presentable { @@ -31,12 +31,12 @@ final class PollHistoryCoordinator: Coordinator, Presentable { // Must be used only internally var childCoordinators: [Coordinator] = [] - var completion: ((PollHistoryViewModelResult) -> Void)? + var completion: (() -> Void)? init(parameters: PollHistoryCoordinatorParameters) { self.parameters = parameters - let viewModel = PollHistoryViewModel(promptType: parameters.promptType) + let viewModel = PollHistoryViewModel(mode: parameters.mode) let view = PollHistory(viewModel: viewModel.context) pollHistoryViewModel = viewModel pollHistoryHostingController = VectorHostingController(rootView: view) @@ -49,9 +49,7 @@ final class PollHistoryCoordinator: Coordinator, Presentable { func start() { MXLog.debug("[PollHistoryCoordinator] did start.") pollHistoryViewModel.completion = { [weak self] result in - guard let self = self else { return } - MXLog.debug("[PollHistoryCoordinator] PollHistoryViewModel did complete with result: \(result).") - self.completion?(result) + self?.completion?() } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift index 37d400e659..778cbdf129 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift @@ -23,32 +23,31 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable { // A case for each state you want to represent // with specific, minimal associated data that will allow you // mock that screen. - case promptType(PollHistoryPromptType) + case active + case past /// The associated screen var screenType: Any.Type { PollHistory.self } - /// A list of screen state definitions - static var allCases: [MockPollHistoryScreenState] { - // Each of the presence statuses - PollHistoryPromptType.allCases.map(MockPollHistoryScreenState.promptType) - } - /// Generate the view struct for the screen state. var screenView: ([Any], AnyView) { - let promptType: PollHistoryPromptType + let pollHistoryMode: PollHistoryMode + switch self { - case .promptType(let type): - promptType = type + case .active: + pollHistoryMode = .active + case .past: + pollHistoryMode = .past } - let viewModel = PollHistoryViewModel(promptType: promptType) + + let viewModel = PollHistoryViewModel(mode: pollHistoryMode) // can simulate service and viewModel actions here if needs be. return ( - [promptType, viewModel], + [pollHistoryMode, viewModel], AnyView(PollHistory(viewModel: viewModel.context) .addDependency(MockAvatarService.example)) ) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift index 7895fbcb21..2f0a0437f6 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift @@ -14,54 +14,31 @@ // limitations under the License. // -import Foundation - -// MARK: - Coordinator - -enum PollHistoryPromptType { - case regular - case upgrade -} +// MARK: View model -extension PollHistoryPromptType: Identifiable, CaseIterable { - var id: Self { self } - - var title: String { - switch self { - case .regular: - return VectorL10n.roomCreationMakePublicPromptTitle - case .upgrade: - return VectorL10n.roomDetailsHistorySectionPromptTitle - } - } - - var image: ImageAsset { - switch self { - case .regular: - return Asset.Images.appSymbol - case .upgrade: - return Asset.Images.keyVerificationSuccessShield - } - } +enum PollHistoryViewModelResult: Equatable { + #warning("e.g. show poll detail") } -// MARK: View model +// MARK: View -enum PollHistoryViewModelResult { - case accept - case cancel +enum PollHistoryMode { + case active + case past } -// MARK: View +struct PollHistoryViewBindings { + var mode: PollHistoryMode +} struct PollHistoryViewState: BindableState { - var promptType: PollHistoryPromptType - var count: Int + init(mode: PollHistoryMode) { + self.bindings = .init(mode: mode) + } + + var bindings: PollHistoryViewBindings } enum PollHistoryViewAction { - case incrementCount - case decrementCount - case accept - case cancel + #warning("e.g. show poll detail") } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift index c7a78bbe5d..6ce689d100 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift @@ -21,22 +21,13 @@ typealias PollHistoryViewModelType = StateStoreViewModel Void)? - init(promptType: PollHistoryPromptType, initialCount: Int = 0) { - super.init(initialViewState: PollHistoryViewState(promptType: promptType, count: 0)) + init(mode: PollHistoryMode) { + super.init(initialViewState: PollHistoryViewState(mode: mode)) } // MARK: - Public override func process(viewAction: PollHistoryViewAction) { - switch viewAction { - case .accept: - completion?(.accept) - case .cancel: - completion?(.cancel) - case .incrementCount: - state.count += 1 - case .decrementCount: - state.count -= 1 - } + } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 3ba8f1ed88..9fe93d4a5e 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -18,77 +18,13 @@ import SwiftUI struct PollHistory: View { @Environment(\.theme) private var theme - @Environment(\.horizontalSizeClass) private var horizontalSizeClass - - private var horizontalPadding: CGFloat { - horizontalSizeClass == .regular ? 50 : 16 - } @ObservedObject var viewModel: PollHistoryViewModel.Context var body: some View { - GeometryReader { geometry in - VStack { - ScrollView(showsIndicators: false) { - mainContent - .padding(.top, 50) - .padding(.horizontal, horizontalPadding) - } - - buttons - .padding(.horizontal, horizontalPadding) - .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 16) - } - } - .background(theme.colors.background.ignoresSafeArea()) - .accentColor(theme.colors.accent) - } - - /// The main content of the view to be shown in a scroll view. - var mainContent: some View { - VStack(spacing: 36) { - Text(viewModel.viewState.promptType.title) - .font(theme.fonts.title1B) - .foregroundColor(theme.colors.primaryContent) - .accessibilityIdentifier("title") - - Image(viewModel.viewState.promptType.image.name) - .resizable() - .scaledToFit() - .frame(width: 100) - .foregroundColor(theme.colors.accent) - - HStack { - Text("Counter: \(viewModel.viewState.count)") - .foregroundColor(theme.colors.primaryContent) - - Button("-") { - viewModel.send(viewAction: .decrementCount) - } - - Button("+") { - viewModel.send(viewAction: .incrementCount) - } - } - .font(theme.fonts.title3) - } - } - - /// The action buttons shown at the bottom of the view. - var buttons: some View { - VStack { - Button { viewModel.send(viewAction: .accept) } label: { - Text("Accept") - .font(theme.fonts.bodySB) - } - .buttonStyle(PrimaryActionButtonStyle()) - - Button { viewModel.send(viewAction: .cancel) } label: { - Text("Cancel") - .font(theme.fonts.body) - .padding(.vertical, 12) - } - } + Text("Hello world") + .background(theme.colors.background.ignoresSafeArea()) + .accentColor(theme.colors.accent) } } From dc654be9afba6b02e5d9ada1da16b742c6ff6697 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 12:22:47 +0100 Subject: [PATCH 027/160] Add UI skeleton --- .../Room/PollHistory/View/PollHistory.swift | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 9fe93d4a5e..49bf96209a 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -21,10 +21,36 @@ struct PollHistory: View { @ObservedObject var viewModel: PollHistoryViewModel.Context + var bindings: PollHistoryViewBindings { + viewModel.viewState.bindings + } + var body: some View { - Text("Hello world") - .background(theme.colors.background.ignoresSafeArea()) - .accentColor(theme.colors.accent) + VStack { + Picker("abc", selection: .constant(PollHistoryMode.active)) { + Text("Active Polls") + .tag(PollHistoryMode.active) + + Text("Past Polls") + .tag(PollHistoryMode.past) + } + .pickerStyle(SegmentedPickerStyle()) + + ScrollView { + ForEach(0..<10) { index in + Text("Active poll number: \(index)") + } + + Button { + #warning("handle action") + } label: { + Text("Load more polls") + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + .background(theme.colors.background.ignoresSafeArea()) + .accentColor(theme.colors.accent) } } From 8535f6c5cfee4a01f079a68fab20d500e50382ad Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 13:35:12 +0100 Subject: [PATCH 028/160] removing some changelog entries that are similiar --- changelog.d/2292.change | 1 - changelog.d/2419.bugfix | 1 - changelog.d/5437.bugfix | 1 - changelog.d/7263.bugfix | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 changelog.d/2292.change delete mode 100644 changelog.d/2419.bugfix delete mode 100644 changelog.d/5437.bugfix diff --git a/changelog.d/2292.change b/changelog.d/2292.change deleted file mode 100644 index b1d61e979d..0000000000 --- a/changelog.d/2292.change +++ /dev/null @@ -1 +0,0 @@ -Links are now in blue like on web and Android. \ No newline at end of file diff --git a/changelog.d/2419.bugfix b/changelog.d/2419.bugfix deleted file mode 100644 index 900d2135c8..0000000000 --- a/changelog.d/2419.bugfix +++ /dev/null @@ -1 +0,0 @@ -Hyperlinks are now blue and should now be distinguishable from unsent messages in encrypted rooms. \ No newline at end of file diff --git a/changelog.d/5437.bugfix b/changelog.d/5437.bugfix deleted file mode 100644 index 59c6185c50..0000000000 --- a/changelog.d/5437.bugfix +++ /dev/null @@ -1 +0,0 @@ -HTML links should now be displayed in default system blue. \ No newline at end of file diff --git a/changelog.d/7263.bugfix b/changelog.d/7263.bugfix index 061f8a6444..425e2dd95f 100644 --- a/changelog.d/7263.bugfix +++ b/changelog.d/7263.bugfix @@ -1 +1 @@ -Timeline's tag and hyperlinks match now in colour Android and Web. \ No newline at end of file +Timeline's links and hyperlinks match now the blue colour of Android and Web. \ No newline at end of file From 35468f85358d4b291e356e8ddcc13afb8e4d359f Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 14:33:50 +0100 Subject: [PATCH 029/160] adding an underline to the Re-request encryption keys message --- Riot/Utils/EventFormatter.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index eb793b8115..643696b2bf 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -359,7 +359,8 @@ - (NSAttributedString *)unsafeAttributedStringFromEvent:(MXEvent *)event attributes:@{ NSLinkAttributeName: linkActionString, NSForegroundColorAttributeName: self.sendingTextColor, - NSFontAttributeName: self.encryptedMessagesTextFont + NSFontAttributeName: self.encryptedMessagesTextFont, + NSUnderlineStyleAttributeName: [NSNumber numberWithInt:NSUnderlineStyleSingle] }]]; [attributedStringWithRerequestMessage appendAttributedString: From 0cc54b6e244fd3c9e592f8d7ae6bb1b6a6b4f486 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 15:45:16 +0100 Subject: [PATCH 030/160] Add SegmentedPicker --- .../Room/PollHistory/View/PollHistory.swift | 42 ++++++++----- .../PollHistory/View/SegmentedPicker.swift | 61 +++++++++++++++++++ 2 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 49bf96209a..4e76539b59 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -27,28 +27,38 @@ struct PollHistory: View { var body: some View { VStack { - Picker("abc", selection: .constant(PollHistoryMode.active)) { - Text("Active Polls") - .tag(PollHistoryMode.active) - - Text("Past Polls") - .tag(PollHistoryMode.past) + HStack { + SegmentedPicker( + segments: [ + ("Active Polls", PollHistoryMode.active), + ("Past Pools", PollHistoryMode.past) + ], + selection: $viewModel.mode, + interSegmentSpacing: 14 + ) + Spacer() } - .pickerStyle(SegmentedPickerStyle()) ScrollView { - ForEach(0..<10) { index in - Text("Active poll number: \(index)") - } - - Button { - #warning("handle action") - } label: { - Text("Load more polls") + LazyVStack(spacing: 32) { + ForEach(0..<10) { index in + Text("Active poll number: \(index)") + } + .frame(maxWidth: .infinity, alignment: .leading) + + Button { + #warning("handle action") + } label: { + Text("Load more polls") + } + .frame(maxWidth: .infinity, alignment: .leading) } + .padding(.top, 32) } - .frame(maxWidth: .infinity, maxHeight: .infinity) } + .padding(.horizontal, 16) + .padding(.vertical, 32) + .frame(maxWidth: .infinity, maxHeight: .infinity) .background(theme.colors.background.ignoresSafeArea()) .accentColor(theme.colors.accent) } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift new file mode 100644 index 0000000000..d60388ad68 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift @@ -0,0 +1,61 @@ +// +// Copyright 2023 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 SwiftUI + +struct SegmentedPicker: View { + private let segments: [(String, Tag)] + private let selection: Binding + private let interSegmentSpacing: CGFloat + + @Environment(\.theme) private var theme + + init(segments: [(String, Tag)], selection: Binding, interSegmentSpacing: CGFloat) { + self.segments = segments + self.selection = selection + self.interSegmentSpacing = interSegmentSpacing + } + + var body: some View { + HStack(spacing: interSegmentSpacing) { + ForEach(segments, id: \.1) { text, tag in + let isSelectedSegment = tag == selection.wrappedValue + + Button { + selection.wrappedValue = tag + } label: { + Text(text) + .font(isSelectedSegment ? theme.fonts.headline : theme.fonts.body) + .underline(isSelectedSegment) + } + .accentColor(isSelectedSegment ? theme.colors.accent : theme.colors.primaryContent) + } + } + } +} + +struct SegmentedPicker_Previews: PreviewProvider { + static var previews: some View { + SegmentedPicker( + segments: [ + ("Segment 1", "1"), + ("Segment 2", "2") + ], + selection: .constant("1"), + interSegmentSpacing: 14 + ) + } +} From 8ba0fea0268e483ddbc2e32e907838da19248a66 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Thu, 12 Jan 2023 15:55:06 +0100 Subject: [PATCH 031/160] Remove strong references on audio players used for voicebroadcast --- .../Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift index 04a4ac7ec5..24ff08d0d1 100644 --- a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift +++ b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift @@ -94,7 +94,7 @@ import MediaPlayer private override init() { audioPlayers = NSMapTable(valueOptions: .weakMemory) audioRecorders = NSHashTable(options: .weakMemory) - nowPlayingInfoDelegates = NSMapTable(valueOptions: .weakMemory) + nowPlayingInfoDelegates = NSMapTable(keyOptions: .weakMemory, valueOptions: .weakMemory) activeAudioPlayers = Set() super.init() From e62ef380d71ece10927e79021b0c9511cff4529c Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Thu, 12 Jan 2023 16:00:43 +0100 Subject: [PATCH 032/160] Fix Towncrier file --- changelog.d/pr-7257.bugfix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/pr-7257.bugfix b/changelog.d/pr-7257.bugfix index c83bd783df..8a41b21c87 100644 --- a/changelog.d/pr-7257.bugfix +++ b/changelog.d/pr-7257.bugfix @@ -1 +1 @@ -Voice Broacast: The Now Playing Info Center now displays a voice broadcast instead of a voice message when a user is listening to a voice broadcast. +Voice Broadcast: The Now Playing Info Center now displays a voice broadcast instead of a voice message when a user is listening to a voice broadcast. From ffe7a3e969773616ed5eec1657b67d0219cabb0f Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 16:20:38 +0100 Subject: [PATCH 033/160] added the "links" color from figma --- DesignKit/Source/ColorValues.swift | 2 ++ DesignKit/Source/Colors.swift | 4 ++++ DesignKit/Source/ColorsSwiftUI.swift | 7 +++++-- DesignKit/Source/ColorsUIkit.swift | 3 +++ DesignKit/Variants/Colors/Dark/DarkColors.swift | 1 + DesignKit/Variants/Colors/Light/LightColors.swift | 1 + 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/DesignKit/Source/ColorValues.swift b/DesignKit/Source/ColorValues.swift index 338d1cfe88..4e967ab05e 100644 --- a/DesignKit/Source/ColorValues.swift +++ b/DesignKit/Source/ColorValues.swift @@ -48,5 +48,7 @@ public struct ColorValues: Colors { public let ems: UIColor + public let links: UIColor + public let namesAndAvatars: [UIColor] } diff --git a/DesignKit/Source/Colors.swift b/DesignKit/Source/Colors.swift index bf3e9abd39..bea9b07066 100644 --- a/DesignKit/Source/Colors.swift +++ b/DesignKit/Source/Colors.swift @@ -67,6 +67,10 @@ public protocol Colors { /// Global color: The EMS brand's purple colour. var ems: ColorType { get } + /// - Links + /// - Hyperlinks + var links: ColorType { get } + /// - Names in chat timeline /// - Avatars default states that include first name letter var namesAndAvatars: [ColorType] { get } diff --git a/DesignKit/Source/ColorsSwiftUI.swift b/DesignKit/Source/ColorsSwiftUI.swift index ea3ca6779e..bb25d025f4 100644 --- a/DesignKit/Source/ColorsSwiftUI.swift +++ b/DesignKit/Source/ColorsSwiftUI.swift @@ -21,7 +21,7 @@ import SwiftUI Struct for holding colors for use in SwiftUI. */ public struct ColorSwiftUI: Colors { - + public let accent: Color public let alert: Color @@ -48,8 +48,10 @@ public struct ColorSwiftUI: Colors { public var ems: Color - public let namesAndAvatars: [Color] + public let links: Color + public let namesAndAvatars: [Color] + init(values: ColorValues) { accent = Color(values.accent) alert = Color(values.alert) @@ -64,6 +66,7 @@ public struct ColorSwiftUI: Colors { navigation = Color(values.navigation) background = Color(values.background) ems = Color(values.ems) + links = Color(values.links) namesAndAvatars = values.namesAndAvatars.map({ Color($0) }) } } diff --git a/DesignKit/Source/ColorsUIkit.swift b/DesignKit/Source/ColorsUIkit.swift index 3add385c36..5ca20ab0b6 100644 --- a/DesignKit/Source/ColorsUIkit.swift +++ b/DesignKit/Source/ColorsUIkit.swift @@ -45,6 +45,8 @@ import UIKit public let navigation: UIColor public let background: UIColor + + public let links: UIColor public let namesAndAvatars: [UIColor] @@ -61,6 +63,7 @@ import UIKit tile = values.tile navigation = values.navigation background = values.background + links = values.links namesAndAvatars = values.namesAndAvatars } } diff --git a/DesignKit/Variants/Colors/Dark/DarkColors.swift b/DesignKit/Variants/Colors/Dark/DarkColors.swift index 88bd12ff37..21394475c8 100644 --- a/DesignKit/Variants/Colors/Dark/DarkColors.swift +++ b/DesignKit/Variants/Colors/Dark/DarkColors.swift @@ -34,6 +34,7 @@ public class DarkColors { navigation: UIColor(rgb:0x21262C), background: UIColor(rgb:0x15191E), ems: UIColor(rgb: 0x7E69FF), + links: UIColor(rgb: 0x0086E6), namesAndAvatars: [ UIColor(rgb:0x368BD6), UIColor(rgb:0xAC3BA8), diff --git a/DesignKit/Variants/Colors/Light/LightColors.swift b/DesignKit/Variants/Colors/Light/LightColors.swift index 93cb3eadba..f8fa0e8e3b 100644 --- a/DesignKit/Variants/Colors/Light/LightColors.swift +++ b/DesignKit/Variants/Colors/Light/LightColors.swift @@ -35,6 +35,7 @@ public class LightColors { navigation: UIColor(rgb:0xF4F6FA), background: UIColor(rgb:0xFFFFFF), ems: UIColor(rgb: 0x7E69FF), + links: UIColor(rgb: 0x0086E6), namesAndAvatars: [ UIColor(rgb:0x368BD6), UIColor(rgb:0xAC3BA8), From 50cf98e692c76baf38bb9016f58c9aa2327c2b1c Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 16:45:43 +0100 Subject: [PATCH 034/160] added the links color wherever possible --- .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.h | 6 ++++++ .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 3 ++- .../Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift | 2 ++ Riot/Utils/EventFormatter.m | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.h b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.h index 776b799278..999da70349 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.h +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.h @@ -366,6 +366,12 @@ typedef enum : NSUInteger { */ @property (nonatomic) UIColor *sendingTextColor; +/** + Color used to display links and hyperlinks contentt. + Default is [UIColor linkColor]. + */ +@property (nonatomic) UIColor *linksColor; + /** Color used to display error text. Default is red. diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index 70c36ecd58..cee8dccecc 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -89,6 +89,7 @@ - (instancetype)initWithMatrixSession:(MXSession *)matrixSession _encryptingTextColor = [UIColor lightGrayColor]; _sendingTextColor = [UIColor lightGrayColor]; _errorTextColor = [UIColor redColor]; + _linksColor = [UIColor linkColor]; _htmlBlockquoteBorderColor = [MXKTools colorWithRGBValue:0xDDDDDD]; _defaultTextFont = [UIFont systemFontOfSize:14]; @@ -1749,7 +1750,7 @@ - (NSAttributedString*)renderString:(NSString*)string forEvent:(MXEvent*)event if (url.URL) { [str addAttribute:NSLinkAttributeName value:url.URL range:matchRange]; - [str addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:matchRange]; + [str addAttribute:NSForegroundColorAttributeName value:self.linksColor range:matchRange]; } } } diff --git a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift index 0fdfb16708..013602843c 100644 --- a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift +++ b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift @@ -44,6 +44,7 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp private var hostingViewController: VectorHostingController! private var wysiwygViewModel = WysiwygComposerViewModel( textColor: ThemeService.shared().theme.colors.primaryContent, + linkColor: ThemeService.shared().theme.colors.links, codeBackgroundColor: ThemeService.shared().theme.selectedBackgroundColor ) private var viewModel: ComposerViewModelProtocol! @@ -298,6 +299,7 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp private func update(theme: Theme) { hostingViewController.view.backgroundColor = theme.colors.background wysiwygViewModel.textColor = theme.colors.primaryContent + wysiwygViewModel.linkColor = theme.colors.links wysiwygViewModel.codeBackgroundColor = theme.selectedBackgroundColor } diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 643696b2bf..079a00f77a 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -486,6 +486,7 @@ - (instancetype)initWithMatrixSession:(MXSession *)matrixSession self.bingTextColor = ThemeService.shared.theme.noticeColor; self.encryptingTextColor = ThemeService.shared.theme.textPrimaryColor; self.sendingTextColor = ThemeService.shared.theme.textPrimaryColor; + self.linksColor = ThemeService.shared.theme.colors.links; self.errorTextColor = ThemeService.shared.theme.textPrimaryColor; self.showEditionMention = YES; self.editionMentionTextColor = ThemeService.shared.theme.textSecondaryColor; From cf6d64a974e6dbc5629ddd9fd7bcbd5d0768c44a Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 16:52:11 +0100 Subject: [PATCH 035/160] Add PollListItem --- .../Room/PollHistory/View/PollHistory.swift | 8 ++- .../Room/PollHistory/View/PollListItem.swift | 56 +++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 4e76539b59..f3311b73fe 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -38,11 +38,12 @@ struct PollHistory: View { ) Spacer() } + .padding(.horizontal, 16) ScrollView { LazyVStack(spacing: 32) { ForEach(0..<10) { index in - Text("Active poll number: \(index)") + PollListItem(data: .init(startDate: Date(), question: "Poll question number \(index)")) } .frame(maxWidth: .infinity, alignment: .leading) @@ -53,11 +54,11 @@ struct PollHistory: View { } .frame(maxWidth: .infinity, alignment: .leading) } + .padding(.horizontal, 16) .padding(.top, 32) } } - .padding(.horizontal, 16) - .padding(.vertical, 32) + .padding(.top, 32) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(theme.colors.background.ignoresSafeArea()) .accentColor(theme.colors.accent) @@ -68,6 +69,7 @@ struct PollHistory: View { struct PollHistory_Previews: PreviewProvider { static let stateRenderer = MockPollHistoryScreenState.stateRenderer + static var previews: some View { stateRenderer.screenGroup() } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift new file mode 100644 index 0000000000..984cb2b685 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -0,0 +1,56 @@ +// +// Copyright 2023 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 SwiftUI + +struct PollListData { + let startDate: Date + let question: String +} + +struct PollListItem: View { + @Environment(\.theme) private var theme + + private let data: PollListData + + init(data: PollListData) { + self.data = data + } + + var body: some View { + VStack(alignment: .leading, spacing: 12) { + Text(data.startDate.description) + .foregroundColor(theme.colors.tertiaryContent) + .font(theme.fonts.caption1) + + HStack(spacing: 8) { + Image(uiImage: Asset.Images.pollHistory.image) + .resizable() + .frame(width: 16, height: 16) + + Text(data.question) + .foregroundColor(theme.colors.primaryContent) + .font(theme.fonts.body) + } + } + } +} + +struct PollListItem_Previews: PreviewProvider { + static var previews: some View { + PollListItem(data: .init(startDate: .init(), question: "Did you like this poll?")) + } +} From caf69c1ad24890f6180de3bf4e3f454762b57979 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 17:07:02 +0100 Subject: [PATCH 036/160] removing useless ios 13 checks --- Riot/Managers/Theme/Themes/DarkTheme.swift | 10 ++-------- Riot/Managers/Theme/Themes/DefaultTheme.swift | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Riot/Managers/Theme/Themes/DarkTheme.swift b/Riot/Managers/Theme/Themes/DarkTheme.swift index 9dbba85c7d..269b387fa0 100644 --- a/Riot/Managers/Theme/Themes/DarkTheme.swift +++ b/Riot/Managers/Theme/Themes/DarkTheme.swift @@ -168,14 +168,8 @@ class DarkTheme: NSObject, Theme { searchBar.backgroundImage = UIImage() // Remove top and bottom shadow searchBar.tintColor = self.tintColor - if #available(iOS 13.0, *) { - searchBar.searchTextField.backgroundColor = self.searchBackgroundColor - searchBar.searchTextField.textColor = self.searchPlaceholderColor - } else { - if let searchBarTextField = searchBar.vc_searchTextField { - searchBarTextField.textColor = self.searchPlaceholderColor - } - } + searchBar.searchTextField.backgroundColor = self.searchBackgroundColor + searchBar.searchTextField.textColor = self.searchPlaceholderColor } func applyStyle(onTextField texField: UITextField) { diff --git a/Riot/Managers/Theme/Themes/DefaultTheme.swift b/Riot/Managers/Theme/Themes/DefaultTheme.swift index d5d309bf30..97c7019751 100644 --- a/Riot/Managers/Theme/Themes/DefaultTheme.swift +++ b/Riot/Managers/Theme/Themes/DefaultTheme.swift @@ -177,14 +177,8 @@ class DefaultTheme: NSObject, Theme { return } - if #available(iOS 13.0, *) { - searchBar.searchTextField.backgroundColor = self.searchBackgroundColor - searchBar.searchTextField.textColor = self.searchPlaceholderColor - } else { - if let searchBarTextField = searchBar.vc_searchTextField { - searchBarTextField.textColor = self.searchPlaceholderColor - } - } + searchBar.searchTextField.backgroundColor = self.searchBackgroundColor + searchBar.searchTextField.textColor = self.searchPlaceholderColor } func applyStyle(onTextField texField: UITextField) { From e4a930a64d6eca32c05da5aaa545cd218eb892f7 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 17:09:44 +0100 Subject: [PATCH 037/160] Add localizations --- Riot/Assets/en.lproj/Vector.strings | 6 ++++++ Riot/Generated/Strings.swift | 12 ++++++++++++ .../Room/PollHistory/PollHistoryModels.swift | 2 +- .../Room/PollHistory/View/PollHistory.swift | 17 +++++++++++++---- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index b87d35a783..1650228d4f 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2292,6 +2292,12 @@ Tap the + to start adding people."; "space_detail_nav_title" = "Space detail"; "space_invite_nav_title" = "Space invite"; +// MARK: - Polls history + +"poll_history_title" = "Poll history"; +"poll_history_active_segment_title" = "Active polls"; +"poll_history_past_segment_title" = "Past polls"; + // MARK: - Polls "poll_edit_form_create_poll" = "Create poll"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 36fd6b67a6..dea531fc96 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -4839,6 +4839,18 @@ public class VectorL10n: NSObject { public static var pollEditFormUpdateFailureTitle: String { return VectorL10n.tr("Vector", "poll_edit_form_update_failure_title") } + /// Active polls + public static var pollHistoryActiveSegmentTitle: String { + return VectorL10n.tr("Vector", "poll_history_active_segment_title") + } + /// Past polls + public static var pollHistoryPastSegmentTitle: String { + return VectorL10n.tr("Vector", "poll_history_past_segment_title") + } + /// Poll history + public static var pollHistoryTitle: String { + return VectorL10n.tr("Vector", "poll_history_title") + } /// Due to decryption errors, some votes may not be counted public static var pollTimelineDecryptionError: String { return VectorL10n.tr("Vector", "poll_timeline_decryption_error") diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift index 2f0a0437f6..a1bf4f3434 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift @@ -22,7 +22,7 @@ enum PollHistoryViewModelResult: Equatable { // MARK: View -enum PollHistoryMode { +enum PollHistoryMode: CaseIterable { case active case past } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index f3311b73fe..6d46c05e99 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -29,10 +29,7 @@ struct PollHistory: View { VStack { HStack { SegmentedPicker( - segments: [ - ("Active Polls", PollHistoryMode.active), - ("Past Pools", PollHistoryMode.past) - ], + segments: PollHistoryMode.allCases.map { ($0.segmentTitle, $0) }, selection: $viewModel.mode, interSegmentSpacing: 14 ) @@ -62,6 +59,18 @@ struct PollHistory: View { .frame(maxWidth: .infinity, maxHeight: .infinity) .background(theme.colors.background.ignoresSafeArea()) .accentColor(theme.colors.accent) + .navigationTitle(VectorL10n.pollHistoryTitle) + } +} + +extension PollHistoryMode { + var segmentTitle: String { + switch self { + case .active: + return VectorL10n.pollHistoryActiveSegmentTitle + case .past: + return VectorL10n.pollHistoryPastSegmentTitle + } } } From 1b9a26c3ccfcca2955182d00f37a51422ba7617c Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 12 Jan 2023 17:54:44 +0100 Subject: [PATCH 038/160] replaced UIColor link with ThemeService links color everywhere it was used, and included the ThemeService in NSE and SiriIntents --- .../MatrixKit/Utils/EventFormatter/HTMLFormatter.swift | 2 +- Riot/Modules/MatrixKit/Utils/MXKTools.m | 6 +++--- RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h | 2 ++ RiotNSE/target.yml | 2 ++ SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h | 1 + SiriIntents/target.yml | 2 ++ 6 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift b/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift index e65f07ce19..6c7e43a90a 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/HTMLFormatter.swift @@ -51,7 +51,7 @@ class HTMLFormatter: NSObject { DTDefaultFontName: font.fontName, DTDefaultFontSize: font.pointSize, DTDefaultLinkDecoration: false, - DTDefaultLinkColor: UIColor.link, + DTDefaultLinkColor: ThemeService.shared().theme.colors.links, DTWillFlushBlockCallBack: sanitizeCallback ] options.merge(extraOptions) { (_, new) in new } diff --git a/Riot/Modules/MatrixKit/Utils/MXKTools.m b/Riot/Modules/MatrixKit/Utils/MXKTools.m index fdb7f51f89..9ba006a891 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKTools.m +++ b/Riot/Modules/MatrixKit/Utils/MXKTools.m @@ -1052,7 +1052,7 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable NSURLComponents *url = [[NSURLComponents new] initWithURL:matchUrl resolvingAgainstBaseURL:NO]; if (url.URL) { - [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:matchRange]; + [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.colors.links range:matchRange]; } } } @@ -1103,7 +1103,7 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable if (NSIntersectionRange(match.range, linkMatch.range).length == match.range.length) { // but before we set the right color - [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:linkMatch.range]; + [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.colors.links range:linkMatch.range]; hasAlreadyLink = YES; break; } @@ -1118,7 +1118,7 @@ + (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutable NSString *link = [mutableAttributedString.string substringWithRange:match.range]; link = [link stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; [mutableAttributedString addAttribute:NSLinkAttributeName value:link range:match.range]; - [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor linkColor] range:match.range]; + [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.colors.links range:match.range]; } }]; } diff --git a/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h b/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h index 6409af92f6..5db20c7452 100644 --- a/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h +++ b/RiotNSE/SupportingFiles/RiotNSE-Bridging-Header.h @@ -23,4 +23,6 @@ #import "BuildInfo.h" +#import "ThemeService.h" + #endif /* RiotNSE_Bridging_Header_h */ diff --git a/RiotNSE/target.yml b/RiotNSE/target.yml index 415f8447aa..ae27022c32 100644 --- a/RiotNSE/target.yml +++ b/RiotNSE/target.yml @@ -78,3 +78,5 @@ targets: - "**/*.md" # excludes all files with the .md extension - path: ../Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyleIdentifier.swift - path: ../Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/MatrixSDK + - path: ../Riot/Managers/Theme + - path: ../Riot/Categories/UIColor.swift diff --git a/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h b/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h index ca6d81962e..01aeb20d14 100644 --- a/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h +++ b/SiriIntents/SupportingFiles/SiriIntents-Bridging-Header.h @@ -16,3 +16,4 @@ #import "MatrixKit-Bridging-Header.h" #import "BuildInfo.h" +#import "ThemeService.h" diff --git a/SiriIntents/target.yml b/SiriIntents/target.yml index 5b63a95b34..324497cf3c 100644 --- a/SiriIntents/target.yml +++ b/SiriIntents/target.yml @@ -66,3 +66,5 @@ targets: - "**/*.md" # excludes all files with the .md extension - path: ../Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyleIdentifier.swift - path: ../Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/MatrixSDK + - path: ../Riot/Managers/Theme + - path: ../Riot/Categories/UIColor.swift From 84f27cc04c5865fc0e67230b7a1f910612f72a0a Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 17:59:23 +0100 Subject: [PATCH 039/160] Add poll history service --- .../Coordinator/PollHistoryCoordinator.swift | 3 +- .../MockPollHistoryScreenState.swift | 2 +- .../Room/PollHistory/PollHistoryModels.swift | 3 +- .../PollHistory/PollHistoryViewModel.swift | 31 +++++++++++++++-- .../MatrixSDK/PollHistoryService.swift | 24 ++++++++++++++ .../Service/Mock/MockPollHistoryService.swift | 27 +++++++++++++++ .../Service/PollHistoryServiceProtocol.swift | 19 +++++++++++ .../Room/PollHistory/View/PollHistory.swift | 11 +++++-- .../Room/PollHistory/View/PollListItem.swift | 33 +++++++++++++++---- 9 files changed, 138 insertions(+), 15 deletions(-) create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/Service/MatrixSDK/PollHistoryService.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift create mode 100644 RiotSwiftUI/Modules/Room/PollHistory/Service/PollHistoryServiceProtocol.swift diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift index 336f034eb1..0cdf3629a4 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift @@ -36,7 +36,8 @@ final class PollHistoryCoordinator: Coordinator, Presentable { init(parameters: PollHistoryCoordinatorParameters) { self.parameters = parameters - let viewModel = PollHistoryViewModel(mode: parameters.mode) + #warning("replace with the real service after that it's done") + let viewModel = PollHistoryViewModel(mode: parameters.mode, pollService: MockPollHistoryService()) let view = PollHistory(viewModel: viewModel.context) pollHistoryViewModel = viewModel pollHistoryHostingController = VectorHostingController(rootView: view) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift index 778cbdf129..e85384c4be 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift @@ -42,7 +42,7 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable { pollHistoryMode = .past } - let viewModel = PollHistoryViewModel(mode: pollHistoryMode) + let viewModel = PollHistoryViewModel(mode: pollHistoryMode, pollService: MockPollHistoryService()) // can simulate service and viewModel actions here if needs be. diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift index a1bf4f3434..c8960add0b 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift @@ -37,8 +37,9 @@ struct PollHistoryViewState: BindableState { } var bindings: PollHistoryViewBindings + var polls: [PollListData] = [] } enum PollHistoryViewAction { - #warning("e.g. show poll detail") + case viewAppeared } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift index 6ce689d100..0addb8ef99 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift @@ -18,16 +18,43 @@ import SwiftUI typealias PollHistoryViewModelType = StateStoreViewModel -class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModelProtocol { +final class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModelProtocol { + private let pollService: PollHistoryServiceProtocol + private var fetchingTask: Task? { + didSet { + oldValue?.cancel() + } + } + var completion: ((PollHistoryViewModelResult) -> Void)? - init(mode: PollHistoryMode) { + init(mode: PollHistoryMode, pollService: PollHistoryServiceProtocol) { + self.pollService = pollService super.init(initialViewState: PollHistoryViewState(mode: mode)) } // MARK: - Public override func process(viewAction: PollHistoryViewAction) { + switch viewAction { + case .viewAppeared: + fetchingTask = fetchPolls() + } + } +} +private extension PollHistoryViewModel { + func fetchPolls() -> Task { + Task { + let polls = try await pollService.fetchHistory() + + guard Task.isCancelled == false else { + return + } + + await MainActor.run { + state.polls = polls + } + } } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Service/MatrixSDK/PollHistoryService.swift b/RiotSwiftUI/Modules/Room/PollHistory/Service/MatrixSDK/PollHistoryService.swift new file mode 100644 index 0000000000..a2dcf256ae --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/Service/MatrixSDK/PollHistoryService.swift @@ -0,0 +1,24 @@ +// +// Copyright 2023 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 MatrixSDK +import Foundation + +final class PollHistoryService: PollHistoryServiceProtocol { + func fetchHistory() async throws -> [PollListData] { + [] + } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift new file mode 100644 index 0000000000..62015b8a3b --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift @@ -0,0 +1,27 @@ +// +// Copyright 2023 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. +// + +final class MockPollHistoryService: PollHistoryServiceProtocol { + func fetchHistory() async throws -> [PollListData] { + (1..<10) + .map { index in + PollListData(startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), question: "Do you like the poll number \(index)?") + } + .sorted { poll1, poll2 in + poll1.startDate > poll2.startDate + } + } +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Service/PollHistoryServiceProtocol.swift b/RiotSwiftUI/Modules/Room/PollHistory/Service/PollHistoryServiceProtocol.swift new file mode 100644 index 0000000000..4bb9b43b53 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/PollHistory/Service/PollHistoryServiceProtocol.swift @@ -0,0 +1,19 @@ +// +// Copyright 2023 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. +// + +protocol PollHistoryServiceProtocol { + func fetchHistory() async throws -> [PollListData] +} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 6d46c05e99..9de37b9c0b 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -39,8 +39,10 @@ struct PollHistory: View { ScrollView { LazyVStack(spacing: 32) { - ForEach(0..<10) { index in - PollListItem(data: .init(startDate: Date(), question: "Poll question number \(index)")) + let enumeratedPolls = Array(viewModel.viewState.polls.enumerated()) + + ForEach(enumeratedPolls, id: \.offset) { _, pollData in + PollListItem(pollData: pollData) } .frame(maxWidth: .infinity, alignment: .leading) @@ -60,10 +62,13 @@ struct PollHistory: View { .background(theme.colors.background.ignoresSafeArea()) .accentColor(theme.colors.accent) .navigationTitle(VectorL10n.pollHistoryTitle) + .onAppear { + viewModel.send(viewAction: .viewAppeared) + } } } -extension PollHistoryMode { +private extension PollHistoryMode { var segmentTitle: String { switch self { case .active: diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index 984cb2b685..dff98ba0a7 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -24,33 +24,52 @@ struct PollListData { struct PollListItem: View { @Environment(\.theme) private var theme - private let data: PollListData + private let pollData: PollListData - init(data: PollListData) { - self.data = data + init(pollData: PollListData) { + self.pollData = pollData } var body: some View { VStack(alignment: .leading, spacing: 12) { - Text(data.startDate.description) + Text(pollData.formattedDate) .foregroundColor(theme.colors.tertiaryContent) .font(theme.fonts.caption1) - HStack(spacing: 8) { + HStack(alignment: .firstTextBaseline, spacing: 8) { Image(uiImage: Asset.Images.pollHistory.image) .resizable() .frame(width: 16, height: 16) - Text(data.question) + Text(pollData.question) .foregroundColor(theme.colors.primaryContent) .font(theme.fonts.body) + .lineLimit(2) } } } } +private extension PollListData { + var formattedDate: String { + DateFormatter.shortDateFormatter.string(from: startDate) + } +} + +private extension DateFormatter { + static let shortDateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.timeStyle = .none + formatter.dateStyle = .short + formatter.timeZone = .init(identifier: "UTC") + return formatter + }() +} + +// MARK: - Previews + struct PollListItem_Previews: PreviewProvider { static var previews: some View { - PollListItem(data: .init(startDate: .init(), question: "Did you like this poll?")) + PollListItem(pollData: .init(startDate: .init(), question: "Did you like this poll?")) } } From d2c1cb6f7b01902471bef56e756264f1a3f7d30a Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 12 Jan 2023 18:25:06 +0100 Subject: [PATCH 040/160] Handle empty poll list case --- Riot/Assets/en.lproj/Vector.strings | 2 + Riot/Generated/Strings.swift | 8 +++ .../MockPollHistoryScreenState.swift | 11 +++- .../Service/Mock/MockPollHistoryService.swift | 16 +++--- .../Room/PollHistory/View/PollHistory.swift | 52 ++++++++++++------- 5 files changed, 63 insertions(+), 26 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 1650228d4f..62f25672c9 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2297,6 +2297,8 @@ Tap the + to start adding people."; "poll_history_title" = "Poll history"; "poll_history_active_segment_title" = "Active polls"; "poll_history_past_segment_title" = "Past polls"; +"poll_history_no_active_poll_text" = "There are no active polls in this room"; +"poll_history_no_past_poll_text" = "There are no past polls in this room"; // MARK: - Polls diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index dea531fc96..e0be60ceee 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -4843,6 +4843,14 @@ public class VectorL10n: NSObject { public static var pollHistoryActiveSegmentTitle: String { return VectorL10n.tr("Vector", "poll_history_active_segment_title") } + /// There are no active polls in this room + public static var pollHistoryNoActivePollText: String { + return VectorL10n.tr("Vector", "poll_history_no_active_poll_text") + } + /// There are no past polls in this room + public static var pollHistoryNoPastPollText: String { + return VectorL10n.tr("Vector", "poll_history_no_past_poll_text") + } /// Past polls public static var pollHistoryPastSegmentTitle: String { return VectorL10n.tr("Vector", "poll_history_past_segment_title") diff --git a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift index e85384c4be..08b33293bd 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift @@ -25,6 +25,8 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable { // mock that screen. case active case past + case activeEmpty + case pastEmpty /// The associated screen var screenType: Any.Type { @@ -34,15 +36,22 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable { /// Generate the view struct for the screen state. var screenView: ([Any], AnyView) { let pollHistoryMode: PollHistoryMode + let pollService = MockPollHistoryService() switch self { case .active: pollHistoryMode = .active case .past: pollHistoryMode = .past + case .activeEmpty: + pollHistoryMode = .active + pollService.pollListData = [] + case .pastEmpty: + pollHistoryMode = .past + pollService.pollListData = [] } - let viewModel = PollHistoryViewModel(mode: pollHistoryMode, pollService: MockPollHistoryService()) + let viewModel = PollHistoryViewModel(mode: pollHistoryMode, pollService: pollService) // can simulate service and viewModel actions here if needs be. diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift index 62015b8a3b..67d3121816 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift @@ -15,13 +15,15 @@ // final class MockPollHistoryService: PollHistoryServiceProtocol { + var pollListData: [PollListData] = (1..<10) + .map { index in + PollListData(startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), question: "Do you like the poll number \(index)?") + } + .sorted { poll1, poll2 in + poll1.startDate > poll2.startDate + } + func fetchHistory() async throws -> [PollListData] { - (1..<10) - .map { index in - PollListData(startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), question: "Do you like the poll number \(index)?") - } - .sorted { poll1, poll2 in - poll1.startDate > poll2.startDate - } + pollListData } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 9de37b9c0b..fa000b9014 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -37,24 +37,10 @@ struct PollHistory: View { } .padding(.horizontal, 16) - ScrollView { - LazyVStack(spacing: 32) { - let enumeratedPolls = Array(viewModel.viewState.polls.enumerated()) - - ForEach(enumeratedPolls, id: \.offset) { _, pollData in - PollListItem(pollData: pollData) - } - .frame(maxWidth: .infinity, alignment: .leading) - - Button { - #warning("handle action") - } label: { - Text("Load more polls") - } - .frame(maxWidth: .infinity, alignment: .leading) - } - .padding(.horizontal, 16) - .padding(.top, 32) + if viewModel.viewState.polls.isEmpty { + noPollsView + } else { + pollListView } } .padding(.top, 32) @@ -66,6 +52,36 @@ struct PollHistory: View { viewModel.send(viewAction: .viewAppeared) } } + + private var pollListView: some View { + ScrollView { + LazyVStack(spacing: 32) { + let enumeratedPolls = Array(viewModel.viewState.polls.enumerated()) + + ForEach(enumeratedPolls, id: \.offset) { _, pollData in + PollListItem(pollData: pollData) + } + .frame(maxWidth: .infinity, alignment: .leading) + + Button { + #warning("handle action") + } label: { + Text("Load more polls") + } + .frame(maxWidth: .infinity, alignment: .leading) + } + .padding(.top, 32) + .padding(.horizontal, 16) + } + } + + private var noPollsView: some View { + Text(viewModel.mode == .active ? VectorL10n.pollHistoryNoActivePollText : VectorL10n.pollHistoryNoPastPollText) + .font(theme.fonts.body) + .foregroundColor(theme.colors.secondaryContent) + .frame(maxHeight: .infinity) + .padding(.horizontal, 16) + } } private extension PollHistoryMode { From 3d8d6e10bc99c751eef0b5f104d2fd9ac121e5ed Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Thu, 12 Jan 2023 18:08:37 +0100 Subject: [PATCH 041/160] Fix how is resent a voice broadcast chunk --- .../MatrixKit/Models/Room/MXKRoomDataSource.m | 30 ++++++++++++++++--- changelog.d/7261.bugfix | 1 + 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 changelog.d/7261.bugfix diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m index d8f55bf149..d89262a0ec 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m @@ -2185,10 +2185,32 @@ - (void)resendEventWithEventId:(NSString *)eventId success:(void (^)(NSString *) [self removeEventWithEventId:eventId]; if (event.isVoiceMessage) { - NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioDuration]; - NSArray *samples = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioWaveform]; - - [self sendVoiceMessage:localFileURL mimeType:mimetype duration:duration.doubleValue samples:samples success:success failure:failure]; + // Check if it is an actual voice message or a voicebroadcast chunk + if (event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] != nil) { + // VoiceBroadcast chunk + NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioDuration]; + NSDictionary* additionalContentParams = @{ + kMXEventRelationRelatesToKey: event.content[kMXEventRelationRelatesToKey], + VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType: event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] + }; + [_room sendVoiceMessage:localFileURL + additionalContentParams:additionalContentParams + mimeType:mimetype + duration:duration.doubleValue + samples:nil + threadId:self.threadId + localEcho:nil + success:success + failure:failure + keepActualFilename:false]; + + } else { + // Voice message + NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioDuration]; + NSArray *samples = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioWaveform]; + + [self sendVoiceMessage:localFileURL mimeType:mimetype duration:duration.doubleValue samples:samples success:success failure:failure]; + } } else { [self sendAudioFile:localFileURL mimeType:mimetype success:success failure:failure]; } diff --git a/changelog.d/7261.bugfix b/changelog.d/7261.bugfix new file mode 100644 index 0000000000..3594c59803 --- /dev/null +++ b/changelog.d/7261.bugfix @@ -0,0 +1 @@ +Voice Broadcast: VoiceBroadcast chunks are no longer resent as voice messages From 6a9fb090fc2038bef662834592291fc2a2167317 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 10:49:43 +0100 Subject: [PATCH 042/160] Add ui tests --- .../Modules/Common/Mock/MockAppScreens.swift | 3 +- .../Test/UI/PollHistoryUITests.swift | 30 ++++++------ .../Test/Unit/PollHistoryViewModelTests.swift | 48 ------------------- .../Room/PollHistory/View/PollHistory.swift | 1 + .../Room/PollHistory/View/PollListItem.swift | 1 + 5 files changed, 20 insertions(+), 63 deletions(-) delete mode 100644 RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift diff --git a/RiotSwiftUI/Modules/Common/Mock/MockAppScreens.swift b/RiotSwiftUI/Modules/Common/Mock/MockAppScreens.swift index eaee22e738..ba1d91e52e 100644 --- a/RiotSwiftUI/Modules/Common/Mock/MockAppScreens.swift +++ b/RiotSwiftUI/Modules/Common/Mock/MockAppScreens.swift @@ -72,6 +72,7 @@ enum MockAppScreens { MockComposerScreenState.self, MockComposerCreateActionListScreenState.self, MockComposerLinkActionScreenState.self, - MockVoiceBroadcastPlaybackScreenState.self + MockVoiceBroadcastPlaybackScreenState.self, + MockPollHistoryScreenState.self ] } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift index 3b123c95dc..a313776037 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift @@ -18,21 +18,23 @@ import RiotSwiftUI import XCTest class PollHistoryUITests: MockScreenTestCase { - func testPollHistoryPromptRegular() { - let promptType = PollHistoryPromptType.regular - app.goToScreenWithIdentifier(MockPollHistoryScreenState.promptType(promptType).title) - - let title = app.staticTexts["title"] - XCTAssert(title.exists) - XCTAssertEqual(title.label, promptType.title) + func testPollHistoryHasContent() { + app.goToScreenWithIdentifier(MockPollHistoryScreenState.active.title) + let title = app.navigationBars.firstMatch.identifier + let emptyText = app.staticTexts["PollHistory.emptyText"] + let items = app.staticTexts["PollListItem.title"] + XCTAssertEqual(title, VectorL10n.pollHistoryTitle) + XCTAssertTrue(items.exists) + XCTAssertFalse(emptyText.exists) } - func testPollHistoryPromptUpgrade() { - let promptType = PollHistoryPromptType.upgrade - app.goToScreenWithIdentifier(MockPollHistoryScreenState.promptType(promptType).title) - - let title = app.staticTexts["title"] - XCTAssert(title.exists) - XCTAssertEqual(title.label, promptType.title) + func testPollHistoryShowsEmptyScreen() { + app.goToScreenWithIdentifier(MockPollHistoryScreenState.activeEmpty.title) + let title = app.navigationBars.firstMatch.identifier + let emptyText = app.staticTexts["PollHistory.emptyText"] + let items = app.staticTexts["PollListItem.title"] + XCTAssertEqual(title, VectorL10n.pollHistoryTitle) + XCTAssertFalse(items.exists) + XCTAssertTrue(emptyText.exists) } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift b/RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift deleted file mode 100644 index a388d98235..0000000000 --- a/RiotSwiftUI/Modules/Room/PollHistory/Test/Unit/PollHistoryViewModelTests.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright 2021 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 XCTest - -@testable import RiotSwiftUI - -class PollHistoryViewModelTests: XCTestCase { - private enum Constants { - static let counterInitialValue = 0 - } - - var viewModel: PollHistoryViewModelProtocol! - var context: PollHistoryViewModelType.Context! - - override func setUpWithError() throws { - viewModel = PollHistoryViewModel(promptType: .regular, initialCount: Constants.counterInitialValue) - context = viewModel.context - } - - func testInitialState() { - XCTAssertEqual(context.viewState.count, Constants.counterInitialValue) - } - - func testCounter() throws { - context.send(viewAction: .incrementCount) - XCTAssertEqual(context.viewState.count, 1) - - context.send(viewAction: .incrementCount) - XCTAssertEqual(context.viewState.count, 2) - - context.send(viewAction: .decrementCount) - XCTAssertEqual(context.viewState.count, 1) - } -} diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index fa000b9014..5bbb60ad65 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -81,6 +81,7 @@ struct PollHistory: View { .foregroundColor(theme.colors.secondaryContent) .frame(maxHeight: .infinity) .padding(.horizontal, 16) + .accessibilityLabel("PollHistory.emptyText") } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index dff98ba0a7..58669552ce 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -45,6 +45,7 @@ struct PollListItem: View { .foregroundColor(theme.colors.primaryContent) .font(theme.fonts.body) .lineLimit(2) + .accessibilityLabel("PollListItem.title") } } } From c7c3b855894df82cd0ec17ff1b96dd92ede7945b Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 10:54:56 +0100 Subject: [PATCH 043/160] Add changelog.d file --- .../Room/RoomInfo/RoomInfoCoordinator.swift | 1 - .../Coordinator/PollHistoryCoordinator.swift | 20 ------------------- changelog.d/pr-7267.change | 1 + 3 files changed, 1 insertion(+), 21 deletions(-) create mode 100644 changelog.d/pr-7267.change diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index 774e60f1ec..046c20c795 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -194,7 +194,6 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { } private func push(coordinator: Coordinator & Presentable, animated: Bool = true) { - coordinator.start() self.add(childCoordinator: coordinator) navigationRouter.push(coordinator, animated: animated) { self.remove(childCoordinator: coordinator) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift index 0cdf3629a4..b9129a6e93 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Coordinator/PollHistoryCoordinator.swift @@ -26,9 +26,6 @@ final class PollHistoryCoordinator: Coordinator, Presentable { private let pollHistoryHostingController: UIViewController private var pollHistoryViewModel: PollHistoryViewModelProtocol - private var indicatorPresenter: UserIndicatorTypePresenterProtocol - private var loadingIndicator: UserIndicator? - // Must be used only internally var childCoordinators: [Coordinator] = [] var completion: (() -> Void)? @@ -41,8 +38,6 @@ final class PollHistoryCoordinator: Coordinator, Presentable { let view = PollHistory(viewModel: viewModel.context) pollHistoryViewModel = viewModel pollHistoryHostingController = VectorHostingController(rootView: view) - - indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: pollHistoryHostingController) } // MARK: - Public @@ -57,19 +52,4 @@ final class PollHistoryCoordinator: Coordinator, Presentable { func toPresentable() -> UIViewController { pollHistoryHostingController } - - // MARK: - Private - - /// Show an activity indicator whilst loading. - /// - Parameters: - /// - label: The label to show on the indicator. - /// - isInteractionBlocking: Whether the indicator should block any user interaction. - private func startLoading(label: String = VectorL10n.loading, isInteractionBlocking: Bool = true) { - loadingIndicator = indicatorPresenter.present(.loading(label: label, isInteractionBlocking: isInteractionBlocking)) - } - - /// Hide the currently displayed activity indicator. - private func stopLoading() { - loadingIndicator = nil - } } diff --git a/changelog.d/pr-7267.change b/changelog.d/pr-7267.change new file mode 100644 index 0000000000..cab02bc6a6 --- /dev/null +++ b/changelog.d/pr-7267.change @@ -0,0 +1 @@ +Polls: add UI for active poll history. From e9525907c3d4f13599ca2f78b93aaa7c4c8658ca Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 12:57:21 +0100 Subject: [PATCH 044/160] Inject AvatarViewMode as EnvironmentObject --- .../MockAnalyticsPromptScreenState.swift | 2 +- .../Avatar/Service/MatrixSDK/AvatarService.swift | 4 ---- .../Modules/Common/Avatar/View/AvatarImage.swift | 4 ++-- .../Common/Avatar/View/SpaceAvatarImage.swift | 4 ++-- .../Common/Avatar/ViewModel/AvatarViewModel.swift | 12 +++++++++++- .../DependencyContainerKey.swift | 15 --------------- .../InfoSheet/MockInfoSheetScreenState.swift | 2 +- .../LiveLocationSharingViewerCoordinator.swift | 2 +- .../Coordinator/LocationSharingCoordinator.swift | 2 +- .../LocationSharingScreenState.swift | 2 +- .../StaticLocationViewingCoordinator.swift | 3 ++- .../MockStaticLocationViewingScreenState.swift | 2 +- .../Avatar/MockOnboardingAvatarScreenState.swift | 2 +- .../MockOnboardingCelebrationScreenState.swift | 2 +- .../MockOnboardingUseCaseScreenState.swift | 2 +- .../RoomNotificationSettingsCoordinator.swift | 2 +- .../View/RoomNotificationSettings.swift | 4 ++-- .../View/RoomNotificationSettingsHeader.swift | 2 +- .../MockRoomAccessTypeChooserScreenState.swift | 2 +- .../Coordinator/RoomUpgradeCoordinator.swift | 2 +- .../RoomUpgrade/MockRoomUpgradeScreenState.swift | 2 +- .../Coordinator/UserSuggestionCoordinator.swift | 4 ++-- .../UserSuggestionScreenState.swift | 2 +- .../View/UserSuggestionListItem.swift | 2 +- .../VoiceBroadcastPlaybackCoordinator.swift | 2 +- .../VoiceBroadcastRecorderCoordinator.swift | 3 ++- .../MatrixItemChooserCoordinator.swift | 5 +++-- .../MockMatrixItemChooserScreenState.swift | 2 +- .../View/MatrixItemChooserListRow.swift | 2 +- .../SpaceCreationEmailInvitesCoordinator.swift | 2 +- ...MockSpaceCreationEmailInvitesScreenState.swift | 2 +- .../SpaceCreationMenuCoordinator.swift | 2 +- .../SpaceCreationPostProcessCoordinator.swift | 2 +- .../MockSpaceCreationPostProcessScreenState.swift | 2 +- .../SpaceCreationRoomsCoordinator.swift | 2 +- .../Mock/MockSpaceCreationRoomsScreenState.swift | 2 +- .../SpaceCreationSettingsCoordinator.swift | 2 +- .../MockSpaceCreationSettingsScreenState.swift | 2 +- .../Coordinator/SpaceSelectorCoordinator.swift | 2 +- .../Coordinator/SpaceSettingsCoordinator.swift | 3 ++- .../MockSpaceSettingsScreenState.swift | 2 +- .../MockTemplateSimpleScreenScreenState.swift | 2 +- .../TemplateUserProfileCoordinator.swift | 2 +- .../MockTemplateUserProfileScreenState.swift | 2 +- .../View/TemplateUserProfileHeader.swift | 2 +- .../Coordinator/TemplateRoomChatCoordinator.swift | 3 ++- .../MockTemplateRoomChatScreenState.swift | 2 +- .../View/TemplateRoomChatBubbleView.swift | 2 +- .../Coordinator/TemplateRoomListCoordinator.swift | 2 +- .../MockTemplateRoomListScreenState.swift | 2 +- .../View/TemplateRoomListRow.swift | 2 +- .../MockUserSessionsOverviewScreenState.swift | 2 +- 52 files changed, 70 insertions(+), 74 deletions(-) diff --git a/RiotSwiftUI/Modules/AnalyticsPrompt/MockAnalyticsPromptScreenState.swift b/RiotSwiftUI/Modules/AnalyticsPrompt/MockAnalyticsPromptScreenState.swift index 7d222aa311..559c67d170 100644 --- a/RiotSwiftUI/Modules/AnalyticsPrompt/MockAnalyticsPromptScreenState.swift +++ b/RiotSwiftUI/Modules/AnalyticsPrompt/MockAnalyticsPromptScreenState.swift @@ -47,7 +47,7 @@ enum MockAnalyticsPromptScreenState: MockScreenState, CaseIterable { return ( [promptType, viewModel], AnyView(AnalyticsPrompt(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Common/Avatar/Service/MatrixSDK/AvatarService.swift b/RiotSwiftUI/Modules/Common/Avatar/Service/MatrixSDK/AvatarService.swift index 02369980c8..ea44882447 100644 --- a/RiotSwiftUI/Modules/Common/Avatar/Service/MatrixSDK/AvatarService.swift +++ b/RiotSwiftUI/Modules/Common/Avatar/Service/MatrixSDK/AvatarService.swift @@ -32,10 +32,6 @@ class AvatarService: AvatarServiceProtocol { private let mediaManager: MXMediaManager - static func instantiate(mediaManager: MXMediaManager) -> AvatarServiceProtocol { - AvatarService(mediaManager: mediaManager) - } - init(mediaManager: MXMediaManager) { self.mediaManager = mediaManager } diff --git a/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift b/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift index 4f51f574ad..ff79501117 100644 --- a/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift +++ b/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift @@ -20,7 +20,7 @@ import SwiftUI struct AvatarImage: View { @Environment(\.theme) var theme: ThemeSwiftUI @Environment(\.dependencies) var dependencies: DependencyContainer - @StateObject var viewModel = AvatarViewModel() + @EnvironmentObject var viewModel: AvatarViewModel var mxContentUri: String? var matrixItemId: String @@ -95,7 +95,7 @@ struct AvatarImage_Previews: PreviewProvider { AvatarImage(mxContentUri: nil, matrixItemId: name, displayName: name, size: .xLarge) } } - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } } diff --git a/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift b/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift index 8e967fe180..c6fe8da0bd 100644 --- a/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift +++ b/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift @@ -20,7 +20,7 @@ import SwiftUI struct SpaceAvatarImage: View { @Environment(\.theme) var theme: ThemeSwiftUI @Environment(\.dependencies) var dependencies: DependencyContainer - @StateObject var viewModel = AvatarViewModel() + @EnvironmentObject var viewModel: AvatarViewModel var mxContentUri: String? var matrixItemId: String @@ -99,7 +99,7 @@ struct LiveAvatarImage_Previews: PreviewProvider { SpaceAvatarImage(mxContentUri: nil, matrixItemId: name, displayName: name, size: .xLarge) } } - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } } diff --git a/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift b/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift index 433fb9cbad..f6372c14f8 100644 --- a/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift +++ b/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift @@ -20,10 +20,14 @@ import Foundation /// Simple ViewModel that supports loading an avatar image class AvatarViewModel: InjectableObject, ObservableObject { - @Inject var avatarService: AvatarServiceProtocol + private let avatarService: AvatarServiceProtocol @Published private(set) var viewState = AvatarViewState.empty + init(avatarService: AvatarServiceProtocol) { + self.avatarService = avatarService + } + private var cancellables = Set() /// Load an avatar @@ -58,3 +62,9 @@ class AvatarViewModel: InjectableObject, ObservableObject { .store(in: &cancellables) } } + +extension AvatarViewModel { + static func withMockedServices() -> AvatarViewModel { + .init(avatarService: MockAvatarService.example) + } +} diff --git a/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift b/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift index 4bde8956e8..9e5403b252 100644 --- a/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift +++ b/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift @@ -31,18 +31,3 @@ extension EnvironmentValues { set { self[DependencyContainerKey.self] = newValue } } } - -extension View { - /// A modifier for adding a dependency to the SwiftUI view hierarchy's dependency container. - /// - /// Important: When adding a dependency to cast it to the type in which it will be injected. - /// So if adding `MockDependency` but type at injection is `Dependency` remember to cast - /// to `Dependency` first. - /// - Parameter dependency: The dependency to add. - /// - Returns: The wrapped view that now includes the dependency. - func addDependency(_ dependency: T) -> some View { - transformEnvironment(\.dependencies) { container in - container.register(dependency: dependency) - } - } -} diff --git a/RiotSwiftUI/Modules/Common/InfoSheet/MockInfoSheetScreenState.swift b/RiotSwiftUI/Modules/Common/InfoSheet/MockInfoSheetScreenState.swift index 62d86a681a..b34c744c3b 100644 --- a/RiotSwiftUI/Modules/Common/InfoSheet/MockInfoSheetScreenState.swift +++ b/RiotSwiftUI/Modules/Common/InfoSheet/MockInfoSheetScreenState.swift @@ -51,7 +51,7 @@ enum MockInfoSheetScreenState: MockScreenState, CaseIterable { return ( [model, viewModel], AnyView(InfoSheet(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/Coordinator/LiveLocationSharingViewerCoordinator.swift b/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/Coordinator/LiveLocationSharingViewerCoordinator.swift index fc5c6b87af..4bd1f7c524 100644 --- a/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/Coordinator/LiveLocationSharingViewerCoordinator.swift +++ b/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/Coordinator/LiveLocationSharingViewerCoordinator.swift @@ -53,7 +53,7 @@ final class LiveLocationSharingViewerCoordinator: Coordinator, Presentable { service: service ) let view = LiveLocationSharingViewer(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) liveLocationSharingViewerViewModel = viewModel liveLocationSharingViewerHostingController = VectorHostingController(rootView: view) diff --git a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift index ea3e1b908e..9cd5853c74 100644 --- a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift +++ b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift @@ -86,7 +86,7 @@ final class LocationSharingCoordinator: Coordinator, Presentable { ) let view = LocationSharingView(context: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.mediaManager))) locationSharingViewModel = viewModel locationSharingHostingController = VectorHostingController(rootView: view) diff --git a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/LocationSharingScreenState.swift b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/LocationSharingScreenState.swift index 3b86f4e89c..c59e0bf4b3 100644 --- a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/LocationSharingScreenState.swift +++ b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/LocationSharingScreenState.swift @@ -34,6 +34,6 @@ enum MockLocationSharingScreenState: MockScreenState, CaseIterable { isLiveLocationSharingEnabled: true, service: locationSharingService) return ([viewModel], AnyView(LocationSharingView(context: viewModel.context) - .addDependency(MockAvatarService.example))) + .environmentObject(AvatarViewModel.withMockedServices()))) } } diff --git a/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/Coordinator/StaticLocationViewingCoordinator.swift b/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/Coordinator/StaticLocationViewingCoordinator.swift index b125fbcd6e..bf938dac83 100644 --- a/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/Coordinator/StaticLocationViewingCoordinator.swift +++ b/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/Coordinator/StaticLocationViewingCoordinator.swift @@ -56,7 +56,8 @@ final class StaticLocationViewingCoordinator: Coordinator, Presentable { coordinateType: parameters.coordinateType ) let view = StaticLocationView(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.mediaManager))) + staticLocationViewingViewModel = viewModel staticLocationViewingHostingController = VectorHostingController(rootView: view) } diff --git a/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/MockStaticLocationViewingScreenState.swift b/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/MockStaticLocationViewingScreenState.swift index 2ea0f0aece..4430c36c20 100644 --- a/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/MockStaticLocationViewingScreenState.swift +++ b/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/MockStaticLocationViewingScreenState.swift @@ -50,6 +50,6 @@ enum MockStaticLocationViewingScreenState: MockScreenState, CaseIterable { return ([viewModel], AnyView(StaticLocationView(viewModel: viewModel.context) - .addDependency(MockAvatarService.example))) + .environmentObject(AvatarViewModel.withMockedServices()))) } } diff --git a/RiotSwiftUI/Modules/Onboarding/Avatar/MockOnboardingAvatarScreenState.swift b/RiotSwiftUI/Modules/Onboarding/Avatar/MockOnboardingAvatarScreenState.swift index 3c972b6027..73fb8e6681 100644 --- a/RiotSwiftUI/Modules/Onboarding/Avatar/MockOnboardingAvatarScreenState.swift +++ b/RiotSwiftUI/Modules/Onboarding/Avatar/MockOnboardingAvatarScreenState.swift @@ -57,7 +57,7 @@ enum MockOnboardingAvatarScreenState: MockScreenState, CaseIterable { return ( [self, viewModel], AnyView(OnboardingAvatarScreen(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Onboarding/Celebration/MockOnboardingCelebrationScreenState.swift b/RiotSwiftUI/Modules/Onboarding/Celebration/MockOnboardingCelebrationScreenState.swift index d911f8249a..e0bca18c1f 100644 --- a/RiotSwiftUI/Modules/Onboarding/Celebration/MockOnboardingCelebrationScreenState.swift +++ b/RiotSwiftUI/Modules/Onboarding/Celebration/MockOnboardingCelebrationScreenState.swift @@ -39,7 +39,7 @@ enum MockOnboardingCelebrationScreenState: MockScreenState, CaseIterable { return ( [self, viewModel], AnyView(OnboardingCelebrationScreen(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Onboarding/UseCase/MockOnboardingUseCaseScreenState.swift b/RiotSwiftUI/Modules/Onboarding/UseCase/MockOnboardingUseCaseScreenState.swift index ed580b8342..c1ac462652 100644 --- a/RiotSwiftUI/Modules/Onboarding/UseCase/MockOnboardingUseCaseScreenState.swift +++ b/RiotSwiftUI/Modules/Onboarding/UseCase/MockOnboardingUseCaseScreenState.swift @@ -45,7 +45,7 @@ enum MockOnboardingUseCaseSelectionScreenState: MockScreenState, CaseIterable { return ( [self, viewModel], AnyView(OnboardingUseCaseSelectionScreen(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Room/NotificationSettings/Coordinator/RoomNotificationSettingsCoordinator.swift b/RiotSwiftUI/Modules/Room/NotificationSettings/Coordinator/RoomNotificationSettingsCoordinator.swift index e0d9098980..9a25f8689d 100644 --- a/RiotSwiftUI/Modules/Room/NotificationSettings/Coordinator/RoomNotificationSettingsCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/NotificationSettings/Coordinator/RoomNotificationSettingsCoordinator.swift @@ -51,7 +51,7 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin ) let avatarService: AvatarServiceProtocol = AvatarService(mediaManager: room.mxSession.mediaManager) let view = RoomNotificationSettings(viewModel: viewModel, presentedModally: presentedModally) - .addDependency(avatarService) + .environmentObject(AvatarViewModel(avatarService: avatarService)) let viewController = VectorHostingController(rootView: view) roomNotificationSettingsViewModel = viewModel roomNotificationSettingsViewController = viewController diff --git a/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettings.swift b/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettings.swift index 3034f50db9..20a6406e35 100644 --- a/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettings.swift +++ b/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettings.swift @@ -85,13 +85,13 @@ struct RoomNotificationSettings_Previews: PreviewProvider { NavigationView { RoomNotificationSettings(viewModel: mockViewModel, presentedModally: true) .navigationBarTitleDisplayMode(.inline) - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } NavigationView { RoomNotificationSettings(viewModel: mockViewModel, presentedModally: true) .navigationBarTitleDisplayMode(.inline) .theme(ThemeIdentifier.dark) - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } } diff --git a/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettingsHeader.swift b/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettingsHeader.swift index 20066b9618..835c9bdd70 100644 --- a/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettingsHeader.swift +++ b/RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettingsHeader.swift @@ -43,6 +43,6 @@ struct RoomNotificationSettingsHeader_Previews: PreviewProvider { static let name = "Element" static var previews: some View { RoomNotificationSettingsHeader(avatarData: MockAvatarInput.example, displayName: name) - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } diff --git a/RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/MockRoomAccessTypeChooserScreenState.swift b/RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/MockRoomAccessTypeChooserScreenState.swift index fd8e741036..9f937d435d 100644 --- a/RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/MockRoomAccessTypeChooserScreenState.swift +++ b/RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/MockRoomAccessTypeChooserScreenState.swift @@ -51,7 +51,7 @@ enum MockRoomAccessTypeChooserScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(RoomAccessTypeChooser(viewModel: viewModel.context, roomName: "Room Name") - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Room/RoomUpgrade/Coordinator/RoomUpgradeCoordinator.swift b/RiotSwiftUI/Modules/Room/RoomUpgrade/Coordinator/RoomUpgradeCoordinator.swift index bc89e53cbc..32564e69d0 100644 --- a/RiotSwiftUI/Modules/Room/RoomUpgrade/Coordinator/RoomUpgradeCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/RoomUpgrade/Coordinator/RoomUpgradeCoordinator.swift @@ -45,7 +45,7 @@ final class RoomUpgradeCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = RoomUpgradeViewModel.makeRoomUpgradeViewModel(roomUpgradeService: RoomUpgradeService(session: parameters.session, roomId: parameters.roomId, parentSpaceId: parameters.parentSpaceId, versionOverride: parameters.versionOverride)) let view = RoomUpgrade(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) roomUpgradeViewModel = viewModel roomUpgradeHostingController = VectorHostingController(rootView: view) roomUpgradeHostingController.view.backgroundColor = .clear diff --git a/RiotSwiftUI/Modules/Room/RoomUpgrade/MockRoomUpgradeScreenState.swift b/RiotSwiftUI/Modules/Room/RoomUpgrade/MockRoomUpgradeScreenState.swift index bca1f0ea73..4529c0eff4 100644 --- a/RiotSwiftUI/Modules/Room/RoomUpgrade/MockRoomUpgradeScreenState.swift +++ b/RiotSwiftUI/Modules/Room/RoomUpgrade/MockRoomUpgradeScreenState.swift @@ -49,7 +49,7 @@ enum MockRoomUpgradeScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(RoomUpgrade(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift index c3812b5e8f..c6d86a6558 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift @@ -61,7 +61,7 @@ final class UserSuggestionCoordinator: Coordinator, Presentable { let viewModel = UserSuggestionViewModel(userSuggestionService: userSuggestionService) let view = UserSuggestionList(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.mediaManager))) userSuggestionViewModel = viewModel userSuggestionHostingController = VectorHostingController(rootView: view) @@ -105,7 +105,7 @@ final class UserSuggestionCoordinator: Coordinator, Presentable { private func calculateViewHeight() -> CGFloat { let viewModel = UserSuggestionViewModel(userSuggestionService: userSuggestionService) let view = UserSuggestionList(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.mediaManager))) let controller = VectorHostingController(rootView: view) guard let view = controller.view else { diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionScreenState.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionScreenState.swift index f8a8acade3..a0ed202682 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionScreenState.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionScreenState.swift @@ -37,7 +37,7 @@ enum MockUserSuggestionScreenState: MockScreenState, CaseIterable { return ( [service, listViewModel], AnyView(UserSuggestionListWithInput(viewModel: viewModel) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListItem.swift b/RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListItem.swift index 0d3328b33c..862e7573d6 100644 --- a/RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListItem.swift +++ b/RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListItem.swift @@ -55,6 +55,6 @@ struct UserSuggestionListItem: View { struct UserSuggestionHeader_Previews: PreviewProvider { static var previews: some View { UserSuggestionListItem(avatar: MockAvatarInput.example, displayName: "Alice", userId: "@alice:matrix.org") - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift index 3f5e55c6e4..bc0d123f44 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift @@ -66,7 +66,7 @@ final class VoiceBroadcastPlaybackCoordinator: Coordinator, Presentable { func toPresentable() -> UIViewController { let view = VoiceBroadcastPlaybackView(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) return VectorHostingController(rootView: view) } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift index 77d4c394a7..409266d155 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift @@ -61,7 +61,8 @@ final class VoiceBroadcastRecorderCoordinator: Coordinator, Presentable { func toPresentable() -> UIViewController { let view = VoiceBroadcastRecorderView(viewModel: voiceBroadcastRecorderViewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) + return VectorHostingController(rootView: view) } diff --git a/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Coordinator/MatrixItemChooserCoordinator.swift b/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Coordinator/MatrixItemChooserCoordinator.swift index 467c69eb98..0f3155c9f4 100644 --- a/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Coordinator/MatrixItemChooserCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Coordinator/MatrixItemChooserCoordinator.swift @@ -70,11 +70,12 @@ final class MatrixItemChooserCoordinator: Coordinator, Presentable { let viewModel = MatrixItemChooserViewModel.makeMatrixItemChooserViewModel(matrixItemChooserService: MatrixItemChooserService(session: parameters.session, selectedItemIds: parameters.selectedItemsIds, itemsProcessor: parameters.itemsProcessor), title: parameters.title, detail: parameters.detail, selectionHeader: parameters.selectionHeader) matrixItemChooserViewModel = viewModel if let viewProvider = parameters.viewProvider { - let view = viewProvider.view(with: viewModel.context).addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + let view = viewProvider.view(with: viewModel.context) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) matrixItemChooserHostingController = VectorHostingController(rootView: view) } else { let view = MatrixItemChooser(viewModel: viewModel.context, listBottomPadding: nil) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) matrixItemChooserHostingController = VectorHostingController(rootView: view) } } diff --git a/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MockMatrixItemChooserScreenState.swift b/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MockMatrixItemChooserScreenState.swift index e18476c24b..b2db1b3403 100644 --- a/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MockMatrixItemChooserScreenState.swift +++ b/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MockMatrixItemChooserScreenState.swift @@ -61,7 +61,7 @@ enum MockMatrixItemChooserScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(MatrixItemChooser(viewModel: viewModel.context, listBottomPadding: nil) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserListRow.swift b/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserListRow.swift index 1d67f2a72e..883fd6e8ec 100644 --- a/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserListRow.swift +++ b/RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserListRow.swift @@ -70,6 +70,6 @@ struct MatrixItemChooserListRow: View { struct MatrixItemChooserListRow_Previews: PreviewProvider { static var previews: some View { TemplateRoomListRow(avatar: MockAvatarInput.example, displayName: "Alice") - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Coordinator/SpaceCreationEmailInvitesCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Coordinator/SpaceCreationEmailInvitesCoordinator.swift index 28792056fe..d7a31ede55 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Coordinator/SpaceCreationEmailInvitesCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Coordinator/SpaceCreationEmailInvitesCoordinator.swift @@ -42,7 +42,7 @@ final class SpaceCreationEmailInvitesCoordinator: Coordinator, Presentable { let service = SpaceCreationEmailInvitesService(session: parameters.session) let viewModel = SpaceCreationEmailInvitesViewModel(creationParameters: parameters.creationParams, service: service) let view = SpaceCreationEmailInvites(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) spaceCreationEmailInvitesViewModel = viewModel let hostingController = VectorHostingController(rootView: view) hostingController.isNavigationBarHidden = true diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesScreenState.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesScreenState.swift index 0b70a87462..add3eb6ed3 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesScreenState.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesScreenState.swift @@ -64,7 +64,7 @@ enum MockSpaceCreationEmailInvitesScreenState: MockScreenState, CaseIterable { return ( [viewModel], AnyView(SpaceCreationEmailInvites(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Coordinator/SpaceCreationMenuCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Coordinator/SpaceCreationMenuCoordinator.swift index 8d590936d3..e3bcd6c9c0 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Coordinator/SpaceCreationMenuCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Coordinator/SpaceCreationMenuCoordinator.swift @@ -41,7 +41,7 @@ final class SpaceCreationMenuCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = SpaceCreationMenuViewModel(navTitle: parameters.navTitle, creationParams: parameters.creationParams, title: parameters.title, detail: parameters.detail, options: parameters.options) let view = SpaceCreationMenu(viewModel: viewModel.context, showBackButton: parameters.showBackButton) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) spaceCreationMenuViewModel = viewModel let hostingController = VectorHostingController(rootView: view) hostingController.isNavigationBarHidden = true diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Coordinator/SpaceCreationPostProcessCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Coordinator/SpaceCreationPostProcessCoordinator.swift index a1838458d5..e385e30cb4 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Coordinator/SpaceCreationPostProcessCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Coordinator/SpaceCreationPostProcessCoordinator.swift @@ -41,7 +41,7 @@ final class SpaceCreationPostProcessCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = SpaceCreationPostProcessViewModel.makeSpaceCreationPostProcessViewModel(spaceCreationPostProcessService: SpaceCreationPostProcessService(session: parameters.session, parentSpaceId: parameters.parentSpaceId, creationParams: parameters.creationParams)) let view = SpaceCreationPostProcess(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) spaceCreationPostProcessViewModel = viewModel let hostingController = VectorHostingController(rootView: view) hostingController.isNavigationBarHidden = true diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessScreenState.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessScreenState.swift index 27c003b71b..f3c18f5435 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessScreenState.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessScreenState.swift @@ -54,7 +54,7 @@ enum MockSpaceCreationPostProcessScreenState: MockScreenState { return ( [service, viewModel], AnyView(SpaceCreationPostProcess(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Coordinator/SpaceCreationRoomsCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Coordinator/SpaceCreationRoomsCoordinator.swift index 2e94feec22..3e7ef4b4ed 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Coordinator/SpaceCreationRoomsCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Coordinator/SpaceCreationRoomsCoordinator.swift @@ -41,7 +41,7 @@ final class SpaceCreationRoomsCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = SpaceCreationRoomsViewModel(creationParameters: parameters.creationParams) let view = SpaceCreationRooms(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) spaceCreationRoomsViewModel = viewModel let hostingController = VectorHostingController(rootView: view) hostingController.isNavigationBarHidden = true diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Service/Mock/MockSpaceCreationRoomsScreenState.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Service/Mock/MockSpaceCreationRoomsScreenState.swift index 3ef06a64fe..f23e463e2c 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Service/Mock/MockSpaceCreationRoomsScreenState.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Service/Mock/MockSpaceCreationRoomsScreenState.swift @@ -55,7 +55,7 @@ enum MockSpaceCreationRoomsScreenState: MockScreenState, CaseIterable { return ( [viewModel], AnyView(SpaceCreationRooms(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Coordinator/SpaceCreationSettingsCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Coordinator/SpaceCreationSettingsCoordinator.swift index 5077e46574..a1ca35a425 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Coordinator/SpaceCreationSettingsCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Coordinator/SpaceCreationSettingsCoordinator.swift @@ -48,7 +48,7 @@ final class SpaceCreationSettingsCoordinator: Coordinator, Presentable { let service = SpaceCreationSettingsService(roomName: parameters.creationParameters.name ?? "", userDefinedAddress: parameters.creationParameters.userDefinedAddress, session: parameters.session) let viewModel = SpaceCreationSettingsViewModel(spaceCreationSettingsService: service, creationParameters: parameters.creationParameters) let view = SpaceCreationSettings(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) spaceCreationSettingsViewModel = viewModel let hostingController = VectorHostingController(rootView: view) hostingController.isNavigationBarHidden = true diff --git a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsScreenState.swift b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsScreenState.swift index 8738289a93..2942a43b41 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsScreenState.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsScreenState.swift @@ -59,7 +59,7 @@ enum MockSpaceCreationSettingsScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(SpaceCreationSettings(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSelectorBottomSheet/SpaceSelector/Coordinator/SpaceSelectorCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceSelectorBottomSheet/SpaceSelector/Coordinator/SpaceSelectorCoordinator.swift index 771ad0b8f3..530f33eb96 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSelectorBottomSheet/SpaceSelector/Coordinator/SpaceSelectorCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSelectorBottomSheet/SpaceSelector/Coordinator/SpaceSelectorCoordinator.swift @@ -62,7 +62,7 @@ final class SpaceSelectorCoordinator: Coordinator, Presentable { let service = SpaceSelectorService(session: parameters.session, parentSpaceId: parameters.parentSpaceId, showHomeSpace: parameters.showHomeSpace, selectedSpaceId: parameters.selectedSpaceId) let viewModel = SpaceSelectorViewModel.makeViewModel(service: service, showCancel: parameters.showCancel) let view = SpaceSelector(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) self.viewModel = viewModel let hostingViewController = VectorHostingController(rootView: view) hostingViewController.hidesBackTitleWhenPushed = true diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Coordinator/SpaceSettingsCoordinator.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Coordinator/SpaceSettingsCoordinator.swift index 0224ae5cfc..6748ee5a7d 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Coordinator/SpaceSettingsCoordinator.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Coordinator/SpaceSettingsCoordinator.swift @@ -48,7 +48,8 @@ final class SpaceSettingsCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = SpaceSettingsViewModel.makeSpaceSettingsViewModel(service: SpaceSettingsService(session: parameters.session, spaceId: parameters.spaceId)) let view = SpaceSettings(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) + spaceSettingsViewModel = viewModel let controller = VectorHostingController(rootView: view) controller.enableNavigationBarScrollEdgeAppearance = true diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/MockSpaceSettingsScreenState.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/MockSpaceSettingsScreenState.swift index f184826388..342cf520f5 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/MockSpaceSettingsScreenState.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/MockSpaceSettingsScreenState.swift @@ -79,7 +79,7 @@ enum MockSpaceSettingsScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(SpaceSettings(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Template/SimpleScreenExample/MockTemplateSimpleScreenScreenState.swift b/RiotSwiftUI/Modules/Template/SimpleScreenExample/MockTemplateSimpleScreenScreenState.swift index 5db4451ecd..ffb4af8ac3 100644 --- a/RiotSwiftUI/Modules/Template/SimpleScreenExample/MockTemplateSimpleScreenScreenState.swift +++ b/RiotSwiftUI/Modules/Template/SimpleScreenExample/MockTemplateSimpleScreenScreenState.swift @@ -50,7 +50,7 @@ enum MockTemplateSimpleScreenScreenState: MockScreenState, CaseIterable { return ( [promptType, viewModel], AnyView(TemplateSimpleScreen(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/Coordinator/TemplateUserProfileCoordinator.swift b/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/Coordinator/TemplateUserProfileCoordinator.swift index b3098629bb..73dc2d9879 100644 --- a/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/Coordinator/TemplateUserProfileCoordinator.swift +++ b/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/Coordinator/TemplateUserProfileCoordinator.swift @@ -37,7 +37,7 @@ final class TemplateUserProfileCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = TemplateUserProfileViewModel.makeTemplateUserProfileViewModel(templateUserProfileService: TemplateUserProfileService(session: parameters.session)) let view = TemplateUserProfile(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) templateUserProfileViewModel = viewModel templateUserProfileHostingController = VectorHostingController(rootView: view) diff --git a/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/MockTemplateUserProfileScreenState.swift b/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/MockTemplateUserProfileScreenState.swift index 08082aec5e..27e9d215b7 100644 --- a/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/MockTemplateUserProfileScreenState.swift +++ b/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/MockTemplateUserProfileScreenState.swift @@ -55,7 +55,7 @@ enum MockTemplateUserProfileScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(TemplateUserProfile(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/View/TemplateUserProfileHeader.swift b/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/View/TemplateUserProfileHeader.swift index a87e06605a..f8e9bfe287 100644 --- a/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/View/TemplateUserProfileHeader.swift +++ b/RiotSwiftUI/Modules/Template/SimpleUserProfileExample/View/TemplateUserProfileHeader.swift @@ -46,6 +46,6 @@ struct TemplateUserProfileHeader: View { struct TemplateUserProfileHeader_Previews: PreviewProvider { static var previews: some View { TemplateUserProfileHeader(avatar: MockAvatarInput.example, displayName: "Alice", presence: .online) - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } diff --git a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/Coordinator/TemplateRoomChatCoordinator.swift b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/Coordinator/TemplateRoomChatCoordinator.swift index bca98511f6..afe669ec89 100644 --- a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/Coordinator/TemplateRoomChatCoordinator.swift +++ b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/Coordinator/TemplateRoomChatCoordinator.swift @@ -33,7 +33,8 @@ final class TemplateRoomChatCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = TemplateRoomChatViewModel(templateRoomChatService: TemplateRoomChatService(room: parameters.room)) let view = TemplateRoomChat(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.room.mxSession.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.room.mxSession.mediaManager))) + templateRoomChatViewModel = viewModel templateRoomChatHostingController = VectorHostingController(rootView: view) } diff --git a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/MockTemplateRoomChatScreenState.swift b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/MockTemplateRoomChatScreenState.swift index 8ec8bced0d..f9a74abaef 100644 --- a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/MockTemplateRoomChatScreenState.swift +++ b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/MockTemplateRoomChatScreenState.swift @@ -56,7 +56,7 @@ enum MockTemplateRoomChatScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(TemplateRoomChat(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/View/TemplateRoomChatBubbleView.swift b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/View/TemplateRoomChatBubbleView.swift index 70495bd25e..24df8b7e09 100644 --- a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/View/TemplateRoomChatBubbleView.swift +++ b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/View/TemplateRoomChatBubbleView.swift @@ -58,6 +58,6 @@ struct TemplateRoomChatBubbleView_Previews: PreviewProvider { ) static var previews: some View { TemplateRoomChatBubbleView(bubble: bubble) - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } diff --git a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/Coordinator/TemplateRoomListCoordinator.swift b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/Coordinator/TemplateRoomListCoordinator.swift index 26bbbbb990..263e878c01 100644 --- a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/Coordinator/TemplateRoomListCoordinator.swift +++ b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/Coordinator/TemplateRoomListCoordinator.swift @@ -33,7 +33,7 @@ final class TemplateRoomListCoordinator: Coordinator, Presentable { self.parameters = parameters let viewModel = TemplateRoomListViewModel(templateRoomListService: TemplateRoomListService(session: parameters.session)) let view = TemplateRoomList(viewModel: viewModel.context) - .addDependency(AvatarService.instantiate(mediaManager: parameters.session.mediaManager)) + .environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.session.mediaManager))) templateRoomListViewModel = viewModel templateRoomListHostingController = VectorHostingController(rootView: view) } diff --git a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/MockTemplateRoomListScreenState.swift b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/MockTemplateRoomListScreenState.swift index 8b8c0e2a34..59ad3fc8e0 100644 --- a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/MockTemplateRoomListScreenState.swift +++ b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/MockTemplateRoomListScreenState.swift @@ -47,7 +47,7 @@ enum MockTemplateRoomListScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(TemplateRoomList(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } diff --git a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/View/TemplateRoomListRow.swift b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/View/TemplateRoomListRow.swift index a8db7b8ba6..06841bbb2f 100644 --- a/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/View/TemplateRoomListRow.swift +++ b/RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/View/TemplateRoomListRow.swift @@ -42,6 +42,6 @@ struct TemplateRoomListRow: View { struct TemplateRoomListRow_Previews: PreviewProvider { static var previews: some View { TemplateRoomListRow(avatar: MockAvatarInput.example, displayName: "Alice") - .addDependency(MockAvatarService.example) + .environmentObject(AvatarViewModel.withMockedServices()) } } diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift index 175a7d9a0b..e09586b833 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/MockUserSessionsOverviewScreenState.swift @@ -56,7 +56,7 @@ enum MockUserSessionsOverviewScreenState: MockScreenState, CaseIterable { return ( [service, viewModel], AnyView(UserSessionsOverview(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } From 42ce8f708e13fd0caff81a821e9cabda9d41615e Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 12:58:49 +0100 Subject: [PATCH 045/160] Delete DependencyInjection folder --- .../Common/Avatar/View/AvatarImage.swift | 2 - .../Common/Avatar/View/SpaceAvatarImage.swift | 2 - .../Avatar/ViewModel/AvatarViewModel.swift | 2 +- .../DependencyContainer.swift | 46 ------------------- .../DependencyContainerKey.swift | 33 ------------- .../Common/DependencyInjection/Inject.swift | 43 ----------------- .../DependencyInjection/Injectable.swift | 30 ------------ .../InjectableObject.swift | 22 --------- 8 files changed, 1 insertion(+), 179 deletions(-) delete mode 100644 RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainer.swift delete mode 100644 RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift delete mode 100644 RiotSwiftUI/Modules/Common/DependencyInjection/Inject.swift delete mode 100644 RiotSwiftUI/Modules/Common/DependencyInjection/Injectable.swift delete mode 100644 RiotSwiftUI/Modules/Common/DependencyInjection/InjectableObject.swift diff --git a/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift b/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift index ff79501117..b143d4d306 100644 --- a/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift +++ b/RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift @@ -19,7 +19,6 @@ import SwiftUI struct AvatarImage: View { @Environment(\.theme) var theme: ThemeSwiftUI - @Environment(\.dependencies) var dependencies: DependencyContainer @EnvironmentObject var viewModel: AvatarViewModel var mxContentUri: String? @@ -43,7 +42,6 @@ struct AvatarImage: View { .frame(maxWidth: CGFloat(size.rawValue), maxHeight: CGFloat(size.rawValue)) .clipShape(Circle()) .onAppear { - viewModel.inject(dependencies: dependencies) viewModel.loadAvatar( mxContentUri: mxContentUri, matrixItemId: matrixItemId, diff --git a/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift b/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift index c6fe8da0bd..2662831e15 100644 --- a/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift +++ b/RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift @@ -19,7 +19,6 @@ import SwiftUI struct SpaceAvatarImage: View { @Environment(\.theme) var theme: ThemeSwiftUI - @Environment(\.dependencies) var dependencies: DependencyContainer @EnvironmentObject var viewModel: AvatarViewModel var mxContentUri: String? @@ -59,7 +58,6 @@ struct SpaceAvatarImage: View { ) }) .onAppear { - viewModel.inject(dependencies: dependencies) viewModel.loadAvatar( mxContentUri: mxContentUri, matrixItemId: matrixItemId, diff --git a/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift b/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift index f6372c14f8..10055738d4 100644 --- a/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift +++ b/RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift @@ -19,7 +19,7 @@ import DesignKit import Foundation /// Simple ViewModel that supports loading an avatar image -class AvatarViewModel: InjectableObject, ObservableObject { +final class AvatarViewModel: ObservableObject { private let avatarService: AvatarServiceProtocol @Published private(set) var viewState = AvatarViewState.empty diff --git a/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainer.swift b/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainer.swift deleted file mode 100644 index d09fa87f41..0000000000 --- a/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainer.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright 2021 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 - -/// Used for storing and resolving dependencies at runtime. -struct DependencyContainer { - // Stores the dependencies with type information removed. - private var dependencyStore: [String: Any] = [:] - - /// Resolve a dependency by type. - /// - /// Given a particular `Type` (Inferred from return type), - /// generate a key and retrieve from storage. - /// - /// - Returns: The resolved dependency. - func resolve() -> T { - let key = String(describing: T.self) - guard let t = dependencyStore[key] as? T else { - fatalError("No provider registered for type \(T.self)") - } - return t - } - - /// Register a dependency. - /// - /// Given a dependency, generate a key from it's `Type` and save in storage. - /// - Parameter dependency: The dependency to register. - mutating func register(dependency: T) { - let key = String(describing: T.self) - dependencyStore[key] = dependency - } -} diff --git a/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift b/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift deleted file mode 100644 index 9e5403b252..0000000000 --- a/RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright 2021 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 -import SwiftUI - -/// An Environment Key for retrieving runtime dependencies. -/// -/// Dependencies are to be injected into `ObservableObjects` -/// that are owned by a View (i.e. `@StateObject`'s, such as ViewModels owned by the View). -private struct DependencyContainerKey: EnvironmentKey { - static let defaultValue = DependencyContainer() -} - -extension EnvironmentValues { - var dependencies: DependencyContainer { - get { self[DependencyContainerKey.self] } - set { self[DependencyContainerKey.self] = newValue } - } -} diff --git a/RiotSwiftUI/Modules/Common/DependencyInjection/Inject.swift b/RiotSwiftUI/Modules/Common/DependencyInjection/Inject.swift deleted file mode 100644 index d45907eebc..0000000000 --- a/RiotSwiftUI/Modules/Common/DependencyInjection/Inject.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright 2021 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 - -/// A property wrapped used to inject from the dependency container on the instance, to instance properties. -/// -/// ``` -/// @Inject var someClass: SomeClass -/// ``` -@propertyWrapper struct Inject { - static subscript(_enclosingInstance instance: T, - wrapped wrappedKeyPath: ReferenceWritableKeyPath, - storage storageKeyPath: ReferenceWritableKeyPath) -> Value { - get { - // Resolve dependencies from enclosing instance's `dependencies` property - let v: Value = instance.dependencies.resolve() - return v - } - set { - fatalError("Only subscript get is supported for injection") - } - } - - @available(*, unavailable, message: "This property wrapper can only be applied to classes") - var wrappedValue: Value { - get { fatalError("wrappedValue get not used") } - set { fatalError("wrappedValue set not used. \(newValue)") } - } -} diff --git a/RiotSwiftUI/Modules/Common/DependencyInjection/Injectable.swift b/RiotSwiftUI/Modules/Common/DependencyInjection/Injectable.swift deleted file mode 100644 index b05b966e4d..0000000000 --- a/RiotSwiftUI/Modules/Common/DependencyInjection/Injectable.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright 2021 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 - -/// A protocol for classes that can be injected with a dependency container -protocol Injectable: AnyObject { - var dependencies: DependencyContainer! { get set } -} - -extension Injectable { - /// Used to inject the dependency container into an Injectable. - /// - Parameter dependencies: The `DependencyContainer` to inject. - func inject(dependencies: DependencyContainer) { - self.dependencies = dependencies - } -} diff --git a/RiotSwiftUI/Modules/Common/DependencyInjection/InjectableObject.swift b/RiotSwiftUI/Modules/Common/DependencyInjection/InjectableObject.swift deleted file mode 100644 index eab3cdcdfa..0000000000 --- a/RiotSwiftUI/Modules/Common/DependencyInjection/InjectableObject.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2021 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 - -/// Class that can be extended that supports injection and the `@Inject` property wrapper. -open class InjectableObject: Injectable { - var dependencies: DependencyContainer! -} From 3696e385e637f6543d0fb7f5424953c9589f919d Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 13:32:25 +0100 Subject: [PATCH 046/160] Add changelog.d file --- changelog.d/pr-7268.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-7268.bugfix diff --git a/changelog.d/pr-7268.bugfix b/changelog.d/pr-7268.bugfix new file mode 100644 index 0000000000..b6af7cd578 --- /dev/null +++ b/changelog.d/pr-7268.bugfix @@ -0,0 +1 @@ +Fix a crash caused by the missing Avatar Service dependency. From c8bdab7e1871456eee7ac1411e3a1cb65b58c7f0 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Fri, 13 Jan 2023 15:29:51 +0100 Subject: [PATCH 047/160] Code cleanup --- .../MatrixKit/Models/Room/MXKRoomDataSource.h | 2 ++ .../MatrixKit/Models/Room/MXKRoomDataSource.m | 35 +++++++------------ Riot/Modules/Room/RoomViewController.m | 2 +- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h index 9928892f27..87aabe50b3 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h @@ -572,6 +572,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey; Once complete, this local echo will be replaced by the event saved by the homeserver. @param audioFileLocalURL the local filesystem path of the audio file to send. + @param additionalContentParams (optional) the additional parameters to the content. @param mimeType (optional) the mime type of the file. Defaults to `audio/ogg` @param duration the length of the voice message in milliseconds @param samples an array of floating point values normalized to [0, 1], boxed within NSNumbers @@ -580,6 +581,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey; @param failure A block object called when the operation fails. */ - (void)sendVoiceMessage:(NSURL *)audioFileLocalURL + additionalContentParams:(NSDictionary*)additionalContentParams mimeType:mimeType duration:(NSUInteger)duration samples:(NSArray *)samples diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m index d89262a0ec..5f33af838e 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m @@ -1998,6 +1998,7 @@ - (void)sendAudioFile:(NSURL *)audioFileLocalURL mimeType:mimeType success:(void } - (void)sendVoiceMessage:(NSURL *)audioFileLocalURL + additionalContentParams:(NSDictionary *)additionalContentParams mimeType:mimeType duration:(NSUInteger)duration samples:(NSArray *)samples @@ -2006,7 +2007,7 @@ - (void)sendVoiceMessage:(NSURL *)audioFileLocalURL { __block MXEvent *localEchoEvent = nil; - [_room sendVoiceMessage:audioFileLocalURL mimeType:mimeType duration:duration samples:samples threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES]; + [_room sendVoiceMessage:audioFileLocalURL additionalContentParams:additionalContentParams mimeType:mimeType duration:duration samples:samples threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES]; if (localEchoEvent) { @@ -2185,32 +2186,20 @@ - (void)resendEventWithEventId:(NSString *)eventId success:(void (^)(NSString *) [self removeEventWithEventId:eventId]; if (event.isVoiceMessage) { - // Check if it is an actual voice message or a voicebroadcast chunk - if (event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] != nil) { - // VoiceBroadcast chunk - NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioDuration]; - NSDictionary* additionalContentParams = @{ + // Voice message + NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioDuration]; + NSArray *samples = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioWaveform]; + + // Additional content params in case it is a voicebroacast chunk + NSDictionary* additionalContentParams = nil; + if (event.content[kMXEventRelationRelatesToKey] != nil && event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] != nil) { + additionalContentParams = @{ kMXEventRelationRelatesToKey: event.content[kMXEventRelationRelatesToKey], VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType: event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] }; - [_room sendVoiceMessage:localFileURL - additionalContentParams:additionalContentParams - mimeType:mimetype - duration:duration.doubleValue - samples:nil - threadId:self.threadId - localEcho:nil - success:success - failure:failure - keepActualFilename:false]; - - } else { - // Voice message - NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioDuration]; - NSArray *samples = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioWaveform]; - - [self sendVoiceMessage:localFileURL mimeType:mimetype duration:duration.doubleValue samples:samples success:success failure:failure]; } + + [self sendVoiceMessage:localFileURL additionalContentParams:additionalContentParams mimeType:mimetype duration:duration.doubleValue samples:samples success:success failure:failure]; } else { [self sendAudioFile:localFileURL mimeType:mimetype success:success failure:failure]; } diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 7e98732090..87b7e858f2 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -7926,7 +7926,7 @@ - (void)voiceMessageController:(VoiceMessageController *)voiceMessageController samples:(NSArray *)samples completion:(void (^)(BOOL))completion { - [self.roomDataSource sendVoiceMessage:url mimeType:nil duration:duration samples:samples success:^(NSString *eventId) { + [self.roomDataSource sendVoiceMessage:url additionalContentParams:nil mimeType:nil duration:duration samples:samples success:^(NSString *eventId) { MXLogDebug(@"Success with event id %@", eventId); completion(YES); } failure:^(NSError *error) { From 8b692295b183981973b2e32afb5a7efbe57e3391 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 16:15:06 +0100 Subject: [PATCH 048/160] Remove unused code --- RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 5bbb60ad65..725ff2e806 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -21,10 +21,6 @@ struct PollHistory: View { @ObservedObject var viewModel: PollHistoryViewModel.Context - var bindings: PollHistoryViewBindings { - viewModel.viewState.bindings - } - var body: some View { VStack { HStack { From da78ce6683b96d613a33f97f7d44110dddbfca23 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 16:17:45 +0100 Subject: [PATCH 049/160] Cleanup layout --- .../Room/PollHistory/View/PollHistory.swift | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index 725ff2e806..b527dfb28a 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -23,14 +23,12 @@ struct PollHistory: View { var body: some View { VStack { - HStack { - SegmentedPicker( - segments: PollHistoryMode.allCases.map { ($0.segmentTitle, $0) }, - selection: $viewModel.mode, - interSegmentSpacing: 14 - ) - Spacer() - } + SegmentedPicker( + segments: PollHistoryMode.allCases.map { ($0.segmentTitle, $0) }, + selection: $viewModel.mode, + interSegmentSpacing: 14 + ) + .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, 16) if viewModel.viewState.polls.isEmpty { From 546c36e43bb6a785aa69f95cbf2fc8dc3fce965a Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 16:22:35 +0100 Subject: [PATCH 050/160] Add a ScaledMetric --- RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index 58669552ce..373ea0202f 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -25,6 +25,7 @@ struct PollListItem: View { @Environment(\.theme) private var theme private let pollData: PollListData + @ScaledMetric private var imageSize = 16 init(pollData: PollListData) { self.pollData = pollData @@ -39,7 +40,7 @@ struct PollListItem: View { HStack(alignment: .firstTextBaseline, spacing: 8) { Image(uiImage: Asset.Images.pollHistory.image) .resizable() - .frame(width: 16, height: 16) + .frame(width: imageSize, height: imageSize) Text(pollData.question) .foregroundColor(theme.colors.primaryContent) From 5735b5d2ce865bd63177304994e60a7bc06d1b72 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 16:30:16 +0100 Subject: [PATCH 051/160] Add accessibility identifiers in SegmentedPicker --- .../Room/PollHistory/Test/UI/PollHistoryUITests.swift | 6 +++++- .../Modules/Room/PollHistory/View/SegmentedPicker.swift | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift index a313776037..720e49c234 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift @@ -23,18 +23,22 @@ class PollHistoryUITests: MockScreenTestCase { let title = app.navigationBars.firstMatch.identifier let emptyText = app.staticTexts["PollHistory.emptyText"] let items = app.staticTexts["PollListItem.title"] + let selectedSegment = app.buttons["\(VectorL10n.pollHistoryActiveSegmentTitle)-selected"] XCTAssertEqual(title, VectorL10n.pollHistoryTitle) XCTAssertTrue(items.exists) XCTAssertFalse(emptyText.exists) + XCTAssertTrue(selectedSegment.exists) } func testPollHistoryShowsEmptyScreen() { - app.goToScreenWithIdentifier(MockPollHistoryScreenState.activeEmpty.title) + app.goToScreenWithIdentifier(MockPollHistoryScreenState.pastEmpty.title) let title = app.navigationBars.firstMatch.identifier let emptyText = app.staticTexts["PollHistory.emptyText"] let items = app.staticTexts["PollListItem.title"] + let selectedSegment = app.buttons["\(VectorL10n.pollHistoryPastSegmentTitle)-selected"] XCTAssertEqual(title, VectorL10n.pollHistoryTitle) XCTAssertFalse(items.exists) XCTAssertTrue(emptyText.exists) + XCTAssertTrue(selectedSegment.exists) } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift index d60388ad68..0293aa99b1 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift @@ -42,6 +42,7 @@ struct SegmentedPicker: View { .underline(isSelectedSegment) } .accentColor(isSelectedSegment ? theme.colors.accent : theme.colors.primaryContent) + .accessibilityLabel(text + (isSelectedSegment ? "-selected" : "")) } } } From b4c8c0e63279f6733c6317d0d0e67f3b4afedcf6 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 16:38:29 +0100 Subject: [PATCH 052/160] Refactor SegmentedPicker --- .../Room/PollHistory/View/PollHistory.swift | 6 ++-- .../PollHistory/View/SegmentedPicker.swift | 33 ++++++++++++------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index b527dfb28a..b1208f547c 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -24,7 +24,7 @@ struct PollHistory: View { var body: some View { VStack { SegmentedPicker( - segments: PollHistoryMode.allCases.map { ($0.segmentTitle, $0) }, + segments: PollHistoryMode.allCases, selection: $viewModel.mode, interSegmentSpacing: 14 ) @@ -79,8 +79,8 @@ struct PollHistory: View { } } -private extension PollHistoryMode { - var segmentTitle: String { +extension PollHistoryMode: CustomStringConvertible { + var description: String { switch self { case .active: return VectorL10n.pollHistoryActiveSegmentTitle diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift index 0293aa99b1..d669d67ad6 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift @@ -16,14 +16,14 @@ import SwiftUI -struct SegmentedPicker: View { - private let segments: [(String, Tag)] - private let selection: Binding +struct SegmentedPicker: View { + private let segments: [Segment] + private let selection: Binding private let interSegmentSpacing: CGFloat @Environment(\.theme) private var theme - init(segments: [(String, Tag)], selection: Binding, interSegmentSpacing: CGFloat) { + init(segments: [Segment], selection: Binding, interSegmentSpacing: CGFloat) { self.segments = segments self.selection = selection self.interSegmentSpacing = interSegmentSpacing @@ -31,18 +31,18 @@ struct SegmentedPicker: View { var body: some View { HStack(spacing: interSegmentSpacing) { - ForEach(segments, id: \.1) { text, tag in - let isSelectedSegment = tag == selection.wrappedValue + ForEach(segments, id: \.hashValue) { segment in + let isSelectedSegment = segment == selection.wrappedValue Button { - selection.wrappedValue = tag + selection.wrappedValue = segment } label: { - Text(text) + Text(segment.description) .font(isSelectedSegment ? theme.fonts.headline : theme.fonts.body) .underline(isSelectedSegment) } .accentColor(isSelectedSegment ? theme.colors.accent : theme.colors.primaryContent) - .accessibilityLabel(text + (isSelectedSegment ? "-selected" : "")) + .accessibilityLabel(segment.description + (isSelectedSegment ? "-selected" : "")) } } } @@ -52,10 +52,19 @@ struct SegmentedPicker_Previews: PreviewProvider { static var previews: some View { SegmentedPicker( segments: [ - ("Segment 1", "1"), - ("Segment 2", "2") + "Segment 1", + "Segment 2" ], - selection: .constant("1"), + selection: .constant("Segment 1"), + interSegmentSpacing: 14 + ) + + SegmentedPicker( + segments: [ + "Segment 1", + "Segment 2" + ], + selection: .constant("Segment 2"), interSegmentSpacing: 14 ) } From e1b04c10361642e699484fa33a1773ac8de549d9 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 13 Jan 2023 16:40:40 +0100 Subject: [PATCH 053/160] Update build setting --- Config/BuildSettings.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 0c23cdd207..d4b57871a2 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -399,13 +399,7 @@ final class BuildSettings: NSObject { // MARK: - Polls static let pollsEnabled = true - static var pollsHistoryEnabled: Bool { - #if DEBUG - true - #else - false - #endif - } + static var pollsHistoryEnabled: Bool = false // MARK: - Location Sharing From 8b2693284be3d0064aa9bcce9905978886c18911 Mon Sep 17 00:00:00 2001 From: aringenbach Date: Thu, 5 Jan 2023 15:56:04 +0100 Subject: [PATCH 054/160] Rich Text Composer: Enable bulleted & numbered lists support --- .../xcshareddata/swiftpm/Package.resolved | 3 +- Riot/Assets/en.lproj/Vector.strings | 2 + Riot/Generated/Strings.swift | 8 +++ .../Room/Composer/Model/ComposerModels.swift | 62 +++++++++++++------ .../Composer/View/FormattingToolbar.swift | 30 ++++----- changelog.d/7238.feature | 1 + project.yml | 2 +- 7 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 changelog.d/7238.feature diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index 102f87715d..3d0b1278d1 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift", "state" : { - "revision" : "534ee5bae5e8de69ed398937b5edb7b5f21551d2" + "revision" : "2f101426d9df13b830e87a5e6f0ac672e8118ca0", + "version" : "0.15.0" } }, { diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index c1b97f7913..cd852aeda0 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2559,6 +2559,8 @@ To enable access, tap Settings> Location and select Always"; "wysiwyg_composer_format_action_strikethrough" = "Apply underline format"; "wysiwyg_composer_format_action_link" = "Apply link format"; "wysiwyg_composer_format_action_inline_code" = "Apply inline code format"; +"wysiwyg_composer_format_action_unordered_list" = "Toggle bulleted list"; +"wysiwyg_composer_format_action_ordered_list" = "Toggle numbered list"; // Links "wysiwyg_composer_link_action_text" = "Text"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 5730a63056..111f810614 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -9359,6 +9359,10 @@ public class VectorL10n: NSObject { public static var wysiwygComposerFormatActionLink: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_link") } + /// Toggle numbered list + public static var wysiwygComposerFormatActionOrderedList: String { + return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_ordered_list") + } /// Apply underline format public static var wysiwygComposerFormatActionStrikethrough: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_strikethrough") @@ -9367,6 +9371,10 @@ public class VectorL10n: NSObject { public static var wysiwygComposerFormatActionUnderline: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_underline") } + /// Toggle bulleted list + public static var wysiwygComposerFormatActionUnorderedList: String { + return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_unordered_list") + } /// Create a link public static var wysiwygComposerLinkActionCreateTitle: String { return VectorL10n.tr("Vector", "wysiwyg_composer_link_action_create_title") diff --git a/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift b/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift index bc2e8771d8..d63c096cdd 100644 --- a/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift +++ b/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift @@ -35,6 +35,8 @@ enum FormatType { case underline case strikethrough case inlineCode + case unorderedList + case orderedList case link } @@ -54,14 +56,18 @@ extension FormatItem { return Asset.Images.bold.name case .italic: return Asset.Images.italic.name - case .strikethrough: - return Asset.Images.strikethrough.name case .underline: return Asset.Images.underlined.name - case .link: - return Asset.Images.link.name + case .strikethrough: + return Asset.Images.strikethrough.name case .inlineCode: return Asset.Images.code.name + case .unorderedList: + return Asset.Images.bulletList.name + case .orderedList: + return Asset.Images.numberedList.name + case .link: + return Asset.Images.link.name } } @@ -71,14 +77,18 @@ extension FormatItem { return "boldButton" case .italic: return "italicButton" - case .strikethrough: - return "strikethroughButton" case .underline: return "underlineButton" - case .link: - return "linkButton" + case .strikethrough: + return "strikethroughButton" case .inlineCode: return "inlineCodeButton" + case .unorderedList: + return "unorderedListButton" + case .orderedList: + return "orderedListButton" + case .link: + return "linkButton" } } @@ -88,14 +98,18 @@ extension FormatItem { return VectorL10n.wysiwygComposerFormatActionBold case .italic: return VectorL10n.wysiwygComposerFormatActionItalic - case .strikethrough: - return VectorL10n.wysiwygComposerFormatActionStrikethrough case .underline: return VectorL10n.wysiwygComposerFormatActionUnderline - case .link: - return VectorL10n.wysiwygComposerFormatActionLink + case .strikethrough: + return VectorL10n.wysiwygComposerFormatActionStrikethrough case .inlineCode: return VectorL10n.wysiwygComposerFormatActionInlineCode + case .unorderedList: + return VectorL10n.wysiwygComposerFormatActionUnorderedList + case .orderedList: + return VectorL10n.wysiwygComposerFormatActionOrderedList + case .link: + return VectorL10n.wysiwygComposerFormatActionLink } } } @@ -108,14 +122,18 @@ extension FormatType { return .bold case .italic: return .italic - case .strikethrough: - return .strikeThrough case .underline: return .underline - case .link: - return .link + case .strikethrough: + return .strikeThrough case .inlineCode: return .inlineCode + case .unorderedList: + return .unorderedList + case .orderedList: + return .orderedList + case .link: + return .link } } @@ -127,14 +145,18 @@ extension FormatType { return .bold case .italic: return .italic - case .strikethrough: - return .strikeThrough case .underline: return .underline - case .link: - return .link + case .strikethrough: + return .strikeThrough + case .unorderedList: + return .unorderedList + case .orderedList: + return .orderedList case .inlineCode: return .inlineCode + case .link: + return .link } } } diff --git a/RiotSwiftUI/Modules/Room/Composer/View/FormattingToolbar.swift b/RiotSwiftUI/Modules/Room/Composer/View/FormattingToolbar.swift index d8670ee0c3..e7d59a989e 100644 --- a/RiotSwiftUI/Modules/Room/Composer/View/FormattingToolbar.swift +++ b/RiotSwiftUI/Modules/Room/Composer/View/FormattingToolbar.swift @@ -32,21 +32,23 @@ struct FormattingToolbar: View { var formatAction: (FormatType) -> Void var body: some View { - HStack(spacing: 4) { - ForEach(formatItems) { item in - Button { - formatAction(item.type) - } label: { - Image(item.icon) - .renderingMode(.template) - .foregroundColor(getForegroundColor(for: item)) + ScrollView(.horizontal) { + HStack(spacing: 4) { + ForEach(formatItems) { item in + Button { + formatAction(item.type) + } label: { + Image(item.icon) + .renderingMode(.template) + .foregroundColor(getForegroundColor(for: item)) + } + .disabled(item.state == .disabled) + .frame(width: 44, height: 44) + .background(getBackgroundColor(for: item)) + .cornerRadius(8) + .accessibilityIdentifier(item.accessibilityIdentifier) + .accessibilityLabel(item.accessibilityLabel) } - .disabled(item.state == .disabled) - .frame(width: 44, height: 44) - .background(getBackgroundColor(for: item)) - .cornerRadius(8) - .accessibilityIdentifier(item.accessibilityIdentifier) - .accessibilityLabel(item.accessibilityLabel) } } } diff --git a/changelog.d/7238.feature b/changelog.d/7238.feature new file mode 100644 index 0000000000..173f1195ed --- /dev/null +++ b/changelog.d/7238.feature @@ -0,0 +1 @@ +Rich Text Composer: Enable bulleted/numbered lists support diff --git a/project.yml b/project.yml index f2c4dbc230..7d0096d517 100644 --- a/project.yml +++ b/project.yml @@ -53,7 +53,7 @@ packages: branch: main WysiwygComposer: url: https://github.com/matrix-org/matrix-wysiwyg-composer-swift - revision: 534ee5bae5e8de69ed398937b5edb7b5f21551d2 + version: 0.15.0 DeviceKit: url: https://github.com/devicekit/DeviceKit majorVersion: 4.7.0 From 036a9f00969f63e3c8988a51ffaa91acbe134509 Mon Sep 17 00:00:00 2001 From: aringenbach Date: Mon, 16 Jan 2023 11:44:40 +0100 Subject: [PATCH 055/160] Rich Text Composer: Enable quote & code blocks support --- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../code_block.imageset/Contents.json | 23 ++++++++++ .../code_block.imageset/code_block.png | Bin 0 -> 493 bytes .../code_block.imageset/code_block@2x.png | Bin 0 -> 649 bytes .../code_block.imageset/code_block@3x.png | Bin 0 -> 953 bytes Riot/Assets/en.lproj/Vector.strings | 4 ++ Riot/Generated/Images.swift | 1 + Riot/Generated/Strings.swift | 8 ++++ .../Room/Composer/Model/ComposerModels.swift | 42 +++++++++++++----- changelog.d/7271.feature | 1 + project.yml | 2 +- 11 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 Riot/Assets/Images.xcassets/Composer/code_block.imageset/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Composer/code_block.imageset/code_block.png create mode 100644 Riot/Assets/Images.xcassets/Composer/code_block.imageset/code_block@2x.png create mode 100644 Riot/Assets/Images.xcassets/Composer/code_block.imageset/code_block@3x.png create mode 100644 changelog.d/7271.feature diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3d0b1278d1..1cc4e6de40 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift", "state" : { - "revision" : "2f101426d9df13b830e87a5e6f0ac672e8118ca0", - "version" : "0.15.0" + "revision" : "e63034b57eeec1164e6cfcccf817f3b764b56a83", + "version" : "0.17.0" } }, { diff --git a/Riot/Assets/Images.xcassets/Composer/code_block.imageset/Contents.json b/Riot/Assets/Images.xcassets/Composer/code_block.imageset/Contents.json new file mode 100644 index 0000000000..bcb234ccc0 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Composer/code_block.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "code_block.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "code_block@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "code_block@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Composer/code_block.imageset/code_block.png b/Riot/Assets/Images.xcassets/Composer/code_block.imageset/code_block.png new file mode 100644 index 0000000000000000000000000000000000000000..a70342a591b96912c2c7d0fa1ccc02f0c3e2e430 GIT binary patch literal 493 zcmV%XoH!HrD}xP%)3H{b|8LKiNYNay(m zfsg{FvEW93Ni);;Ufllg zWqWA0kJmjPEAZ58msR<4E#E9S367A|Q87OfP!EzMR}g$5VMhHS;fO_i6%!}2R6u?D zEIB8#FN?!yOr34>BKM8ALSg}up+6qk`?-si%)5lPlT9peZI${wRQc_)I}*LSm)1g$ za-Lf`DbVBHpA8XKYv-rk!~%-Rj-H7`{Zd0`n!IkExvTQTR*@1Rk|vATOWe1l2{SIa zLdP0v7p3khaU|fs7p*1w5Axi5kOpoo`9*;s7>dlEM?i%GDo6?UE>DNc@LgBROeG z>ey0@m@_s%9+yQL2jsAIj2fHUv_0*bTa9f(BZBx|?wp|~gE zD`uCy(|z!Ohvaq2s$w}Ngk60sf`3jh&@{n7(*y%e6AaX0_&jn}B(}g3uAkyn{S@Lqo7iTlD!0HO*#HVMYo2neG(oJ*a9AH6h18d?LB>bw% zL&S;Jv^G)8K&f~x{m}Zh`^rWIZOo^#Un)>S95pcbi}9w1{fJ|HFsUzOM>wfvNhpSyin^N z*kppg9z0j&x_l4_wQu4w6KtSel}7{z*|Dv7!RjegG{JSwZB-6WpESmWc)_|FT?yEi z68WmznODX0SG57hKK8eW-3Djt0TV&4#0z0X)-=ID(*y%e6AUy>;Z02X3nqR@-lpII z`W6!sEcCIQfhDLhe{8xaOY{ZNsJC-dNOu3SV#`OQSk!kYh0=}gyX2+KOS@wp+yxKd jb@PHqjf>&~0SEj7>wg-`p8M^s00000NkvXXu0mjfAGsgQ literal 0 HcmV?d00001 diff --git a/Riot/Assets/Images.xcassets/Composer/code_block.imageset/code_block@3x.png b/Riot/Assets/Images.xcassets/Composer/code_block.imageset/code_block@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..21bd83678de90b26f05c9b880a1671e48d592ffa GIT binary patch literal 953 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!oCO|{#S9FJ79h;%I?XTvD9BhG z=+U|c2;0%p@!cok8 zNjSvTF)?^0>yix%oAf+FUWnZgSJh!Cof;yV%4zFZ&HRG*l61;tlPu}ob%GNGK0P^W zu#NTPZ!^Z*$wu?l(*E2QW^fc>d3djBvexXkpSgJ0qS?MGNvt_ga?z9{{M3WQ^{W62QCGDI#d*kEx6@^-{n);s$;{7G-rxCk_JBnde3D0Mip7$O9n-`%W{ z)VO_ZfBn^*7eRq17k3}~b=vx<8oT=PZTuB!!h7d)g`@{fd(-_O{DQ_l*)RHQWlqJH zef{wM>A{cFs~*ZG=xKH+OqxC(JAid zzCH8eea9gy9X-k1apBXRPTiB;3nGe+9hvgPHNeL*xyWAC}Om-5(k?LF&&=hlV`2(zEC0-xA=kKDXtq`^sml z7JuKe_vbGrub`-a#T&0V2b@p#e)Qx*H4}e@E@ys&!wEY?Hsc-(mXeX zA667mHT-Q}->cZpG0(GK^`e}6b(n1Qma^qGFV1>(_bs)16S1X#ORl+7hJ0%1<6kaO z0YcKVO5b?1D=EEBLXR!mJNCwPE?cSi!zoin zrbuAJ>#SFGI(HmC$|ms3eLfueN+f0ajsPktXOt$EG!WlmFu< Location and select Always"; "wysiwyg_composer_format_action_inline_code" = "Apply inline code format"; "wysiwyg_composer_format_action_unordered_list" = "Toggle bulleted list"; "wysiwyg_composer_format_action_ordered_list" = "Toggle numbered list"; +"wysiwyg_composer_format_action_code_block" = "Toggle code block"; +"wysiwyg_composer_format_action_quote" = "Toggle quote"; + + // Links "wysiwyg_composer_link_action_text" = "Text"; diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index ed763a1710..5f3ef86c54 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -110,6 +110,7 @@ internal class Asset: NSObject { internal static let strikethrough = ImageAsset(name: "Strikethrough") internal static let underlined = ImageAsset(name: "Underlined") internal static let bulletList = ImageAsset(name: "bullet_list") + internal static let codeBlock = ImageAsset(name: "code_block") internal static let indentDecrease = ImageAsset(name: "indent_decrease") internal static let maximiseComposer = ImageAsset(name: "maximise_composer") internal static let minimiseComposer = ImageAsset(name: "minimise_composer") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 111f810614..920857f286 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -9347,6 +9347,10 @@ public class VectorL10n: NSObject { public static var wysiwygComposerFormatActionBold: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_bold") } + /// Toggle code block + public static var wysiwygComposerFormatActionCodeBlock: String { + return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_code_block") + } /// Apply inline code format public static var wysiwygComposerFormatActionInlineCode: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_inline_code") @@ -9363,6 +9367,10 @@ public class VectorL10n: NSObject { public static var wysiwygComposerFormatActionOrderedList: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_ordered_list") } + /// Toggle quote + public static var wysiwygComposerFormatActionQuote: String { + return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_quote") + } /// Apply underline format public static var wysiwygComposerFormatActionStrikethrough: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_strikethrough") diff --git a/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift b/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift index d63c096cdd..5525e99403 100644 --- a/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift +++ b/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift @@ -34,9 +34,11 @@ enum FormatType { case italic case underline case strikethrough - case inlineCode case unorderedList case orderedList + case inlineCode + case codeBlock + case quote case link } @@ -60,12 +62,16 @@ extension FormatItem { return Asset.Images.underlined.name case .strikethrough: return Asset.Images.strikethrough.name - case .inlineCode: - return Asset.Images.code.name case .unorderedList: return Asset.Images.bulletList.name case .orderedList: return Asset.Images.numberedList.name + case .inlineCode: + return Asset.Images.code.name + case .codeBlock: + return Asset.Images.codeBlock.name + case .quote: + return Asset.Images.quote.name case .link: return Asset.Images.link.name } @@ -81,12 +87,16 @@ extension FormatItem { return "underlineButton" case .strikethrough: return "strikethroughButton" - case .inlineCode: - return "inlineCodeButton" case .unorderedList: return "unorderedListButton" case .orderedList: return "orderedListButton" + case .inlineCode: + return "inlineCodeButton" + case .codeBlock: + return "codeBlockButton" + case .quote: + return "quoteButton" case .link: return "linkButton" } @@ -102,12 +112,16 @@ extension FormatItem { return VectorL10n.wysiwygComposerFormatActionUnderline case .strikethrough: return VectorL10n.wysiwygComposerFormatActionStrikethrough - case .inlineCode: - return VectorL10n.wysiwygComposerFormatActionInlineCode case .unorderedList: return VectorL10n.wysiwygComposerFormatActionUnorderedList case .orderedList: return VectorL10n.wysiwygComposerFormatActionOrderedList + case .inlineCode: + return VectorL10n.wysiwygComposerFormatActionInlineCode + case .codeBlock: + return VectorL10n.wysiwygComposerFormatActionCodeBlock + case .quote: + return VectorL10n.wysiwygComposerFormatActionQuote case .link: return VectorL10n.wysiwygComposerFormatActionLink } @@ -126,12 +140,16 @@ extension FormatType { return .underline case .strikethrough: return .strikeThrough - case .inlineCode: - return .inlineCode case .unorderedList: return .unorderedList case .orderedList: return .orderedList + case .inlineCode: + return .inlineCode + case .codeBlock: + return .codeBlock + case .quote: + return .quote case .link: return .link } @@ -155,6 +173,10 @@ extension FormatType { return .orderedList case .inlineCode: return .inlineCode + case .codeBlock: + return .codeBlock + case .quote: + return .quote case .link: return .link } @@ -189,5 +211,3 @@ final class LinkActionWrapper: NSObject { super.init() } } - - diff --git a/changelog.d/7271.feature b/changelog.d/7271.feature new file mode 100644 index 0000000000..f2ae089f9f --- /dev/null +++ b/changelog.d/7271.feature @@ -0,0 +1 @@ +Rich Text Composer: Enable quote & code blocks support diff --git a/project.yml b/project.yml index 7d0096d517..c2de639efa 100644 --- a/project.yml +++ b/project.yml @@ -53,7 +53,7 @@ packages: branch: main WysiwygComposer: url: https://github.com/matrix-org/matrix-wysiwyg-composer-swift - version: 0.15.0 + version: 0.17.0 DeviceKit: url: https://github.com/devicekit/DeviceKit majorVersion: 4.7.0 From 25a52a24532cfa9bb6b27d663ceb1d80584ccf2b Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Mon, 16 Jan 2023 12:01:24 +0100 Subject: [PATCH 056/160] Improve accessibility --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++++ .../Room/PollHistory/Test/UI/PollHistoryUITests.swift | 6 ++++-- .../Modules/Room/PollHistory/View/SegmentedPicker.swift | 3 ++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 62f25672c9..41cca1e700 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -96,6 +96,7 @@ // Accessibility "accessibility_checkbox_label" = "checkbox"; "accessibility_button_label" = "button"; +"accessibility_selected" = "selected"; // MARK: Onboarding "onboarding_splash_register_button_title" = "Create account"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index e0be60ceee..37dfa9f531 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -27,6 +27,10 @@ public class VectorL10n: NSObject { public static var accessibilityCheckboxLabel: String { return VectorL10n.tr("Vector", "accessibility_checkbox_label") } + /// selected + public static var accessibilitySelected: String { + return VectorL10n.tr("Vector", "accessibility_selected") + } /// Unable to verify email address. Please check your email and click on the link it contains. Once this is done, click continue public static var accountEmailValidationError: String { return VectorL10n.tr("Vector", "account_email_validation_error") diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift index 720e49c234..3fcc05c7b3 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift @@ -23,11 +23,12 @@ class PollHistoryUITests: MockScreenTestCase { let title = app.navigationBars.firstMatch.identifier let emptyText = app.staticTexts["PollHistory.emptyText"] let items = app.staticTexts["PollListItem.title"] - let selectedSegment = app.buttons["\(VectorL10n.pollHistoryActiveSegmentTitle)-selected"] + let selectedSegment = app.buttons[VectorL10n.pollHistoryActiveSegmentTitle] XCTAssertEqual(title, VectorL10n.pollHistoryTitle) XCTAssertTrue(items.exists) XCTAssertFalse(emptyText.exists) XCTAssertTrue(selectedSegment.exists) + XCTAssertEqual(selectedSegment.value as? String, VectorL10n.accessibilitySelected) } func testPollHistoryShowsEmptyScreen() { @@ -35,10 +36,11 @@ class PollHistoryUITests: MockScreenTestCase { let title = app.navigationBars.firstMatch.identifier let emptyText = app.staticTexts["PollHistory.emptyText"] let items = app.staticTexts["PollListItem.title"] - let selectedSegment = app.buttons["\(VectorL10n.pollHistoryPastSegmentTitle)-selected"] + let selectedSegment = app.buttons[VectorL10n.pollHistoryPastSegmentTitle] XCTAssertEqual(title, VectorL10n.pollHistoryTitle) XCTAssertFalse(items.exists) XCTAssertTrue(emptyText.exists) XCTAssertTrue(selectedSegment.exists) + XCTAssertEqual(selectedSegment.value as? String, VectorL10n.accessibilitySelected) } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift index d669d67ad6..520a649c7a 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/SegmentedPicker.swift @@ -42,7 +42,8 @@ struct SegmentedPicker: View { .underline(isSelectedSegment) } .accentColor(isSelectedSegment ? theme.colors.accent : theme.colors.primaryContent) - .accessibilityLabel(segment.description + (isSelectedSegment ? "-selected" : "")) + .accessibilityLabel(segment.description) + .accessibilityValue(isSelectedSegment ? VectorL10n.accessibilitySelected : "") } } } From f098e77ff62867c9db4d674a31988bb4b63f406a Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Fri, 13 Jan 2023 15:00:59 +0000 Subject: [PATCH 057/160] Add labs settings for crypto v2 --- Config/CommonConfiguration.swift | 6 ++ Riot/Assets/en.lproj/Vector.strings | 3 + Riot/Generated/Strings.swift | 12 ++++ Riot/Managers/Settings/RiotSettings.swift | 6 ++ .../Modules/Settings/SettingsViewController.m | 58 ++++++++++++++++++- changelog.d/pr-7272.change | 1 + 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 changelog.d/pr-7272.change diff --git a/Config/CommonConfiguration.swift b/Config/CommonConfiguration.swift index fee3796ff1..f3172a7109 100644 --- a/Config/CommonConfiguration.swift +++ b/Config/CommonConfiguration.swift @@ -91,6 +91,12 @@ class CommonConfiguration: NSObject, Configurable { MXKeyProvider.sharedInstance().delegate = EncryptionKeyManager.shared sdkOptions.enableNewClientInformationFeature = RiotSettings.shared.enableClientInformationFeature + + #if DEBUG + if sdkOptions.isCryptoSDKAvailable { + sdkOptions.enableCryptoSDK = RiotSettings.shared.enableCryptoSDK + } + #endif } private func makeASCIIUserAgent() -> String? { diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index c1b97f7913..bf1b697465 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -803,6 +803,9 @@ Tap the + to start adding people."; "settings_labs_enable_new_app_layout" = "New Application Layout"; "settings_labs_enable_wysiwyg_composer" = "Try out the rich text editor"; "settings_labs_enable_voice_broadcast" = "Voice broadcast"; +"settings_labs_enable_crypto_sdk" = "Enable new rust-based Crypto SDK"; +"settings_labs_confirm_crypto_sdk" = "This action cannot be undone"; +"settings_labs_disable_crypto_sdk" = "Crypto SDK is enabled. To disable please reinstall the app"; "settings_version" = "Version %@"; "settings_olm_version" = "Olm Version %@"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 5730a63056..3de9542c2e 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -7547,10 +7547,18 @@ public class VectorL10n: NSObject { public static var settingsLabs: String { return VectorL10n.tr("Vector", "settings_labs") } + /// This action cannot be undone + public static var settingsLabsConfirmCryptoSdk: String { + return VectorL10n.tr("Vector", "settings_labs_confirm_crypto_sdk") + } /// Create conference calls with jitsi public static var settingsLabsCreateConferenceWithJitsi: String { return VectorL10n.tr("Vector", "settings_labs_create_conference_with_jitsi") } + /// Crypto SDK is enabled. To disable please reinstall the app + public static var settingsLabsDisableCryptoSdk: String { + return VectorL10n.tr("Vector", "settings_labs_disable_crypto_sdk") + } /// End-to-End Encryption public static var settingsLabsE2eEncryption: String { return VectorL10n.tr("Vector", "settings_labs_e2e_encryption") @@ -7563,6 +7571,10 @@ public class VectorL10n: NSObject { public static var settingsLabsEnableAutoReportDecryptionErrors: String { return VectorL10n.tr("Vector", "settings_labs_enable_auto_report_decryption_errors") } + /// Enable new rust-based Crypto SDK + public static var settingsLabsEnableCryptoSdk: String { + return VectorL10n.tr("Vector", "settings_labs_enable_crypto_sdk") + } /// Live location sharing - share current location (active development, and temporarily, locations persist in room history) public static var settingsLabsEnableLiveLocationSharing: String { return VectorL10n.tr("Vector", "settings_labs_enable_live_location_sharing") diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 591f3968a3..d9e64a1af2 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -191,6 +191,12 @@ final class RiotSettings: NSObject { /// Flag indicating if the voice broadcast feature is enabled @UserDefault(key: "enableVoiceBroadcast", defaultValue: false, storage: defaults) var enableVoiceBroadcast + + #if DEBUG + /// Flag indicating if we are using rust-based `MatrixCryptoSDK` instead of `MatrixSDK`'s internal crypto module + @UserDefault(key: "enableCryptoSDK", defaultValue: false, storage: defaults) + var enableCryptoSDK + #endif // MARK: Calls diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index 54bb95d34e..90533cfd13 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -176,7 +176,8 @@ typedef NS_ENUM(NSUInteger, LABS_ENABLE) LABS_ENABLE_NEW_SESSION_MANAGER, LABS_ENABLE_NEW_CLIENT_INFO_FEATURE, LABS_ENABLE_WYSIWYG_COMPOSER, - LABS_ENABLE_VOICE_BROADCAST + LABS_ENABLE_VOICE_BROADCAST, + LABS_ENABLE_CRYPTO_SDK }; typedef NS_ENUM(NSUInteger, SECURITY) @@ -587,6 +588,13 @@ - (void)updateSections if (BuildSettings.settingsScreenShowLabSettings) { Section *sectionLabs = [Section sectionWithTag:SECTION_TAG_LABS]; + #if DEBUG + if (MXSDKOptions.sharedInstance.isCryptoSDKAvailable) + { + [sectionLabs addRowWithTag:LABS_ENABLE_CRYPTO_SDK]; + } + #endif + [sectionLabs addRowWithTag:LABS_ENABLE_RINGING_FOR_GROUP_CALLS_INDEX]; [sectionLabs addRowWithTag:LABS_ENABLE_THREADS_INDEX]; [sectionLabs addRowWithTag:LABS_ENABLE_AUTO_REPORT_DECRYPTION_ERRORS]; @@ -2583,6 +2591,23 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = labelAndSwitchCell; } + else + { + #if DEBUG + if (row == LABS_ENABLE_CRYPTO_SDK) + { + MXKTableViewCellWithLabelAndSwitch *labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; + BOOL isEnabled = MXSDKOptions.sharedInstance.enableCryptoSDK; + labelAndSwitchCell.mxkLabel.text = isEnabled ? VectorL10n.settingsLabsDisableCryptoSdk : VectorL10n.settingsLabsEnableCryptoSdk; + labelAndSwitchCell.mxkSwitch.on = isEnabled; + [labelAndSwitchCell.mxkSwitch setEnabled:!isEnabled]; + labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor; + [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableCryptoSDKFeature:) forControlEvents:UIControlEventTouchUpInside]; + + cell = labelAndSwitchCell; + } + #endif + } } else if (section == SECTION_TAG_SECURITY) { @@ -3354,6 +3379,37 @@ - (void)toggleEnableVoiceBroadcastFeature:(UISwitch *)sender RiotSettings.shared.enableVoiceBroadcast = sender.isOn; } +#if DEBUG +- (void)toggleEnableCryptoSDKFeature:(UISwitch *)sender +{ + BOOL isEnabled = sender.isOn; + MXWeakify(self); + + [currentAlert dismissViewControllerAnimated:NO completion:nil]; + UIAlertController *confirmationAlert = [UIAlertController alertControllerWithTitle:nil + message:VectorL10n.settingsLabsConfirmCryptoSdk + preferredStyle:UIAlertControllerStyleAlert]; + + [confirmationAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + + [sender setOn:NO animated:YES]; + }]]; + + [confirmationAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n continue] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + + RiotSettings.shared.enableCryptoSDK = isEnabled; + MXSDKOptions.sharedInstance.enableCryptoSDK = isEnabled; + [[AppDelegate theDelegate] reloadMatrixSessions:YES]; + }]]; + + [self presentViewController:confirmationAlert animated:YES completion:nil]; + currentAlert = confirmationAlert; +} +#endif + - (void)togglePinRoomsWithMissedNotif:(UISwitch *)sender { RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome = sender.isOn; diff --git a/changelog.d/pr-7272.change b/changelog.d/pr-7272.change new file mode 100644 index 0000000000..04a8dcc2e1 --- /dev/null +++ b/changelog.d/pr-7272.change @@ -0,0 +1 @@ +CryptoSDK: Add labs settings to enable Crypto SDK From ee51fc74855c5e573a28c3a8952da40b03e03c77 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Thu, 12 Jan 2023 16:53:31 +0100 Subject: [PATCH 058/160] Improved voice broadcast completion detection during playback --- .../VoiceBroadcastAggregator.swift | 8 ++++- .../VoiceBroadcastPlaybackViewModel.swift | 32 +++++++++++++++++-- changelog.d/pr-7273.change | 1 + 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 changelog.d/pr-7273.change diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift index f9afbadc1d..1741dc14cc 100644 --- a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift +++ b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift @@ -53,6 +53,8 @@ public class VoiceBroadcastAggregator { private var voiceBroadcastInfoStartEventContent: VoiceBroadcastInfo! private var voiceBroadcastSenderId: String! + public private(set) var voiceBroadcastLastChunkSequence: Int = 0 + private var referenceEventsListener: Any? private var events: [MXEvent] = [] @@ -168,7 +170,10 @@ public class VoiceBroadcastAggregator { let state = VoiceBroadcastInfoState(rawValue: voiceBroadcastInfo.state) else { return } - + // For .pause and .stopped, if there is a lastChunkSequence (ie its value is > 0), we store it + if [.stopped, .paused].contains(state), voiceBroadcastInfo.lastChunkSequence > 0 { + self.voiceBroadcastLastChunkSequence = voiceBroadcastInfo.lastChunkSequence + } self.delegate?.voiceBroadcastAggregator(self, didReceiveState: state) } } @@ -187,6 +192,7 @@ public class VoiceBroadcastAggregator { } self.events.removeAll() + self.voiceBroadcastLastChunkSequence = 0 let filteredChunk = response.chunk.filter { event in event.sender == self.voiceBroadcastSenderId && diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift index 1f5ac98721..9f96a0d521 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift @@ -43,7 +43,14 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic private var reloadVoiceBroadcastChunkQueue: Bool = false private var seekToChunkTime: TimeInterval? + private var lastChunkAddedToPlayer: UInt = 0 + private var isPlayingLastChunk: Bool { + // We can't play the last chunk if the brodcast is not stopped + guard state.broadcastState == .stopped else { + return false + } + let chunks = reorderVoiceBroadcastChunks(chunks: Array(voiceBroadcastAggregator.voiceBroadcast.chunks)) guard let chunkDuration = chunks.last?.duration else { return false @@ -168,11 +175,24 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic private func stopIfVoiceBroadcastOver() { MXLog.debug("[VoiceBroadcastPlaybackViewModel] stopIfVoiceBroadcastOver") + var shouldStop = false + // Check if the broadcast is over before stopping everything - // If not, the player should not stopped. The view state must be move to buffering - if state.broadcastState == .stopped, isPlayingLastChunk { + if state.broadcastState == .stopped { + // If we known the last chunk sequence, use it to check if we need to stop + // Note: it's possible to be in .stopped state and to still have a last chunk sequence at 0 (old versions or a crash during recording). In this case, we use isPlayingLastChunk as a fallback solution + if voiceBroadcastAggregator.voiceBroadcastLastChunkSequence > 0 { + // we should stop only if we have already added the last chunk to the player + shouldStop = (lastChunkAddedToPlayer == voiceBroadcastAggregator.voiceBroadcastLastChunkSequence) + } else { + shouldStop = isPlayingLastChunk + } + } + + if shouldStop { stop() } else { + // If not, the player should not stopped. The view state must be move to buffering state.playbackState = .buffering } } @@ -200,6 +220,7 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic private func seek(to seekTime: Float) { // Flush the chunks queue and the current audio player playlist + lastChunkAddedToPlayer = 0 voiceBroadcastChunkQueue = [] reloadVoiceBroadcastChunkQueue = isProcessingVoiceBroadcastChunk audioPlayer?.removeAllPlayerItems() @@ -294,7 +315,7 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic guard result.eventIdentifier == chunk.attachment.eventId else { return } - + self.lastChunkAddedToPlayer = max(self.lastChunkAddedToPlayer, chunk.sequence) self.voiceBroadcastAttachmentCacheManagerLoadResults.append(result) // Instanciate audioPlayer if needed. @@ -436,6 +457,11 @@ extension VoiceBroadcastPlaybackViewModel: VoiceBroadcastAggregatorDelegate { // Handle the live icon appearance state.playingState.isLive = isLivePlayback + + // Handle the case where the playback state is .buffering and the new broadcast state is .stopped + if didReceiveState == .stopped, self.state.playbackState == .buffering { + stopIfVoiceBroadcastOver() + } } func voiceBroadcastAggregatorDidUpdateData(_ aggregator: VoiceBroadcastAggregator) { diff --git a/changelog.d/pr-7273.change b/changelog.d/pr-7273.change new file mode 100644 index 0000000000..2c3d47b2e1 --- /dev/null +++ b/changelog.d/pr-7273.change @@ -0,0 +1 @@ +Voice Broadcast: Improved detection of voice broadcast completion during playback. From acf83a3f9b7f910eb7340c51878b9c7704ea929f Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Mon, 16 Jan 2023 14:45:21 +0100 Subject: [PATCH 059/160] Fix build error --- .../Modules/Room/PollHistory/MockPollHistoryScreenState.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift index 08b33293bd..c00ccf528b 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift @@ -58,7 +58,7 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable { return ( [pollHistoryMode, viewModel], AnyView(PollHistory(viewModel: viewModel.context) - .addDependency(MockAvatarService.example)) + .environmentObject(AvatarViewModel.withMockedServices())) ) } } From dcd5e66068399672653063249da2457ca0315ad4 Mon Sep 17 00:00:00 2001 From: Philippe Loriaux Date: Mon, 16 Jan 2023 14:47:48 +0100 Subject: [PATCH 060/160] Remove "Leave" button on Room details screen --- .../Settings/RoomSettingsViewController.m | 90 +------------------ 1 file changed, 1 insertion(+), 89 deletions(-) diff --git a/Riot/Modules/Room/Settings/RoomSettingsViewController.m b/Riot/Modules/Room/Settings/RoomSettingsViewController.m index d042a5f183..d958bd2e84 100644 --- a/Riot/Modules/Room/Settings/RoomSettingsViewController.m +++ b/Riot/Modules/Room/Settings/RoomSettingsViewController.m @@ -52,8 +52,7 @@ ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC, ROOM_SETTINGS_MAIN_SECTION_ROW_TAG, ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT, - ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS, - ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE + ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS }; enum @@ -515,7 +514,6 @@ - (void)updateSections { [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS]; } - [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE]; [tmpSections addObject:sectionMain]; if (RiotSettings.shared.roomSettingsScreenAllowChangingAccessSettings) @@ -2325,22 +2323,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = favoriteCell; } } - else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE) - { - MXKTableViewCellWithButton *leaveCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath]; - - NSString* title = [VectorL10n leave]; - - [leaveCell.mxkButton setTitle:title forState:UIControlStateNormal]; - [leaveCell.mxkButton setTitle:title forState:UIControlStateHighlighted]; - [leaveCell.mxkButton setTintColor:ThemeService.shared.theme.tintColor]; - leaveCell.mxkButton.titleLabel.font = [UIFont systemFontOfSize:17]; - - [leaveCell.mxkButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; - [leaveCell.mxkButton addTarget:self action:@selector(onLeave:) forControlEvents:UIControlEventTouchUpInside]; - - cell = leaveCell; - } } else if (section == SECTION_TAG_ACCESS) { @@ -3196,76 +3178,6 @@ - (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)ro #pragma mark - actions -- (void)onLeave:(id)sender -{ - // Prompt user before leaving the room - __weak typeof(self) weakSelf = self; - - [currentAlert dismissViewControllerAnimated:NO completion:nil]; - - NSString *title, *message; - if ([self.mainSession roomWithRoomId:self.roomId].isDirect) - { - title = [VectorL10n roomParticipantsLeavePromptTitleForDm]; - message = [VectorL10n roomParticipantsLeavePromptMsgForDm]; - } - else - { - title = [VectorL10n roomParticipantsLeavePromptTitle]; - message = [VectorL10n roomParticipantsLeavePromptMsg]; - } - - currentAlert = [UIAlertController alertControllerWithTitle:title - message:message - preferredStyle:UIAlertControllerStyleAlert]; - - [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] - style:UIAlertActionStyleCancel - handler:^(UIAlertAction * action) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - } - - }]]; - - [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n leave] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - - [self startActivityIndicator]; - [self->mxRoom leave:^{ - - if (self.delegate) { - [self.delegate roomSettingsViewControllerDidLeaveRoom:self]; - } else { - [[LegacyAppDelegate theDelegate] restoreInitialDisplay:nil]; - } - - } failure:^(NSError *error) { - - [self stopActivityIndicator]; - - MXLogDebug(@"[RoomSettingsViewController] Leave room failed"); - // Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; - - }]; - } - - }]]; - - [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCLeaveAlert"]; - [self presentViewController:currentAlert animated:YES completion:nil]; -} - - (void)onRoomAvatarTap:(UITapGestureRecognizer *)recognizer { SingleImagePickerPresenter *singleImagePickerPresenter = [[SingleImagePickerPresenter alloc] initWithSession:self.mainSession]; From 73a5d937130ea210263f01a5cbc9f1bb121ebef3 Mon Sep 17 00:00:00 2001 From: Philippe Loriaux Date: Mon, 16 Jan 2023 15:02:33 +0100 Subject: [PATCH 061/160] Add Towncrier file --- changelog.d/pr-7275.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-7275.change diff --git a/changelog.d/pr-7275.change b/changelog.d/pr-7275.change new file mode 100644 index 0000000000..6435f2f71d --- /dev/null +++ b/changelog.d/pr-7275.change @@ -0,0 +1 @@ +Remove "Leave" button on Room details screen From 648b4091a6e89e64f41ac6853ff82ecd9a649860 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Mon, 16 Jan 2023 12:31:51 +0100 Subject: [PATCH 062/160] Live voice broadcast should not appear in Info Center while playing --- Riot/Modules/Application/LegacyAppDelegate.m | 3 +++ .../VoiceMessageMediaServiceProvider.swift | 26 ++++++++++++++++--- .../VoiceMessageNowPlayingInfoDelegate.swift | 2 ++ .../VoiceBroadcastPlaybackCoordinator.swift | 9 ++++++- .../VoiceBroadcastPlaybackProvider.swift | 6 +++++ .../VoiceBroadcastPlaybackViewModel.swift | 20 +++++++++++--- 6 files changed, 58 insertions(+), 8 deletions(-) diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 15cdb8be1c..de9e397c3a 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -618,6 +618,9 @@ - (void)applicationDidEnterBackground:(UIApplication *)application // Pause Voice Broadcast recording if needed [VoiceBroadcastRecorderProvider.shared pauseRecording]; + + // Pause Voice Broadcast playing if needed + [VoiceBroadcastPlaybackProvider.shared pausePlayingInProgressVoiceBroadcast]; } - (void)applicationWillEnterForeground:(UIApplication *)application diff --git a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift index 24ff08d0d1..c6dc8b8b4f 100644 --- a/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift +++ b/Riot/Modules/Room/VoiceMessages/VoiceMessageMediaServiceProvider.swift @@ -138,7 +138,14 @@ import MediaPlayer func audioPlayerDidStartPlaying(_ audioPlayer: VoiceMessageAudioPlayer) { currentlyPlayingAudioPlayer = audioPlayer activeAudioPlayers.insert(audioPlayer) - setUpRemoteCommandCenter() + + let shouldSetupRemoteCommandCenter = nowPlayingInfoDelegates.object(forKey: audioPlayer)?.shouldSetupRemoteCommandCenter(audioPlayer: audioPlayer) ?? true + if shouldSetupRemoteCommandCenter { + setUpRemoteCommandCenter() + } else { + // clean up the remote command center + tearDownRemoteCommandCenter() + } pauseAllServicesExcept(audioPlayer) } @@ -150,7 +157,7 @@ import MediaPlayer // ask the delegate if we should disconnect from NowPlayingInfoCenter (if there's no delegate, we consider it safe to disconnect it) if nowPlayingInfoDelegate?.shouldDisconnectFromNowPlayingInfoCenter(audioPlayer: audioPlayer) ?? true { currentlyPlayingAudioPlayer = nil - tearDownRemoteCommandCenter(for: audioPlayer) + tearDownRemoteCommandCenter() } } activeAudioPlayers.remove(audioPlayer) @@ -164,7 +171,7 @@ import MediaPlayer // ask the delegate if we should disconnect from NowPlayingInfoCenter (if there's no delegate, we consider it safe to disconnect it) if nowPlayingInfoDelegate?.shouldDisconnectFromNowPlayingInfoCenter(audioPlayer: audioPlayer) ?? true { currentlyPlayingAudioPlayer = nil - tearDownRemoteCommandCenter(for: audioPlayer) + tearDownRemoteCommandCenter() } } activeAudioPlayers.remove(audioPlayer) @@ -264,13 +271,24 @@ import MediaPlayer } } - private func tearDownRemoteCommandCenter(for audioPlayer: VoiceMessageAudioPlayer) { + private func tearDownRemoteCommandCenter() { displayLink.isPaused = true UIApplication.shared.endReceivingRemoteControlEvents() let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() nowPlayingInfoCenter.nowPlayingInfo = nil + nowPlayingInfoCenter.playbackState = .stopped + + let commandCenter = MPRemoteCommandCenter.shared() + commandCenter.playCommand.isEnabled = false + commandCenter.playCommand.removeTarget(nil) + commandCenter.pauseCommand.isEnabled = false + commandCenter.pauseCommand.removeTarget(nil) + commandCenter.skipForwardCommand.isEnabled = false + commandCenter.skipForwardCommand.removeTarget(nil) + commandCenter.skipBackwardCommand.isEnabled = false + commandCenter.skipBackwardCommand.removeTarget(nil) } private func updateNowPlayingInfoCenter() { diff --git a/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoDelegate.swift b/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoDelegate.swift index 6955b4c0f0..959f8ca91b 100644 --- a/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoDelegate.swift +++ b/Riot/Modules/Room/VoiceMessages/VoiceMessageNowPlayingInfoDelegate.swift @@ -20,5 +20,7 @@ import Foundation func updateNowPlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) + func shouldSetupRemoteCommandCenter(audioPlayer player: VoiceMessageAudioPlayer) -> Bool + func shouldDisconnectFromNowPlayingInfoCenter(audioPlayer: VoiceMessageAudioPlayer) -> Bool } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift index 3f5e55c6e4..4369419bc5 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift @@ -80,8 +80,15 @@ final class VoiceBroadcastPlaybackCoordinator: Coordinator, Presentable { } func endVoiceBroadcast() {} - + func pausePlaying() { viewModel.context.send(viewAction: .pause) } + + func pausePlayingInProgressVoiceBroadcast() { + // Pause the playback if we are playing a live voice broadcast (or waiting for more chunks) + if [.playing, .buffering].contains(viewModel.context.viewState.playbackState), viewModel.context.viewState.broadcastState != .stopped { + viewModel.context.send(viewAction: .pause) + } + } } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackProvider.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackProvider.swift index 3f28ab081d..94c10eea48 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackProvider.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackProvider.swift @@ -78,6 +78,12 @@ import Foundation } } + @objc public func pausePlayingInProgressVoiceBroadcast() { + coordinatorsForEventIdentifiers.forEach { _, coordinator in + coordinator.pausePlayingInProgressVoiceBroadcast() + } + } + private func handleEvent(event: MXEvent, direction: MXTimelineDirection, customObject: Any?) { if direction == .backwards { // ignore backwards events diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift index 56e4357578..5269f67c2f 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift @@ -490,12 +490,22 @@ extension VoiceBroadcastPlaybackViewModel: VoiceMessageAudioPlayerDelegate { extension VoiceBroadcastPlaybackViewModel: VoiceMessageNowPlayingInfoDelegate { + func shouldSetupRemoteCommandCenter(audioPlayer player: VoiceMessageAudioPlayer) -> Bool { + guard BuildSettings.allowBackgroundAudioMessagePlayback, audioPlayer != nil, audioPlayer === player else { + return false + } + + // we should setup the remote command center only for ended voice broadcast because we won't get new chunk if the app is in background. + return state.broadcastState == .stopped + } + func shouldDisconnectFromNowPlayingInfoCenter(audioPlayer player: VoiceMessageAudioPlayer) -> Bool { guard BuildSettings.allowBackgroundAudioMessagePlayback, audioPlayer != nil, audioPlayer === player else { return true } - return state.broadcastState == .stopped + // we should disconnect from the now playing info center if the playback is stopped or if the broadcast is in progress + return state.playbackState == .stopped || state.broadcastState != .stopped } func updateNowPlayingInfoCenter(forPlayer player: VoiceMessageAudioPlayer) { @@ -503,12 +513,16 @@ extension VoiceBroadcastPlaybackViewModel: VoiceMessageNowPlayingInfoDelegate { return } + // Don't update the NowPlayingInfoCenter for live broadcasts + guard state.broadcastState == .stopped else { + MPNowPlayingInfoCenter.default().nowPlayingInfo = nil + return + } + let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default() nowPlayingInfoCenter.nowPlayingInfo = [ // Title MPMediaItemPropertyTitle: VectorL10n.voiceBroadcastPlaybackLockScreenPlaceholder, - // Buffering status (using the "artist" property to display it under the title) - MPMediaItemPropertyArtist: state.playbackState == .buffering ? VectorL10n.voiceBroadcastBuffering : "", // Duration MPMediaItemPropertyPlaybackDuration: (state.playingState.duration / 1000.0) as Any, // Elapsed time From f8a851b5dd0019f9a45917dac5530ba8b3f224a6 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Mon, 16 Jan 2023 16:00:18 +0100 Subject: [PATCH 063/160] Make sure we store the last block sequence sent (even if it's 0) --- .../VoiceBroadcastSDK/VoiceBroadcastAggregator.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift index 1741dc14cc..39264b42c9 100644 --- a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift +++ b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastAggregator.swift @@ -170,8 +170,8 @@ public class VoiceBroadcastAggregator { let state = VoiceBroadcastInfoState(rawValue: voiceBroadcastInfo.state) else { return } - // For .pause and .stopped, if there is a lastChunkSequence (ie its value is > 0), we store it - if [.stopped, .paused].contains(state), voiceBroadcastInfo.lastChunkSequence > 0 { + // For .pause and .stopped, update the last chunk sequence + if [.stopped, .paused].contains(state) { self.voiceBroadcastLastChunkSequence = voiceBroadcastInfo.lastChunkSequence } self.delegate?.voiceBroadcastAggregator(self, didReceiveState: state) From 5e86a2e71dea6fdfdfebc1283abc4b5d60c76aa8 Mon Sep 17 00:00:00 2001 From: Yoan Pintas Date: Mon, 16 Jan 2023 18:15:49 +0000 Subject: [PATCH 064/160] Unexpected live voice broadcast (#7269) --- Riot/Utils/EventFormatter.m | 112 ++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 18 deletions(-) diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 079a00f77a..21cd496dde 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -546,8 +546,8 @@ - (NSString*)senderAvatarUrlForEvent:(MXEvent*)event withRoomState:(MXRoomState* } #pragma mark - MXRoomSummaryUpdating -- (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withLastEvent:(MXEvent *)event eventState:(MXRoomState *)eventState roomState:(MXRoomState *)roomState { - +- (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withLastEvent:(MXEvent *)event eventState:(MXRoomState *)eventState roomState:(MXRoomState *)roomState +{ // Do not display voice broadcast chunk in last message. if (event.eventType == MXEventTypeRoomMessage && event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType]) { @@ -555,31 +555,94 @@ - (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary } // Update last message if we have a voice broadcast in the room. - if ([event.type isEqualToString:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType]) - { - return [self session:session updateRoomSummary:summary withVoiceBroadcastInfoStateEvent:event roomState:roomState]; - } - else + MXEvent *lastVoiceBroadcastInfoEvent = [self lastVoiceBroadcastInfoEventWithEvent:event roomState:roomState]; + if (lastVoiceBroadcastInfoEvent != nil) { - MXEvent *stateEvent = [roomState stateEventsWithType:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType].lastObject; - if (stateEvent && ![VoiceBroadcastInfo isStoppedFor:[VoiceBroadcastInfo modelFromJSON: stateEvent.content].state]) + MXEvent *voiceBroadcastInfoStartedEvent = [self voiceBroadcastInfoStartedEventWithEvent:lastVoiceBroadcastInfoEvent + roomId:summary.roomId + session:session]; + if (voiceBroadcastInfoStartedEvent != nil + && !(voiceBroadcastInfoStartedEvent.isRedactedEvent || [voiceBroadcastInfoStartedEvent.eventId isEqualToString:event.redacts])) { - return [self session:session updateRoomSummary:summary withVoiceBroadcastInfoStateEvent:stateEvent roomState:roomState]; + return [self session:session + updateRoomSummary:summary +withVoiceBroadcastInfoStateEvent:lastVoiceBroadcastInfoEvent + voiceBroadcastInfoStartedEvent:voiceBroadcastInfoStartedEvent roomState:roomState]; } } BOOL updated = [super session:session updateRoomSummary:summary withLastEvent:event eventState:eventState roomState:roomState]; - if (updated) { + if (updated) + { // Force the default text color for the last message (cancel highlighted message color) NSMutableAttributedString *lastEventDescription = [[NSMutableAttributedString alloc] initWithAttributedString:summary.lastMessage.attributedText]; - [lastEventDescription addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.textSecondaryColor range:NSMakeRange(0, lastEventDescription.length)]; + [lastEventDescription addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.textSecondaryColor + range:NSMakeRange(0, lastEventDescription.length)]; summary.lastMessage.attributedText = lastEventDescription; } return updated; } + +- (MXEvent *)lastVoiceBroadcastInfoEventWithEvent:(MXEvent *)event roomState:(MXRoomState *)roomState +{ + MXEvent *voiceBroadcastInfoEvent = nil; + VoiceBroadcastInfo *info = nil; + if ([event.type isEqualToString:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType]) + { + info = [VoiceBroadcastInfo modelFromJSON: event.content]; + + if (info != nil) + { + voiceBroadcastInfoEvent = event; + } + } + else + { + MXEvent *stateEvent = [roomState stateEventsWithType:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType].lastObject; + if (stateEvent != nil) + { + info = [VoiceBroadcastInfo modelFromJSON: stateEvent.content]; + if (info != nil && ![VoiceBroadcastInfo isStoppedFor:info.state]) + { + voiceBroadcastInfoEvent = stateEvent; + } + } + } + + return voiceBroadcastInfoEvent; +} + +- (MXEvent *)voiceBroadcastInfoStartedEventWithEvent:(MXEvent *)voiceBroadcastInfoEvent roomId:(NSString *)roomId session:(MXSession *)session +{ + VoiceBroadcastInfo *voiceBroadcastInfo = [VoiceBroadcastInfo modelFromJSON: voiceBroadcastInfoEvent.content]; + if ([VoiceBroadcastInfo isStartedFor:voiceBroadcastInfo.state]) + { + return voiceBroadcastInfoEvent; + } + else + { + dispatch_group_t group = dispatch_group_create(); + dispatch_group_enter(group); + + __block MXEvent *voiceBroadcastInfoStartedEvent; + + [session eventWithEventId:voiceBroadcastInfo.voiceBroadcastId inRoom:roomId success:^(MXEvent *resultEvent) { + voiceBroadcastInfoStartedEvent = resultEvent; + dispatch_group_leave(group); + } failure:^(NSError *error) { + MXLogErrorDetails(@"[EventFormatter] Fetch eventWithEventId with error = %@", error.description); + dispatch_group_leave(group); + }]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + return voiceBroadcastInfoStartedEvent; + } +} + - (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withStateEvents:(NSArray *)stateEvents roomState:(MXRoomState *)roomState { BOOL updated = [super session:session updateRoomSummary:summary withStateEvents:stateEvents roomState:roomState]; @@ -603,18 +666,29 @@ - (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary return updated; } -- (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withVoiceBroadcastInfoStateEvent:(MXEvent *)stateEvent roomState:(MXRoomState *)roomState +- (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withVoiceBroadcastInfoStateEvent:(MXEvent *)stateEvent voiceBroadcastInfoStartedEvent:(MXEvent *)voiceBroadcastInfoStartedEvent roomState:(MXRoomState *)roomState { - [summary updateLastMessage:[[MXRoomLastMessage alloc] initWithEvent:stateEvent]]; - if (summary.lastMessage.others == nil) + BOOL isStoppedVoiceBroadcast = [VoiceBroadcastInfo isStoppedFor:[VoiceBroadcastInfo modelFromJSON: stateEvent.content].state]; + + if ([summary.lastMessage.eventId isEqualToString:voiceBroadcastInfoStartedEvent.eventId]) { - summary.lastMessage.others = [NSMutableDictionary dictionary]; + if (!isStoppedVoiceBroadcast) + { + return NO; + } + } + else + { + [summary updateLastMessage:[[MXRoomLastMessage alloc] initWithEvent:voiceBroadcastInfoStartedEvent]]; + if (summary.lastMessage.others == nil) + { + summary.lastMessage.others = [NSMutableDictionary dictionary]; + } } - summary.lastMessage.others[@"lastEventDate"] = [self dateStringFromEvent:stateEvent withTime:YES]; NSAttributedString *attachmentString = nil; UIColor *textColor; - if ([VoiceBroadcastInfo isStoppedFor:[VoiceBroadcastInfo modelFromJSON: stateEvent.content].state]) + if (isStoppedVoiceBroadcast) { textColor = ThemeService.shared.theme.textSecondaryColor; NSString *senderDisplayName; @@ -627,6 +701,7 @@ - (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary senderDisplayName = [self senderDisplayNameForEvent:stateEvent withRoomState:roomState]; summary.lastMessage.text = [VectorL10n noticeVoiceBroadcastEnded:senderDisplayName]; } + summary.lastMessage.others[@"lastEventDate"] = [self dateStringFromEvent:stateEvent withTime:YES]; } else { @@ -638,6 +713,7 @@ - (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary attachmentString = [NSAttributedString attributedStringWithAttachment:attachment]; summary.lastMessage.text = VectorL10n.noticeVoiceBroadcastLive; + summary.lastMessage.others[@"lastEventDate"] = [self dateStringFromEvent:voiceBroadcastInfoStartedEvent withTime:YES]; } // Compute the attribute text message From f685d6fd4edb17d3813096e9e47fca7979b0cffd Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Tue, 17 Jan 2023 11:00:08 +0100 Subject: [PATCH 065/160] Fix voicebroadcast playback slider on seek --- .../VoiceBroadcastPlaybackViewModel.swift | 41 +++++++++++++------ changelog.d/7252.bugfix | 1 + 2 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 changelog.d/7252.bugfix diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift index fcd58b1d9f..ffe713e735 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/MatrixSDK/VoiceBroadcastPlaybackViewModel.swift @@ -60,6 +60,20 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic return state.bindings.progress + 1000 >= state.playingState.duration - Float(chunkDuration) } + private var playingChunk: VoiceBroadcastChunk? { + guard let currentAudioPlayerUrl = audioPlayer?.currentUrl, + let playingEventId = voiceBroadcastAttachmentCacheManagerLoadResults.first(where: { result in + result.url == currentAudioPlayerUrl + })?.eventIdentifier else { + return nil + } + + let playingChunk = voiceBroadcastAggregator.voiceBroadcast.chunks.first(where: { chunk in + chunk.attachment.eventId == playingEventId + }) + return playingChunk + } + private var isLivePlayback: Bool { return (!isPlaybackInitialized || isPlayingLastChunk) && (state.broadcastState == .started || state.broadcastState == .resumed) } @@ -392,20 +406,19 @@ class VoiceBroadcastPlaybackViewModel: VoiceBroadcastPlaybackViewModelType, Voic } @objc private func handleDisplayLinkTick() { - guard let playingEventId = voiceBroadcastAttachmentCacheManagerLoadResults.first(where: { result in - result.url == audioPlayer?.currentUrl - })?.eventIdentifier, - let playingSequence = voiceBroadcastAggregator.voiceBroadcast.chunks.first(where: { chunk in - chunk.attachment.eventId == playingEventId - })?.sequence else { + guard let playingSequence = self.playingChunk?.sequence else { return } - - let progress = Double(voiceBroadcastAggregator.voiceBroadcast.chunks.filter { chunk in - chunk.sequence < playingSequence - }.reduce(0) { $0 + $1.duration}) + (audioPlayer?.currentTime.rounded() ?? 0) * 1000 - - state.bindings.progress = Float(progress) + + // Get the audioPlayer current time, which is the elapsed time in the currently playing media item. + // Note: if the audioPlayer is not ready (eg. after a seek), its currentTime will be 0 and we shouldn't update the progress to avoid visual glitches. + let currentTime = audioPlayer?.currentTime ?? .zero + if currentTime > 0 { + let progress = Double(voiceBroadcastAggregator.voiceBroadcast.chunks.filter { chunk in + chunk.sequence < playingSequence + }.reduce(0) { $0 + $1.duration}) + currentTime * 1000 + state.bindings.progress = Float(progress) + } updateUI() } @@ -467,7 +480,6 @@ extension VoiceBroadcastPlaybackViewModel: VoiceBroadcastAggregatorDelegate { } func voiceBroadcastAggregatorDidUpdateData(_ aggregator: VoiceBroadcastAggregator) { - updateDuration() if state.playbackState != .stopped, !isActuallyPaused { @@ -486,11 +498,13 @@ extension VoiceBroadcastPlaybackViewModel: VoiceMessageAudioPlayerDelegate { state.playbackState = .playing state.playingState.isLive = isLivePlayback isPlaybackInitialized = true + displayLink.isPaused = false } func audioPlayerDidPausePlaying(_ audioPlayer: VoiceMessageAudioPlayer) { state.playbackState = .paused state.playingState.isLive = false + displayLink.isPaused = true } func audioPlayerDidStopPlaying(_ audioPlayer: VoiceMessageAudioPlayer) { @@ -500,6 +514,7 @@ extension VoiceBroadcastPlaybackViewModel: VoiceMessageAudioPlayerDelegate { audioPlayer.deregisterDelegate(self) self.mediaServiceProvider.deregisterNowPlayingInfoDelegate(forPlayer: audioPlayer) self.audioPlayer = nil + displayLink.isPaused = true } func audioPlayer(_ audioPlayer: VoiceMessageAudioPlayer, didFailWithError error: Error) { diff --git a/changelog.d/7252.bugfix b/changelog.d/7252.bugfix new file mode 100644 index 0000000000..0e823509f0 --- /dev/null +++ b/changelog.d/7252.bugfix @@ -0,0 +1 @@ +Voice Broadcast: Fixed an issue where the voice broadcast audio player progress bar behaved unexpectedly. From 02477cc2408276aaa547510ef4289e691845699e Mon Sep 17 00:00:00 2001 From: Yoan Pintas Date: Tue, 17 Jan 2023 14:49:36 +0000 Subject: [PATCH 066/160] Handle a connection issue when we try to start a new voice broadcast (#7276) --- Riot/Assets/en.lproj/Vector.strings | 4 +++- Riot/Generated/Strings.swift | 8 ++++++++ Riot/Modules/Room/RoomViewController.m | 14 ++++++++++---- .../VoiceBroadcastSDK/VoiceBroadcastService.swift | 5 ++++- changelog.d/7234.change | 1 + 5 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 changelog.d/7234.change diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index c14597906a..576df0110b 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2208,6 +2208,7 @@ Tap the + to start adding people."; "voice_broadcast_blocked_by_someone_else_message" = "Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one."; "voice_broadcast_already_in_progress_message" = "You are already recording a voice broadcast. Please end your current voice broadcast to start a new one."; "voice_broadcast_playback_loading_error" = "Unable to play this voice broadcast."; +"voice_broadcast_playback_lock_screen_placeholder" = "Voice broadcast"; "voice_broadcast_live" = "Live"; "voice_broadcast_tile" = "Voice broadcast"; "voice_broadcast_time_left" = "%@ left"; @@ -2217,7 +2218,8 @@ Tap the + to start adding people."; "voice_broadcast_stop_alert_agree_button" = "Yes, stop"; "voice_broadcast_voip_cannot_start_title" = "Can’t start a call"; "voice_broadcast_voip_cannot_start_description" = "You can’t start a call as you are currently recording a live broadcast. Please end your live broadcast in order to start a call."; -"voice_broadcast_playback_lock_screen_placeholder" = "Voice broadcast"; +"voice_broadcast_connection_error_title" = "Connection error"; +"voice_broadcast_connection_error_message" = "Unfortunately we’re unable to start a recording right now. Please try again later."; // MARK: - Version check diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index c9bb71b43a..6d5ef8e9aa 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -9207,6 +9207,14 @@ public class VectorL10n: NSObject { public static var voiceBroadcastBuffering: String { return VectorL10n.tr("Vector", "voice_broadcast_buffering") } + /// Unfortunately we’re unable to start a recording right now. Please try again later. + public static var voiceBroadcastConnectionErrorMessage: String { + return VectorL10n.tr("Vector", "voice_broadcast_connection_error_message") + } + /// Connection error + public static var voiceBroadcastConnectionErrorTitle: String { + return VectorL10n.tr("Vector", "voice_broadcast_connection_error_title") + } /// Live public static var voiceBroadcastLive: String { return VectorL10n.tr("Vector", "voice_broadcast_live") diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 87b7e858f2..a1a0b6b6c3 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -2454,13 +2454,19 @@ - (void)roomInputToolbarViewDidTapVoiceBroadcast // Prevents listening a VB when recording a new one [VoiceBroadcastPlaybackProvider.shared pausePlaying]; + // Check connectivity + if ([AppDelegate theDelegate].isOffline) + { + [self showAlertWithTitle:[VectorL10n voiceBroadcastConnectionErrorTitle] message:[VectorL10n voiceBroadcastConnectionErrorMessage]]; + return; + } + // Request the voice broadcast service to start recording - No service is returned if someone else is already broadcasting in the room [session getOrCreateVoiceBroadcastServiceFor:self.roomDataSource.room completion:^(VoiceBroadcastService *voiceBroadcastService) { if (voiceBroadcastService) { - [voiceBroadcastService startVoiceBroadcastWithSuccess:^(NSString * _Nullable success) { - - } failure:^(NSError * _Nonnull error) { - + [voiceBroadcastService startVoiceBroadcastWithSuccess:^(NSString * _Nullable success) { } failure:^(NSError * _Nonnull error) { + [self showAlertWithTitle:[VectorL10n voiceBroadcastConnectionErrorTitle] message:[VectorL10n voiceBroadcastConnectionErrorMessage]]; + [session tearDownVoiceBroadcastService]; }]; } else diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift index 8c707eab2c..c41d5d37d9 100644 --- a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift +++ b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift @@ -186,7 +186,7 @@ public class VoiceBroadcastService: NSObject { return } - self.room.sendStateEvent(.custom(VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType), + let httpOperation = self.room.sendStateEvent(.custom(VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType), content: stateEventContent, stateKey: stateKey) { [weak self] response in guard let self = self else { return } @@ -199,6 +199,9 @@ public class VoiceBroadcastService: NSObject { } taskCompleted() } + + // No retry to send the request + httpOperation.maxNumberOfTries = 0 } } } diff --git a/changelog.d/7234.change b/changelog.d/7234.change new file mode 100644 index 0000000000..52af7685d9 --- /dev/null +++ b/changelog.d/7234.change @@ -0,0 +1 @@ +Handle a connection issue when we try to start a new voice broadcast. From 180fcb7ccad2289242edbb9ff1eb4438c0c13f9a Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Tue, 17 Jan 2023 16:44:56 +0100 Subject: [PATCH 067/160] Improve PollListItem to support ended polls --- .../MockPollHistoryScreenState.swift | 4 +- .../Room/PollHistory/PollHistoryModels.swift | 3 +- .../PollHistory/PollHistoryViewModel.swift | 19 ++++- .../Service/Mock/MockPollHistoryService.swift | 27 +++++-- .../Room/PollHistory/View/PollHistory.swift | 3 + .../Room/PollHistory/View/PollListItem.swift | 70 ++++++++++++++++++- 6 files changed, 113 insertions(+), 13 deletions(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift index c00ccf528b..65d393957b 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift @@ -45,10 +45,10 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable { pollHistoryMode = .past case .activeEmpty: pollHistoryMode = .active - pollService.pollListData = [] + pollService.activePollsData = [] case .pastEmpty: pollHistoryMode = .past - pollService.pollListData = [] + pollService.pastPollsData = [] } let viewModel = PollHistoryViewModel(mode: pollHistoryMode, pollService: pollService) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift index c8960add0b..93ef308193 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift @@ -33,7 +33,7 @@ struct PollHistoryViewBindings { struct PollHistoryViewState: BindableState { init(mode: PollHistoryMode) { - self.bindings = .init(mode: mode) + bindings = .init(mode: mode) } var bindings: PollHistoryViewBindings @@ -42,4 +42,5 @@ struct PollHistoryViewState: BindableState { enum PollHistoryViewAction { case viewAppeared + case segmentDidChange } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift index 0addb8ef99..4199251da3 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift @@ -20,6 +20,7 @@ typealias PollHistoryViewModelType = StateStoreViewModel? { didSet { oldValue?.cancel() @@ -39,6 +40,8 @@ final class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModel switch viewAction { case .viewAppeared: fetchingTask = fetchPolls() + case .segmentDidChange: + updatePolls() } } } @@ -53,8 +56,22 @@ private extension PollHistoryViewModel { } await MainActor.run { - state.polls = polls + self.polls = polls + updatePolls() } } } + + func updatePolls() { + let renderedPolls: [PollListData] + + switch context.mode { + case .active: + renderedPolls = polls.filter { $0.winningOption == nil } + case .past: + renderedPolls = polls.filter { $0.winningOption != nil } + } + + state.polls = renderedPolls + } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift index 67d3121816..62796963de 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift @@ -15,15 +15,30 @@ // final class MockPollHistoryService: PollHistoryServiceProtocol { - var pollListData: [PollListData] = (1..<10) + var activePollsData: [PollListData] = (1..<10) .map { index in - PollListData(startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), question: "Do you like the poll number \(index)?") - } - .sorted { poll1, poll2 in - poll1.startDate > poll2.startDate + PollListData( + startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), + question: "Do you like the active poll number \(index)?", + numberOfVotes: 30, + winningOption: nil + ) } + var pastPollsData: [PollListData] = (1..<10) + .map { index in + PollListData( + startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), + question: "Do you like the past poll number \(index)?", + numberOfVotes: 30, + winningOption: .init(id: "id", text: "Yes, of course!", count: 20, winner: true, selected: true) + ) + } + func fetchHistory() async throws -> [PollListData] { - pollListData + (activePollsData + pastPollsData) + .sorted { poll1, poll2 in + poll1.startDate > poll2.startDate + } } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index b1208f547c..cd9001a56f 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -45,6 +45,9 @@ struct PollHistory: View { .onAppear { viewModel.send(viewAction: .viewAppeared) } + .onChange(of: viewModel.mode) { newValue in + viewModel.send(viewAction: .segmentDidChange) + } } private var pollListView: some View { diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index 373ea0202f..98c5f06bd8 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -19,6 +19,8 @@ import SwiftUI struct PollListData { let startDate: Date let question: String + let numberOfVotes: UInt + let winningOption: TimelinePollAnswerOption? } struct PollListItem: View { @@ -36,18 +38,62 @@ struct PollListItem: View { Text(pollData.formattedDate) .foregroundColor(theme.colors.tertiaryContent) .font(theme.fonts.caption1) - + HStack(alignment: .firstTextBaseline, spacing: 8) { Image(uiImage: Asset.Images.pollHistory.image) .resizable() .frame(width: imageSize, height: imageSize) - + Text(pollData.question) .foregroundColor(theme.colors.primaryContent) .font(theme.fonts.body) .lineLimit(2) .accessibilityLabel("PollListItem.title") } + + if pollData.winningOption != nil { + optionView(winningOption: pollData.winningOption!) + } + } + } + + private var clipShape: some Shape { + RoundedRectangle(cornerRadius: 4.0) + } + + private func optionView(winningOption: TimelinePollAnswerOption) -> some View { + VStack(alignment: .leading, spacing: 12.0) { + HStack(alignment: .top, spacing: 8.0) { + Text(pollData.winningOption!.text) + .font(theme.fonts.body) + .foregroundColor(theme.colors.primaryContent) + + Spacer() + + votesText(winningOption: winningOption) + } + + ProgressView(value: Double(winningOption.count), + total: Double(pollData.numberOfVotes)) + .progressViewStyle(LinearProgressViewStyle()) + .scaleEffect(x: 1.0, y: 1.2, anchor: .center) + } + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 8.0) + .padding(.top, 12.0) + .padding(.bottom, 12.0) + .clipShape(clipShape) + .overlay(clipShape.stroke(theme.colors.accent, lineWidth: 1.0)) + .accentColor(theme.colors.accent) + } + + private func votesText(winningOption: TimelinePollAnswerOption) -> some View { + Label { + Text(winningOption.count == 1 ? VectorL10n.pollTimelineOneVote : VectorL10n.pollTimelineVotesCount(Int(winningOption.count))) + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.accent) + } icon: { + Image(uiImage: Asset.Images.pollWinnerIcon.image) } } } @@ -72,6 +118,24 @@ private extension DateFormatter { struct PollListItem_Previews: PreviewProvider { static var previews: some View { - PollListItem(pollData: .init(startDate: .init(), question: "Did you like this poll?")) + Group { + let pollData1 = PollListData( + startDate: .init(), + question: "Do you like polls?", + numberOfVotes: 30, + winningOption: .init(id: "id", text: "Yes, of course!", count: 18, winner: true, selected: true) + ) + + PollListItem(pollData: pollData1) + + let pollData2 = PollListData( + startDate: .init(), + question: "Do you like polls?", + numberOfVotes: 30, + winningOption: nil) + + PollListItem(pollData: pollData2) + } + .padding() } } From 1d04bd8ac76d248b17c723fb53dc2314e63ae075 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Tue, 17 Jan 2023 16:54:18 +0100 Subject: [PATCH 068/160] Add results view --- .../Room/PollHistory/View/PollListItem.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index 98c5f06bd8..c2447fa1e6 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -52,7 +52,10 @@ struct PollListItem: View { } if pollData.winningOption != nil { - optionView(winningOption: pollData.winningOption!) + VStack(alignment: .leading, spacing: 12) { + optionView(winningOption: pollData.winningOption!) + resultView + } } } } @@ -96,6 +99,14 @@ struct PollListItem: View { Image(uiImage: Asset.Images.pollWinnerIcon.image) } } + + private var resultView: some View { + let text = pollData.numberOfVotes == 1 ? VectorL10n.pollTimelineTotalFinalResultsOneVote : VectorL10n.pollTimelineTotalFinalResults(Int(pollData.numberOfVotes)) + + return Text(text) + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.tertiaryContent) + } } private extension PollListData { From bc9c0bba8f26d42e08d1d9dc3e64e4905ee6c4a2 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Tue, 17 Jan 2023 17:35:44 +0100 Subject: [PATCH 069/160] Add ui tests --- .../Test/UI/PollHistoryUITests.swift | 26 +++++++++++++++++-- .../Room/PollHistory/View/PollHistory.swift | 2 +- .../Room/PollHistory/View/PollListItem.swift | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift index 3fcc05c7b3..5867b88e8f 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Test/UI/PollHistoryUITests.swift @@ -18,29 +18,51 @@ import RiotSwiftUI import XCTest class PollHistoryUITests: MockScreenTestCase { - func testPollHistoryHasContent() { + func testActivePollHistoryHasContent() { app.goToScreenWithIdentifier(MockPollHistoryScreenState.active.title) let title = app.navigationBars.firstMatch.identifier let emptyText = app.staticTexts["PollHistory.emptyText"] let items = app.staticTexts["PollListItem.title"] let selectedSegment = app.buttons[VectorL10n.pollHistoryActiveSegmentTitle] + let winningOption = app.staticTexts["PollListData.winningOption"] + XCTAssertEqual(title, VectorL10n.pollHistoryTitle) XCTAssertTrue(items.exists) XCTAssertFalse(emptyText.exists) XCTAssertTrue(selectedSegment.exists) XCTAssertEqual(selectedSegment.value as? String, VectorL10n.accessibilitySelected) + XCTAssertFalse(winningOption.exists) } - func testPollHistoryShowsEmptyScreen() { + func testPastPollHistoryHasContent() { + app.goToScreenWithIdentifier(MockPollHistoryScreenState.past.title) + let title = app.navigationBars.firstMatch.identifier + let emptyText = app.staticTexts["PollHistory.emptyText"] + let items = app.staticTexts["PollListItem.title"] + let selectedSegment = app.buttons[VectorL10n.pollHistoryPastSegmentTitle] + let winningOption = app.staticTexts["PollListData.winningOption"] + + XCTAssertEqual(title, VectorL10n.pollHistoryTitle) + XCTAssertTrue(items.exists) + XCTAssertFalse(emptyText.exists) + XCTAssertTrue(selectedSegment.exists) + XCTAssertEqual(selectedSegment.value as? String, VectorL10n.accessibilitySelected) + XCTAssertTrue(winningOption.exists) + } + + func testPastPollHistoryIsEmpty() { app.goToScreenWithIdentifier(MockPollHistoryScreenState.pastEmpty.title) let title = app.navigationBars.firstMatch.identifier let emptyText = app.staticTexts["PollHistory.emptyText"] let items = app.staticTexts["PollListItem.title"] let selectedSegment = app.buttons[VectorL10n.pollHistoryPastSegmentTitle] + let winningOption = app.staticTexts["PollListData.winningOption"] + XCTAssertEqual(title, VectorL10n.pollHistoryTitle) XCTAssertFalse(items.exists) XCTAssertTrue(emptyText.exists) XCTAssertTrue(selectedSegment.exists) XCTAssertEqual(selectedSegment.value as? String, VectorL10n.accessibilitySelected) + XCTAssertFalse(winningOption.exists) } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index cd9001a56f..7cf9bb45aa 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -45,7 +45,7 @@ struct PollHistory: View { .onAppear { viewModel.send(viewAction: .viewAppeared) } - .onChange(of: viewModel.mode) { newValue in + .onChange(of: viewModel.mode) { _ in viewModel.send(viewAction: .segmentDidChange) } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index c2447fa1e6..b810f098fc 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -70,6 +70,7 @@ struct PollListItem: View { Text(pollData.winningOption!.text) .font(theme.fonts.body) .foregroundColor(theme.colors.primaryContent) + .accessibilityLabel("PollListData.winningOption") Spacer() From 1f8abe1041f41d9fabd768cedb93310548ccf316 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Tue, 17 Jan 2023 17:42:14 +0100 Subject: [PATCH 070/160] Add changelog.d file --- changelog.d/pr-7278.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-7278.change diff --git a/changelog.d/pr-7278.change b/changelog.d/pr-7278.change new file mode 100644 index 0000000000..f7254ebb92 --- /dev/null +++ b/changelog.d/pr-7278.change @@ -0,0 +1 @@ +Polls: poll history UI for past polls. From 7b5cfd173da774fdefdea1cfb4732bf74fabc77f Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 17 Jan 2023 18:10:35 +0100 Subject: [PATCH 071/160] save button improvement and tests updated --- .../xcshareddata/swiftpm/Package.resolved | 3 ++- .../Model/ComposerLinkActionModel.swift | 27 +++++++++++++------ .../Test/UI/ComposerLinkActionUITests.swift | 12 ++++----- .../ComposerLinkActionViewModelTests.swift | 27 +++++++------------ project.yml | 2 +- 5 files changed, 38 insertions(+), 33 deletions(-) diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index 102f87715d..34484b0a74 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift", "state" : { - "revision" : "534ee5bae5e8de69ed398937b5edb7b5f21551d2" + "revision" : "6927cb878376136c4a03d919b689af8dfbdad080", + "version" : "0.19.0" } }, { diff --git a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift index b47c5bcd52..fdf92cab5d 100644 --- a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift +++ b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift @@ -59,20 +59,31 @@ extension ComposerLinkActionViewState { } var isSaveButtonDisabled: Bool { - guard isValidLink else { return true } + guard !bindings.linkUrl.isEmpty else { return true } switch linkAction { case .createWithText: return bindings.text.isEmpty - default: return false + case .create: return false + case .edit: return !bindings.hasEditedUrl } } - - private var isValidLink: Bool { - guard let url = URL(string: bindings.linkUrl) else { return false } - return UIApplication.shared.canOpenURL(url) - } } struct ComposerLinkActionBindings { var text: String - var linkUrl: String + + private let initialLinkUrl: String + fileprivate var hasEditedUrl = false + var linkUrl: String { + didSet { + if !hasEditedUrl && linkUrl != initialLinkUrl { + hasEditedUrl = true + } + } + } + + init(text: String, linkUrl: String) { + self.text = text + self.linkUrl = linkUrl + self.initialLinkUrl = linkUrl + } } diff --git a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/UI/ComposerLinkActionUITests.swift b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/UI/ComposerLinkActionUITests.swift index f30dacf305..c18405951b 100644 --- a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/UI/ComposerLinkActionUITests.swift +++ b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/UI/ComposerLinkActionUITests.swift @@ -29,9 +29,7 @@ final class ComposerLinkActionUITests: MockScreenTestCase { let linkTextField = app.textFields["linkTextField"] XCTAssertTrue(linkTextField.exists) linkTextField.tap() - linkTextField.typeText("invalid url") - XCTAssertFalse(saveButton.isEnabled) - linkTextField.clearAndTypeText("https://element.io") + linkTextField.clearAndTypeText("element.io") XCTAssertTrue(saveButton.isEnabled) } @@ -47,7 +45,7 @@ final class ComposerLinkActionUITests: MockScreenTestCase { let linkTextField = app.textFields["linkTextField"] XCTAssertTrue(linkTextField.exists) linkTextField.tap() - linkTextField.typeText("https://element.io") + linkTextField.typeText("element.io") XCTAssertFalse(saveButton.isEnabled) textTextField.tap() textTextField.typeText("test") @@ -60,13 +58,15 @@ final class ComposerLinkActionUITests: MockScreenTestCase { XCTAssertTrue(app.buttons[VectorL10n.cancel].exists) let saveButton = app.buttons[VectorL10n.save] XCTAssertTrue(saveButton.exists) - XCTAssertTrue(saveButton.isEnabled) + XCTAssertFalse(saveButton.isEnabled) XCTAssertFalse(app.textFields["textTextField"].exists) let linkTextField = app.textFields["linkTextField"] XCTAssertTrue(linkTextField.exists) let value = linkTextField.value as? String XCTAssertEqual(value, "https://element.io") - linkTextField.clearAndTypeText("invalid url") + linkTextField.clearAndTypeText("") XCTAssertFalse(saveButton.isEnabled) + linkTextField.clearAndTypeText("matrix.org") + XCTAssertTrue(saveButton.isEnabled) } } diff --git a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/Unit/ComposerLinkActionViewModelTests.swift b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/Unit/ComposerLinkActionViewModelTests.swift index 40ad273584..2407eccc4e 100644 --- a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/Unit/ComposerLinkActionViewModelTests.swift +++ b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Test/Unit/ComposerLinkActionViewModelTests.swift @@ -53,29 +53,20 @@ final class ComposerLinkActionViewModelTests: XCTestCase { } func testEditDefaultState() { - let link = "https://element.io" + let link = "element.io" setUp(with: .edit(link: link)) XCTAssertEqual(context.viewState.bindings.text, "") XCTAssertEqual(context.viewState.bindings.linkUrl, link) - XCTAssertFalse(context.viewState.isSaveButtonDisabled) + XCTAssertTrue(context.viewState.isSaveButtonDisabled) XCTAssertTrue(context.viewState.shouldDisplayRemoveButton) XCTAssertFalse(context.viewState.shouldDisplayTextField) XCTAssertEqual(context.viewState.title, VectorL10n.wysiwygComposerLinkActionEditTitle) } - func testUrlValidityCheck() { - setUp(with: .create) - XCTAssertTrue(context.viewState.isSaveButtonDisabled) - context.linkUrl = "invalid url" - XCTAssertTrue(context.viewState.isSaveButtonDisabled) - context.linkUrl = "https://element.io" - XCTAssertFalse(context.viewState.isSaveButtonDisabled) - } - func testTextNotEmptyCheck() { setUp(with: .createWithText) XCTAssertTrue(context.viewState.isSaveButtonDisabled) - context.linkUrl = "https://element.io" + context.linkUrl = "element.io" XCTAssertTrue(context.viewState.isSaveButtonDisabled) context.text = "text" XCTAssertFalse(context.viewState.isSaveButtonDisabled) @@ -92,7 +83,7 @@ final class ComposerLinkActionViewModelTests: XCTestCase { } func testRemoveAction() { - setUp(with: .edit(link: "https://element.io")) + setUp(with: .edit(link: "element.io")) var result: ComposerLinkActionViewModelResult! viewModel.callback = { value in result = value @@ -107,7 +98,7 @@ final class ComposerLinkActionViewModelTests: XCTestCase { viewModel.callback = { value in result = value } - let link = "https://element.io" + let link = "element.io" context.linkUrl = link context.send(viewAction: .save) XCTAssertEqual(result, .performOperation(.setLink(urlString: link))) @@ -119,7 +110,7 @@ final class ComposerLinkActionViewModelTests: XCTestCase { viewModel.callback = { value in result = value } - let link = "https://element.io" + let link = "element.io" context.linkUrl = link let text = "test" context.text = text @@ -128,13 +119,15 @@ final class ComposerLinkActionViewModelTests: XCTestCase { } func testSaveActionForEdit() { - setUp(with: .edit(link: "https://element.io")) + setUp(with: .edit(link: "element.io")) var result: ComposerLinkActionViewModelResult! viewModel.callback = { value in result = value } - let link = "https://matrix.org" + XCTAssertTrue(context.viewState.isSaveButtonDisabled) + let link = "matrix.org" context.linkUrl = link + XCTAssertFalse(context.viewState.isSaveButtonDisabled) context.send(viewAction: .save) XCTAssertEqual(result, .performOperation(.setLink(urlString: link))) } diff --git a/project.yml b/project.yml index f2c4dbc230..fe9af33a86 100644 --- a/project.yml +++ b/project.yml @@ -53,7 +53,7 @@ packages: branch: main WysiwygComposer: url: https://github.com/matrix-org/matrix-wysiwyg-composer-swift - revision: 534ee5bae5e8de69ed398937b5edb7b5f21551d2 + version: 0.19.0 DeviceKit: url: https://github.com/devicekit/DeviceKit majorVersion: 4.7.0 From 39d35fd4fcbd32730dedd324c09d0670e5620e27 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 17 Jan 2023 18:32:36 +0100 Subject: [PATCH 072/160] changelog --- changelog.d/7279.change | 1 + changelog.d/7280.change | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog.d/7279.change create mode 100644 changelog.d/7280.change diff --git a/changelog.d/7279.change b/changelog.d/7279.change new file mode 100644 index 0000000000..c605f89208 --- /dev/null +++ b/changelog.d/7279.change @@ -0,0 +1 @@ +Rich Text Editor: https:// or mailto: scheme is automatically added when creating a link if no scheme is specified. diff --git a/changelog.d/7280.change b/changelog.d/7280.change new file mode 100644 index 0000000000..d387d563da --- /dev/null +++ b/changelog.d/7280.change @@ -0,0 +1 @@ +Rich Text Editor: Adding a link over a blank selection, prompts the user to create a new link with new text to replace such selection. From 01baa0718e9424ebc084055ad3b516a5075e3d33 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 10:12:03 +0100 Subject: [PATCH 073/160] Fix accessibility id --- RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index b810f098fc..335d62c397 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -70,7 +70,7 @@ struct PollListItem: View { Text(pollData.winningOption!.text) .font(theme.fonts.body) .foregroundColor(theme.colors.primaryContent) - .accessibilityLabel("PollListData.winningOption") + .accessibilityIdentifier("PollListData.winningOption") Spacer() From 8ad5489a5e386e80c29f64de0225c788ad8be554 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 11:22:40 +0100 Subject: [PATCH 074/160] Add new localisation for ended poll replies --- Riot/Assets/en.lproj/Vector.strings | 2 ++ Riot/Generated/Strings.swift | 4 ++++ .../MXKSendReplyEventStringLocalizer.swift | 20 +++++++++++-------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 95531c6da6..e2d45c94ed 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2368,6 +2368,8 @@ Tap the + to start adding people."; "poll_timeline_ended_text" = "Ended the poll"; +"poll_timeline_reply_ended_poll" = "Ended poll"; + // MARK: - Location sharing "location_sharing_title" = "Location"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 105a5d70e8..e098748096 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -4883,6 +4883,10 @@ public class VectorL10n: NSObject { public static var pollTimelineOneVote: String { return VectorL10n.tr("Vector", "poll_timeline_one_vote") } + /// Ended poll + public static var pollTimelineReplyEndedPoll: String { + return VectorL10n.tr("Vector", "poll_timeline_reply_ended_poll") + } /// Final results based on %lu votes public static func pollTimelineTotalFinalResults(_ p1: Int) -> String { return VectorL10n.tr("Vector", "poll_timeline_total_final_results", p1) diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift b/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift index f22c779fd1..4c942bccdd 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift +++ b/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift @@ -18,34 +18,38 @@ import Foundation class MXKSendReplyEventStringLocalizer: NSObject, MXSendReplyEventStringLocalizerProtocol { func senderSentAnImage() -> String { - return VectorL10n.messageReplyToSenderSentAnImage + VectorL10n.messageReplyToSenderSentAnImage } func senderSentAVideo() -> String { - return VectorL10n.messageReplyToSenderSentAVideo + VectorL10n.messageReplyToSenderSentAVideo } func senderSentAnAudioFile() -> String { - return VectorL10n.messageReplyToSenderSentAnAudioFile + VectorL10n.messageReplyToSenderSentAnAudioFile } func senderSentAVoiceMessage() -> String { - return VectorL10n.messageReplyToSenderSentAVoiceMessage + VectorL10n.messageReplyToSenderSentAVoiceMessage } func senderSentAFile() -> String { - return VectorL10n.messageReplyToSenderSentAFile + VectorL10n.messageReplyToSenderSentAFile } func senderSentTheirLocation() -> String { - return VectorL10n.messageReplyToSenderSentTheirLocation + VectorL10n.messageReplyToSenderSentTheirLocation } func senderSentTheirLiveLocation() -> String { - return VectorL10n.messageReplyToSenderSentTheirLiveLocation + VectorL10n.messageReplyToSenderSentTheirLiveLocation } func messageToReplyToPrefix() -> String { - return VectorL10n.messageReplyToMessageToReplyToPrefix + VectorL10n.messageReplyToMessageToReplyToPrefix + } + + func replyToEndedPoll() -> String { + VectorL10n.pollTimelineReplyEndedPoll } } From a8d041da3bec620176826203f70e40375ee3032c Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 12:43:11 +0100 Subject: [PATCH 075/160] =?UTF-8?q?Add=20replacement=20logic=20for=20?= =?UTF-8?q?=E2=80=9CEnded=20poll=E2=80=9D=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Utils/EventFormatter/MXKEventFormatter.m | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index cee8dccecc..4a7f6dc0ea 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -31,6 +31,7 @@ #import "GeneratedInterface-Swift.h" static NSString *const kHTMLATagRegexPattern = @"([^<]*)"; +static NSString *const kEndedPollPattern = @".*
.*
(.*)
"; @interface MXKEventFormatter () { @@ -1808,6 +1809,7 @@ - (NSAttributedString*)renderHTMLString:(NSString*)htmlString } html = [self renderReplyTo:html withRoomState:roomState]; + html = [self renderPollEndedReplyTo:html repliedEvent:repliedEvent]; } // Apply the css style that corresponds to the event state @@ -2014,6 +2016,39 @@ - (NSString*)renderReplyTo:(NSString*)htmlString withRoomState:(MXRoomState*)roo return html; } +- (NSString*)renderPollEndedReplyTo:(NSString*)htmlString repliedEvent:(MXEvent*)repliedEvent { + static NSRegularExpression *endedPollRegex; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kEndedPollPattern options:NSRegularExpressionCaseInsensitive error:nil]; + }); + + NSTextCheckingResult* match = [endedPollRegex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)]; + NSString* finalString = htmlString; + + if (!(match && match.numberOfRanges > 1)) { + // no useful match found + return finalString; + } + + NSRange groupRange = [match rangeAtIndex:1]; + NSString* replacementText; + + if (repliedEvent) { + MXEvent* pollStartedEvent = [mxSession.store eventWithEventId:repliedEvent.relatesTo.eventId inRoom:repliedEvent.roomId]; + replacementText = [MXEventContentPollStart modelFromJSON:pollStartedEvent.content].question; + } + + if (replacementText == nil) { + replacementText = VectorL10n.pollTimelineReplyEndedPoll; + } + + finalString = [htmlString stringByReplacingCharactersInRange:groupRange withString:replacementText]; + + return finalString; +} + - (void)postFormatMutableAttributedString:(NSMutableAttributedString*)mutableAttributedString forEvent:(MXEvent*)event andRepliedEvent:(MXEvent*)repliedEvent From 69f3df08670d1220ec244e08e5ae1002cada82a2 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 15:05:35 +0100 Subject: [PATCH 076/160] Improve formatter --- .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index 4a7f6dc0ea..1e7d53fe95 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -2024,9 +2024,14 @@ - (NSString*)renderPollEndedReplyTo:(NSString*)htmlString repliedEvent:(MXEvent* endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kEndedPollPattern options:NSRegularExpressionCaseInsensitive error:nil]; }); - NSTextCheckingResult* match = [endedPollRegex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)]; NSString* finalString = htmlString; + if (repliedEvent.eventType != MXEventTypePollEnd) { + return finalString; + } + + NSTextCheckingResult* match = [endedPollRegex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)]; + if (!(match && match.numberOfRanges > 1)) { // no useful match found return finalString; From 80ce6b7f517f67fa2007f301071ee5ea05bc3bf2 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 16:10:15 +0100 Subject: [PATCH 077/160] =?UTF-8?q?Handle=20edge=20cases=20for=20plain=20?= =?UTF-8?q?=E2=80=9Cbody=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index 1e7d53fe95..c8dce874af 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -1882,6 +1882,12 @@ - (NSString*)buildHTMLStringForEvent:(MXEvent*)event inReplyToEvent:(MXEvent*)re { MXJSONModelSetString(repliedEventContent, repliedEvent.content[kMXMessageBodyKey]); } + if (!repliedEventContent && repliedEvent.eventType == MXEventTypePollStart) { + repliedEventContent = [MXEventContentPollStart modelFromJSON:repliedEvent.content].question; + } + if (!repliedEventContent && repliedEvent.eventType == MXEventTypePollEnd) { + repliedEventContent = MXSendReplyEventDefaultStringLocalizer.new.replyToEndedPoll; + } } // No message content in a non-redacted event. Formatter should use fallback. From 2a2df206b59f6d39788824e5925d166521df6f3b Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:22:38 +0100 Subject: [PATCH 078/160] Improve code --- .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index c8dce874af..422e089902 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -31,7 +31,7 @@ #import "GeneratedInterface-Swift.h" static NSString *const kHTMLATagRegexPattern = @"([^<]*)"; -static NSString *const kEndedPollPattern = @".*
.*
(.*)
"; +static NSString *const kRepliedTextPattern = @".*
.*
(.*)
"; @interface MXKEventFormatter () { @@ -2027,7 +2027,7 @@ - (NSString*)renderPollEndedReplyTo:(NSString*)htmlString repliedEvent:(MXEvent* static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kEndedPollPattern options:NSRegularExpressionCaseInsensitive error:nil]; + endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kRepliedTextPattern options:NSRegularExpressionCaseInsensitive error:nil]; }); NSString* finalString = htmlString; From 956994269170229d1bac6650209ed073b1d2a09e Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:23:12 +0100 Subject: [PATCH 079/160] Add UTs --- ...wift => MXKEventFormatterSwiftTests.swift} | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) rename RiotTests/MatrixKitTests/{MXKEventFormatterTests.swift => MXKEventFormatterSwiftTests.swift} (72%) diff --git a/RiotTests/MatrixKitTests/MXKEventFormatterTests.swift b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift similarity index 72% rename from RiotTests/MatrixKitTests/MXKEventFormatterTests.swift rename to RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift index 31db309545..03731dd50e 100644 --- a/RiotTests/MatrixKitTests/MXKEventFormatterTests.swift +++ b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift @@ -29,9 +29,10 @@ private enum Constants { static let expectedEditedHTML = "
In reply to alice
Edited message
Reply" static let expectedEditedHTMLWithNewContent = "
In reply to alice
New content
Reply" static let expectedEditedHTMLWithParsedItalic = "
In reply to alice
New content
Reply" + static let expectedReplyToPollEndedEvent = "
In reply to alice
Ended poll
Reply" } -class MXKEventFormatterTests: XCTestCase { +class MXKEventFormatterSwiftTests: XCTestCase { func testBuildHTMLString() { let formatter = MXKEventFormatter() let repliedEvent = MXEvent() @@ -73,4 +74,39 @@ class MXKEventFormatterTests: XCTestCase { repliedEvent.wireContent[kMXMessageContentKeyNewContent] = nil XCTAssertNil(buildHTML()) } + + func testBuildHTMLStringWithPollEndedReply() { + let formatter = MXKEventFormatter() + let repliedEvent: MXEvent = .mockEvent(eventType: kMXEventTypeStringPollEnd, body: nil) + + let event = MXEvent() + event.sender = "bob" + event.wireType = kMXEventTypeStringRoomMessage + event.wireContent = [ + kMXMessageTypeKey: kMXMessageTypeText, + kMXMessageBodyKey: Constants.replyBody, + kMXEventRelationRelatesToKey: [kMXEventContentRelatesToKeyInReplyTo: ["event_id": Constants.repliedEventId]] + ] + + let formattedText = formatter.buildHTMLString(for: event, inReplyTo: repliedEvent) + + XCTAssertEqual(formattedText, Constants.expectedReplyToPollEndedEvent) + } +} + +private extension MXEvent { + static func mockEvent(eventType: String, body: String? = Constants.repliedEventBody) -> MXEvent { + let repliedEvent = MXEvent() + repliedEvent.sender = "alice" + repliedEvent.roomId = Constants.roomId + repliedEvent.eventId = Constants.repliedEventId + repliedEvent.wireType = eventType + repliedEvent.wireContent = [kMXMessageTypeKey: kMXMessageTypeText] + + if let body = body { + repliedEvent.wireContent[kMXMessageBodyKey] = body + } + + return repliedEvent + } } From 91c61eb8f535f0ae23f022ec4720f008b072f4cb Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:25:14 +0100 Subject: [PATCH 080/160] Cleanup --- .../MatrixKitTests/MXKEventFormatterSwiftTests.swift | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift index 03731dd50e..457f108530 100644 --- a/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift +++ b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift @@ -35,17 +35,10 @@ private enum Constants { class MXKEventFormatterSwiftTests: XCTestCase { func testBuildHTMLString() { let formatter = MXKEventFormatter() - let repliedEvent = MXEvent() + let repliedEvent: MXEvent = .mockEvent(eventType: kMXEventTypeStringRoomMessage) let event = MXEvent() func buildHTML() -> String? { return formatter.buildHTMLString(for: event, inReplyTo: repliedEvent) } - // Initial setup. - repliedEvent.sender = "alice" - repliedEvent.roomId = Constants.roomId - repliedEvent.eventId = Constants.repliedEventId - repliedEvent.wireType = kMXEventTypeStringRoomMessage - repliedEvent.wireContent = [kMXMessageTypeKey: kMXMessageTypeText, - kMXMessageBodyKey: Constants.repliedEventBody] event.sender = "bob" event.wireType = kMXEventTypeStringRoomMessage event.wireContent = [ From f410ad13ada1560a796babef3466e4c1856e4776 Mon Sep 17 00:00:00 2001 From: Yoan Pintas Date: Wed, 18 Jan 2023 16:27:13 +0000 Subject: [PATCH 081/160] Voice broadcast connection error handling while recording (#7282) --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 + Riot/Modules/Application/AppCoordinator.swift | 6 ++ .../VoiceBroadcastPlaybackErrorView.swift | 8 +- .../VoiceBroadcastRecorderCoordinator.swift | 4 + .../VoiceBroadcastRecorderProvider.swift | 19 +++-- .../VoiceBroadcastRecorderService.swift | 18 +++++ ...oiceBroadcastRecorderServiceProtocol.swift | 3 + ...BroadcastRecorderConnectionErrorView.swift | 49 ++++++++++++ .../View/VoiceBroadcastRecorderView.swift | 80 ++++++++++--------- .../VoiceBroadcastRecorderModels.swift | 2 + .../VoiceBroadcastRecorderViewModel.swift | 6 ++ changelog.d/7229.change | 1 + 13 files changed, 152 insertions(+), 49 deletions(-) create mode 100644 RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderConnectionErrorView.swift create mode 100644 changelog.d/7229.change diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 95531c6da6..959d539fc2 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2220,6 +2220,7 @@ Tap the + to start adding people."; "voice_broadcast_voip_cannot_start_description" = "You can’t start a call as you are currently recording a live broadcast. Please end your live broadcast in order to start a call."; "voice_broadcast_connection_error_title" = "Connection error"; "voice_broadcast_connection_error_message" = "Unfortunately we’re unable to start a recording right now. Please try again later."; +"voice_broadcast_recorder_connection_error" = "Connection error - Recording paused"; // MARK: - Version check diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 105a5d70e8..bc1dd84710 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -9231,6 +9231,10 @@ public class VectorL10n: NSObject { public static var voiceBroadcastPlaybackLockScreenPlaceholder: String { return VectorL10n.tr("Vector", "voice_broadcast_playback_lock_screen_placeholder") } + /// Connection error - Recording paused + public static var voiceBroadcastRecorderConnectionError: String { + return VectorL10n.tr("Vector", "voice_broadcast_recorder_connection_error") + } /// Yes, stop public static var voiceBroadcastStopAlertAgreeButton: String { return VectorL10n.tr("Vector", "voice_broadcast_stop_alert_agree_button") diff --git a/Riot/Modules/Application/AppCoordinator.swift b/Riot/Modules/Application/AppCoordinator.swift index 202e698a04..8c84e8bb00 100755 --- a/Riot/Modules/Application/AppCoordinator.swift +++ b/Riot/Modules/Application/AppCoordinator.swift @@ -100,8 +100,14 @@ final class AppCoordinator: NSObject, AppCoordinatorType { if AppDelegate.theDelegate().isOffline { self.splitViewCoordinator?.showAppStateIndicator(with: VectorL10n.networkOfflineTitle, icon: UIImage(systemName: "wifi.slash")) + + // Pause voice broadcast recording without sending pending events. + VoiceBroadcastRecorderProvider.shared.pauseRecordingOnError() } else { self.splitViewCoordinator?.hideAppStateIndicator() + + // Send pause voice broadcast event. + VoiceBroadcastRecorderProvider.shared.pauseRecording() } } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/View/VoiceBroadcastPlaybackErrorView.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/View/VoiceBroadcastPlaybackErrorView.swift index 0ac7822c64..0836bc6618 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/View/VoiceBroadcastPlaybackErrorView.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/View/VoiceBroadcastPlaybackErrorView.swift @@ -28,19 +28,17 @@ struct VoiceBroadcastPlaybackErrorView: View { var action: (() -> Void)? var body: some View { - VStack { - VStack { + ZStack { + HStack { Image(uiImage: Asset.Images.errorIcon.image) .frame(width: 40, height: 40) Text(VectorL10n.voiceBroadcastPlaybackLoadingError) .multilineTextAlignment(.center) .font(theme.fonts.caption1) - .foregroundColor(theme.colors.primaryContent) + .foregroundColor(theme.colors.alert) } - .padding() } .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(theme.colors.system.ignoresSafeArea()) } } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift index 409266d155..2b33f4121f 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderCoordinator.swift @@ -70,6 +70,10 @@ final class VoiceBroadcastRecorderCoordinator: Coordinator, Presentable { voiceBroadcastRecorderViewModel.context.send(viewAction: .pause) } + func pauseRecordingOnError() { + voiceBroadcastRecorderViewModel.context.send(viewAction: .pauseOnError) + } + func isVoiceBroadcastRecording() -> Bool { return voiceBroadcastRecorderService.isRecording } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift index 7b82429cb5..9ef2d5c987 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift @@ -1,4 +1,4 @@ -// +// // Copyright 2022 New Vector Ltd // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,7 +38,7 @@ import Foundation if !self.coordinatorsForEventIdentifiers.isEmpty && self.redactionsListener == nil { redactionsListener = session?.listenToEvents([MXEventType(identifier: kMXEventTypeStringRoomRedaction)], self.handleRedactedEvent) } - + if self.coordinatorsForEventIdentifiers.isEmpty && self.redactionsListener != nil { session?.removeListener(self.redactionsListener) self.redactionsListener = nil @@ -49,7 +49,7 @@ import Foundation // MARK: Private private var currentEventIdentifier: String? - + // MARK: - Setup private override init() { } @@ -85,6 +85,11 @@ import Foundation voiceBroadcastRecorderCoordinatorForCurrentEvent()?.pauseRecording() } + /// Pause current voice broadcast recording without sending pending events. + @objc public func pauseRecordingOnError() { + voiceBroadcastRecorderCoordinatorForCurrentEvent()?.pauseRecordingOnError() + } + @objc public func isVoiceBroadcastRecording() -> Bool { guard let coordinator = voiceBroadcastRecorderCoordinatorForCurrentEvent() else { return false @@ -100,7 +105,7 @@ import Foundation guard let currentEventIdentifier = currentEventIdentifier else { return nil } - + return coordinatorsForEventIdentifiers[currentEventIdentifier] } @@ -109,11 +114,11 @@ import Foundation // ignore backwards events return } - + var coordinator = coordinatorsForEventIdentifiers.removeValue(forKey: event.redacts) - + coordinator?.toPresentable().dismiss(animated: false) { - coordinator = nil + coordinator = nil } } } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift index fd8fc664dd..c4851e7794 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/MatrixSDK/VoiceBroadcastRecorderService.swift @@ -116,6 +116,8 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol { // Discard the service on VoiceBroadcastService error. We keep the service in case of other error type if error as? VoiceBroadcastServiceError != nil { self.tearDownVoiceBroadcastService() + } else { + AppDelegate.theDelegate().showError(asAlert: error) } }) } @@ -136,6 +138,10 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol { } }, failure: { error in MXLog.error("[VoiceBroadcastRecorderService] Failed to pause voice broadcast", context: error) + // Pause voice broadcast recording without sending pending events. + if error is VoiceBroadcastServiceError == false { + AppDelegate.theDelegate().showError(asAlert: error) + } }) } @@ -151,6 +157,9 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol { UIApplication.shared.isIdleTimerDisabled = true }, failure: { error in MXLog.error("[VoiceBroadcastRecorderService] Failed to resume voice broadcast", context: error) + if error is VoiceBroadcastServiceError == false { + AppDelegate.theDelegate().showError(asAlert: error) + } }) } @@ -169,6 +178,15 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol { self.tearDownVoiceBroadcastService() } + func pauseOnErrorRecordingVoiceBroadcast() { + audioEngine.pause() + UIApplication.shared.isIdleTimerDisabled = false + invalidateTimer() + + // Update state + self.serviceDelegate?.voiceBroadcastRecorderService(self, didUpdateState: .error) + } + // MARK: - Private /// Reset chunk values. private func resetValues() { diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift index 1b3e77878e..78492fe15d 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Service/VoiceBroadcastRecorderServiceProtocol.swift @@ -42,4 +42,7 @@ protocol VoiceBroadcastRecorderServiceProtocol { /// Cancel voice broadcast recording after redacted it. func cancelRecordingVoiceBroadcast() + + /// Pause voice broadcast recording without sending pending events. + func pauseOnErrorRecordingVoiceBroadcast() } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderConnectionErrorView.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderConnectionErrorView.swift new file mode 100644 index 0000000000..051a6477b3 --- /dev/null +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderConnectionErrorView.swift @@ -0,0 +1,49 @@ +// +// Copyright 2023 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 SwiftUI + +struct VoiceBroadcastRecorderConnectionErrorView: View { + // MARK: - Properties + + // MARK: Private + + @Environment(\.theme) private var theme: ThemeSwiftUI + + // MARK: Public + + var action: (() -> Void)? + + var body: some View { + ZStack { + HStack(spacing: 0) { + Image(uiImage: Asset.Images.errorIcon.image) + .frame(width: 40, height: 40) + Text(VectorL10n.voiceBroadcastRecorderConnectionError) + .multilineTextAlignment(.center) + .font(theme.fonts.caption1) + .foregroundColor(theme.colors.alert) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct VoiceBroadcastRecorderConnectionErrorView_Previews: PreviewProvider { + static var previews: some View { + VoiceBroadcastRecorderConnectionErrorView() + } +} diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderView.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderView.swift index c0cafed9b7..c8e6532f6d 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderView.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/View/VoiceBroadcastRecorderView.swift @@ -26,7 +26,7 @@ struct VoiceBroadcastRecorderView: View { @State private var showingStopAlert = false private var backgroundColor: Color { - if viewModel.viewState.recordingState != .paused { + if viewModel.viewState.recordingState != .paused, viewModel.viewState.recordingState != .error { return theme.colors.alert } return theme.colors.quarterlyContent @@ -78,47 +78,53 @@ struct VoiceBroadcastRecorderView: View { .accessibilityIdentifier("liveButton") } - HStack(alignment: .top, spacing: 34.0) { - Button { - switch viewModel.viewState.recordingState { - case .started, .resumed: - viewModel.send(viewAction: .pause) - case .stopped: - viewModel.send(viewAction: .start) - case .paused: - viewModel.send(viewAction: .resume) + if viewModel.viewState.recordingState == .error { + VoiceBroadcastRecorderConnectionErrorView() + } else { + HStack(alignment: .top, spacing: 34.0) { + Button { + switch viewModel.viewState.recordingState { + case .started, .resumed: + viewModel.send(viewAction: .pause) + case .stopped: + viewModel.send(viewAction: .start) + case .paused: + viewModel.send(viewAction: .resume) + case .error: + break + } + } label: { + if viewModel.viewState.recordingState == .started || viewModel.viewState.recordingState == .resumed { + Image("voice_broadcast_record_pause") + .renderingMode(.original) + } else { + Image("voice_broadcast_record") + .renderingMode(.original) + } } - } label: { - if viewModel.viewState.recordingState == .started || viewModel.viewState.recordingState == .resumed { - Image("voice_broadcast_record_pause") - .renderingMode(.original) - } else { - Image("voice_broadcast_record") + .accessibilityIdentifier("recordButton") + + Button { + showingStopAlert = true + } label: { + Image("voice_broadcast_stop") .renderingMode(.original) } + .alert(isPresented:$showingStopAlert) { + Alert(title: Text(VectorL10n.voiceBroadcastStopAlertTitle), + message: Text(VectorL10n.voiceBroadcastStopAlertDescription), + primaryButton: .cancel(), + secondaryButton: .default(Text(VectorL10n.voiceBroadcastStopAlertAgreeButton), + action: { + viewModel.send(viewAction: .stop) + })) + } + .accessibilityIdentifier("stopButton") + .disabled(viewModel.viewState.recordingState == .stopped) + .mask(Color.black.opacity(viewModel.viewState.recordingState == .stopped ? 0.3 : 1.0)) } - .accessibilityIdentifier("recordButton") - - Button { - showingStopAlert = true - } label: { - Image("voice_broadcast_stop") - .renderingMode(.original) - } - .alert(isPresented:$showingStopAlert) { - Alert(title: Text(VectorL10n.voiceBroadcastStopAlertTitle), - message: Text(VectorL10n.voiceBroadcastStopAlertDescription), - primaryButton: .cancel(), - secondaryButton: .default(Text(VectorL10n.voiceBroadcastStopAlertAgreeButton), - action: { - viewModel.send(viewAction: .stop) - })) - } - .accessibilityIdentifier("stopButton") - .disabled(viewModel.viewState.recordingState == .stopped) - .mask(Color.black.opacity(viewModel.viewState.recordingState == .stopped ? 0.3 : 1.0)) + .padding(EdgeInsets(top: 10.0, leading: 0.0, bottom: 10.0, trailing: 0.0)) } - .padding(EdgeInsets(top: 10.0, leading: 0.0, bottom: 10.0, trailing: 0.0)) } .padding(EdgeInsets(top: 12.0, leading: 4.0, bottom: 12.0, trailing: 4.0)) } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderModels.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderModels.swift index cb807a430c..f992cd2f46 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderModels.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderModels.swift @@ -21,6 +21,7 @@ enum VoiceBroadcastRecorderViewAction { case stop case pause case resume + case pauseOnError } enum VoiceBroadcastRecorderState { @@ -28,6 +29,7 @@ enum VoiceBroadcastRecorderState { case stopped case paused case resumed + case error } struct VoiceBroadcastRecorderDetails { diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderViewModel.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderViewModel.swift index ba9690bfb1..ff486c5df9 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderViewModel.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/VoiceBroadcastRecorderViewModel.swift @@ -56,6 +56,8 @@ class VoiceBroadcastRecorderViewModel: VoiceBroadcastRecorderViewModelType, Voic pause() case .resume: resume() + case .pauseOnError: + pauseOnError() } } @@ -80,6 +82,10 @@ class VoiceBroadcastRecorderViewModel: VoiceBroadcastRecorderViewModelType, Voic voiceBroadcastRecorderService.resumeRecordingVoiceBroadcast() } + private func pauseOnError() { + voiceBroadcastRecorderService.pauseOnErrorRecordingVoiceBroadcast() + } + private func updateRemainingTime(_ remainingTime: UInt) { state.currentRecordingState = VoiceBroadcastRecorderViewModel.currentRecordingState(from: remainingTime) } diff --git a/changelog.d/7229.change b/changelog.d/7229.change new file mode 100644 index 0000000000..7099b85005 --- /dev/null +++ b/changelog.d/7229.change @@ -0,0 +1 @@ +Voice broadcast connection error handling while recording. From 0df3c31d6bde15e32ed30dff5cd35750a8c06481 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:27:30 +0100 Subject: [PATCH 082/160] Add changelog.d file --- changelog.d/pr-7284.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-7284.change diff --git a/changelog.d/pr-7284.change b/changelog.d/pr-7284.change new file mode 100644 index 0000000000..edab718561 --- /dev/null +++ b/changelog.d/pr-7284.change @@ -0,0 +1 @@ +Polls: render replies to poll events better. From 9480bb714a0b6f0d3ad87e9b115075109380d226 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 16 Jan 2023 17:18:53 +0000 Subject: [PATCH 083/160] Display migration progress during startup --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 +++ Riot/Modules/Application/LegacyAppDelegate.m | 6 ++-- .../AuthenticationCoordinator.swift | 4 +-- .../LegacyAuthenticationCoordinator.swift | 4 +-- .../LaunchLoading/LaunchLoadingView.swift | 32 +++++++++++++------ .../LaunchLoadingViewController.swift | 4 +-- changelog.d/pr-7286.change | 1 + 8 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 changelog.d/pr-7286.change diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index bf1b697465..62f0797dcb 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1977,6 +1977,7 @@ Tap the + to start adding people."; // MARK: - Launch loading +"launch_loading_migrating_data" = "Migrating data\n%@ %%"; "launch_loading_server_syncing" = "Syncing with the server"; "launch_loading_server_syncing_nth_attempt" = "Syncing with the server\n(%@ attempt)"; "launch_loading_processing_response" = "Processing data\n%@ %%"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 3de9542c2e..bb8e85211b 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -3179,6 +3179,10 @@ public class VectorL10n: NSObject { public static var later: String { return VectorL10n.tr("Vector", "later") } + /// Migrating data\n%@ %% + public static func launchLoadingMigratingData(_ p1: String) -> String { + return VectorL10n.tr("Vector", "launch_loading_migrating_data", p1) + } /// Processing data\n%@ %% public static func launchLoadingProcessingResponse(_ p1: String) -> String { return VectorL10n.tr("Vector", "launch_loading_processing_response", p1) diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 15cdb8be1c..6ede5be425 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -2395,14 +2395,14 @@ - (void)showLaunchAnimation MXLogDebug(@"[AppDelegate] showLaunchAnimation"); LaunchLoadingView *launchLoadingView; - if (MXSDKOptions.sharedInstance.enableSyncProgress) + if (MXSDKOptions.sharedInstance.enableStartupProgress) { MXSession *mainSession = self.mxSessions.firstObject; - launchLoadingView = [LaunchLoadingView instantiateWithSyncProgress:mainSession.syncProgress]; + launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:mainSession.startupProgress]; } else { - launchLoadingView = [LaunchLoadingView instantiateWithSyncProgress:nil]; + launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:nil]; } launchLoadingView.frame = window.bounds; diff --git a/Riot/Modules/Authentication/AuthenticationCoordinator.swift b/Riot/Modules/Authentication/AuthenticationCoordinator.swift index 8b98989929..9f2e7083b6 100644 --- a/Riot/Modules/Authentication/AuthenticationCoordinator.swift +++ b/Riot/Modules/Authentication/AuthenticationCoordinator.swift @@ -613,8 +613,8 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc /// Replace the contents of the navigation router with a loading animation. private func showLoadingAnimation() { - let syncProgress: MXSessionSyncProgress? = MXSDKOptions.sharedInstance().enableSyncProgress ? session?.syncProgress : nil - let loadingViewController = LaunchLoadingViewController(syncProgress: syncProgress) + let startupProgress: MXSessionStartupProgress? = MXSDKOptions.sharedInstance().enableStartupProgress ? session?.startupProgress : nil + let loadingViewController = LaunchLoadingViewController(startupProgress: startupProgress) loadingViewController.modalPresentationStyle = .fullScreen // Replace the navigation stack with the loading animation diff --git a/Riot/Modules/Authentication/Legacy/LegacyAuthenticationCoordinator.swift b/Riot/Modules/Authentication/Legacy/LegacyAuthenticationCoordinator.swift index 583419075f..d6270edae1 100644 --- a/Riot/Modules/Authentication/Legacy/LegacyAuthenticationCoordinator.swift +++ b/Riot/Modules/Authentication/Legacy/LegacyAuthenticationCoordinator.swift @@ -106,8 +106,8 @@ final class LegacyAuthenticationCoordinator: NSObject, AuthenticationCoordinator // MARK: - Private private func showLoadingAnimation() { - let syncProgress: MXSessionSyncProgress? = MXSDKOptions.sharedInstance().enableSyncProgress ? session?.syncProgress : nil - let loadingViewController = LaunchLoadingViewController(syncProgress: syncProgress) + let startupProgress: MXSessionStartupProgress? = MXSDKOptions.sharedInstance().enableStartupProgress ? session?.startupProgress : nil + let loadingViewController = LaunchLoadingViewController(startupProgress: startupProgress) loadingViewController.modalPresentationStyle = .fullScreen // Replace the navigation stack with the loading animation diff --git a/Riot/Modules/LaunchLoading/LaunchLoadingView.swift b/Riot/Modules/LaunchLoading/LaunchLoadingView.swift index 55f3aff054..18d6add9d4 100644 --- a/Riot/Modules/LaunchLoading/LaunchLoadingView.swift +++ b/Riot/Modules/LaunchLoading/LaunchLoadingView.swift @@ -41,9 +41,9 @@ final class LaunchLoadingView: UIView, NibLoadable, Themable { // MARK: - Setup - static func instantiate(syncProgress: MXSessionSyncProgress?) -> LaunchLoadingView { + static func instantiate(startupProgress: MXSessionStartupProgress?) -> LaunchLoadingView { let view = LaunchLoadingView.loadFromNib() - syncProgress?.delegate = view + startupProgress?.delegate = view return view } @@ -54,7 +54,7 @@ final class LaunchLoadingView: UIView, NibLoadable, Themable { animationTimeline.play() self.animationTimeline = animationTimeline - self.statusLabel.isHidden = !MXSDKOptions.sharedInstance().enableSyncProgress + self.statusLabel.isHidden = !MXSDKOptions.sharedInstance().enableStartupProgress } // MARK: - Public @@ -65,21 +65,35 @@ final class LaunchLoadingView: UIView, NibLoadable, Themable { } } -extension LaunchLoadingView: MXSessionSyncProgressDelegate { - func sessionDidUpdateSyncState(_ state: MXSessionSyncState) { - guard MXSDKOptions.sharedInstance().enableSyncProgress else { +extension LaunchLoadingView: MXSessionStartupProgressDelegate { + func sessionDidUpdateStartupStage(_ stage: MXSessionStartupStage) { + guard MXSDKOptions.sharedInstance().enableStartupProgress else { + return + } + updateStatusText(for: stage) + + } + + private func updateStatusText(for stage: MXSessionStartupStage) { + guard Thread.isMainThread else { + DispatchQueue.main.async { [weak self] in + self?.updateStatusText(for: stage) + } return } // Sync may be doing a lot of heavy work on the main thread and the status text // does not update reliably enough without explicitly refreshing CATransaction.begin() - statusLabel.text = statusText(for: state) + statusLabel.text = statusText(for: stage) CATransaction.commit() } - private func statusText(for state: MXSessionSyncState) -> String { - switch state { + private func statusText(for stage: MXSessionStartupStage) -> String { + switch stage { + case .migratingData(let progress): + let percent = Int(floor(progress * 100)) + return VectorL10n.launchLoadingMigratingData("\(percent)") case .serverSyncing(let attempts): if attempts > 1, let nth = numberFormatter.string(from: NSNumber(value: attempts)) { return VectorL10n.launchLoadingServerSyncingNthAttempt(nth) diff --git a/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift index 1da229b79a..ef9630dda9 100644 --- a/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift +++ b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift @@ -21,10 +21,10 @@ class LaunchLoadingViewController: UIViewController, Reusable { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - init(syncProgress: MXSessionSyncProgress?) { + init(startupProgress: MXSessionStartupProgress?) { super.init(nibName: "LaunchLoadingViewController", bundle: nil) - let launchLoadingView = LaunchLoadingView.instantiate(syncProgress: syncProgress) + let launchLoadingView = LaunchLoadingView.instantiate(startupProgress: startupProgress) launchLoadingView.update(theme: ThemeService.shared().theme) view.vc_addSubViewMatchingParent(launchLoadingView) diff --git a/changelog.d/pr-7286.change b/changelog.d/pr-7286.change new file mode 100644 index 0000000000..ff8cbb8204 --- /dev/null +++ b/changelog.d/pr-7286.change @@ -0,0 +1 @@ +CryptoV2: Display migration progress during startup From 37bd17798c4df13e4b039ee3e72a00a855395871 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Thu, 19 Jan 2023 12:13:44 +0100 Subject: [PATCH 084/160] Delete a voice broadcast with all related events if MSC3912 is supported. --- Riot/Modules/Room/RoomViewController.m | 42 ++++++++++++++++++-------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index a1a0b6b6c3..e701aacf6b 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -4302,18 +4302,36 @@ - (void)showAdditionalActionsMenuForEvent:(MXEvent*)selectedEvent inCell:(id Date: Fri, 20 Jan 2023 09:27:20 +0100 Subject: [PATCH 085/160] Add Towncrier file --- changelog.d/7283.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7283.feature diff --git a/changelog.d/7283.feature b/changelog.d/7283.feature new file mode 100644 index 0000000000..d139728d5a --- /dev/null +++ b/changelog.d/7283.feature @@ -0,0 +1 @@ +Voice Broadcast: When deleting a voice broadcast, all data is now deleted on server side (MSC3912 implementation). From 6f019b8918a84a6fb3d6043eede15053960f93ee Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Fri, 20 Jan 2023 16:09:18 +0100 Subject: [PATCH 086/160] Pause the voicebroadcast recording if the homeserver is not reachable --- Riot/Modules/Application/AppCoordinator.swift | 8 +--- .../VoiceBroadcastRecorderProvider.swift | 47 ++++++++++++++++++- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Riot/Modules/Application/AppCoordinator.swift b/Riot/Modules/Application/AppCoordinator.swift index 8c84e8bb00..c356d0b863 100755 --- a/Riot/Modules/Application/AppCoordinator.swift +++ b/Riot/Modules/Application/AppCoordinator.swift @@ -100,14 +100,8 @@ final class AppCoordinator: NSObject, AppCoordinatorType { if AppDelegate.theDelegate().isOffline { self.splitViewCoordinator?.showAppStateIndicator(with: VectorL10n.networkOfflineTitle, icon: UIImage(systemName: "wifi.slash")) - - // Pause voice broadcast recording without sending pending events. - VoiceBroadcastRecorderProvider.shared.pauseRecordingOnError() } else { - self.splitViewCoordinator?.hideAppStateIndicator() - - // Send pause voice broadcast event. - VoiceBroadcastRecorderProvider.shared.pauseRecording() + self.splitViewCoordinator?.hideAppStateIndicator() } } diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift index 9ef2d5c987..b694765937 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastRecorder/Coordinator/VoiceBroadcastRecorderProvider.swift @@ -32,6 +32,9 @@ import Foundation coordinatorsForEventIdentifiers.removeAll() } } + didSet { + sessionState = session?.state + } } private var coordinatorsForEventIdentifiers = [String: VoiceBroadcastRecorderCoordinator]() { didSet { @@ -49,9 +52,19 @@ import Foundation // MARK: Private private var currentEventIdentifier: String? + private var sessionState: MXSessionState? + + private var sessionStateDidChangeObserver: Any? // MARK: - Setup - private override init() { } + private override init() { + super.init() + self.registerNotificationObservers() + } + + deinit { + unregisterNotificationObservers() + } // MARK: - Public @@ -121,4 +134,36 @@ import Foundation coordinator = nil } } + + // MARK: - Notification handling + + private func registerNotificationObservers() { + self.sessionStateDidChangeObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.mxSessionStateDidChange, object: session, queue: nil) { [weak self] notification in + guard let self else { return } + guard let concernedSession = notification.object as? MXSession, self.session === concernedSession else { return } + + self.update(sessionState: concernedSession.state) + } + } + + private func unregisterNotificationObservers() { + if let observer = self.sessionStateDidChangeObserver { + NotificationCenter.default.removeObserver(observer) + } + } + + // MARK: - Session state + private func update(sessionState: MXSessionState) { + let oldState = self.sessionState + self.sessionState = sessionState + + switch (oldState, sessionState) { + case (_, .homeserverNotReachable): + pauseRecordingOnError() + case (_, .running): + pauseRecording() + default: + break + } + } } From d31ab31c7772002e7611922ab42c27451e8432a8 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Mon, 23 Jan 2023 09:22:00 +0100 Subject: [PATCH 087/160] Add Towncrier file. --- changelog.d/7285.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7285.change diff --git a/changelog.d/7285.change b/changelog.d/7285.change new file mode 100644 index 0000000000..9d3f369ae8 --- /dev/null +++ b/changelog.d/7285.change @@ -0,0 +1 @@ +Voice Broadcast: handle the lost of connectivity with the homeserver while recording. From ad796ee5091f43bf946825e216e0bb81d8eb337d Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Mon, 23 Jan 2023 16:47:17 +0100 Subject: [PATCH 088/160] Use the new endpoint for redaction --- Riot/Modules/Room/RoomViewController.m | 47 +++++++++++--------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index e701aacf6b..c1a760c480 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -4302,36 +4302,27 @@ - (void)showAdditionalActionsMenuForEvent:(MXEvent*)selectedEvent inCell:(id* relationTypes = nil; // If it's a voice broadcast, delete the selected event and all related events (only if this feature is supported). - BOOL supportsRedactionWithRelations = self.mainSession.store.supportedMatrixVersions.supportsRedactionWithRelations || self.mainSession.store.supportedMatrixVersions.supportsRedactionWithRelationsUnstable; - if (supportsRedactionWithRelations && selectedEvent.eventType == MXEventTypeCustom && [selectedEvent.type isEqualToString:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType]) { - MXWeakify(self); - [self.roomDataSource.room redactEvent:selectedEvent.eventId withRelations:@[MXEventRelationTypeReference] reason:nil success:^{ - MXStrongifyAndReturnIfNil(self); - [self stopActivityIndicator]; - } failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - [self stopActivityIndicator]; - - MXLogDebug(@"[RoomVC] Redact event (%@) failed", selectedEvent.eventId); - //Alert user - [self showError:error]; - }]; - - } else { - MXWeakify(self); - [self.roomDataSource.room redactEvent:selectedEvent.eventId reason:nil success:^{ - MXStrongifyAndReturnIfNil(self); - [self stopActivityIndicator]; - } failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - [self stopActivityIndicator]; - - MXLogDebug(@"[RoomVC] Redact event (%@) failed", selectedEvent.eventId); - //Alert user - [self showError:error]; - }]; + if (selectedEvent.eventType == MXEventTypeCustom && [selectedEvent.type isEqualToString:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType]) { + // Check if the homeserver supports redaction with relations + if (self.mainSession.store.supportedMatrixVersions.supportsRedactionWithRelations || self.mainSession.store.supportedMatrixVersions.supportsRedactionWithRelationsUnstable) { + relationTypes = @[MXEventRelationTypeReference]; + } } + + MXWeakify(self); + [self.roomDataSource.room redactEvent:selectedEvent.eventId withRelations:relationTypes reason:nil success:^{ + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + + MXLogDebug(@"[RoomVC] Redact event (%@) failed", selectedEvent.eventId); + //Alert user + [self showError:error]; + }]; }]]; } From fd71b40d4ed5847f5c3867df5dfe4d0b506b9e22 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Mon, 23 Jan 2023 17:06:47 +0100 Subject: [PATCH 089/160] Always try to delete a voicebroadcast with relations. The SDK will ensure the feature is supported. --- Riot/Modules/Room/RoomViewController.m | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index c1a760c480..3792fee645 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -4303,12 +4303,9 @@ - (void)showAdditionalActionsMenuForEvent:(MXEvent*)selectedEvent inCell:(id* relationTypes = nil; - // If it's a voice broadcast, delete the selected event and all related events (only if this feature is supported). + // If it's a voice broadcast, delete the selected event and all related events. if (selectedEvent.eventType == MXEventTypeCustom && [selectedEvent.type isEqualToString:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType]) { - // Check if the homeserver supports redaction with relations - if (self.mainSession.store.supportedMatrixVersions.supportsRedactionWithRelations || self.mainSession.store.supportedMatrixVersions.supportsRedactionWithRelationsUnstable) { - relationTypes = @[MXEventRelationTypeReference]; - } + relationTypes = @[MXEventRelationTypeReference]; } MXWeakify(self); From 0c1745729954855ecd75f8762f186b93cc6552d9 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Mon, 23 Jan 2023 17:14:11 +0000 Subject: [PATCH 090/160] Fix compile error --- .../VoiceBroadcastSDK/VoiceBroadcastService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift index c41d5d37d9..66bd6dd575 100644 --- a/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift +++ b/Riot/Modules/VoiceBroadcast/VoiceBroadcastSDK/VoiceBroadcastService.swift @@ -298,7 +298,7 @@ extension MXRoom { threadId: String? = nil, sequence: UInt, success: @escaping ((String?) -> Void), - failure: @escaping ((Error?) -> Void)) -> MXHTTPOperation? { + failure: @escaping ((Swift.Error?) -> Void)) -> MXHTTPOperation? { guard let relatesTo = MXEventContentRelatesTo(relationType: MXEventRelationTypeReference, eventId: voiceBroadcastId).jsonDictionary() as? [String: Any] else { failure(VoiceBroadcastServiceError.unknown) From 60e4e562ebe308673b516175028c39b7988c8be0 Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Tue, 24 Jan 2023 09:15:55 +0100 Subject: [PATCH 091/160] Fix a crash for some voice broadcast in case of redaction --- .../Coordinator/VoiceBroadcastPlaybackCoordinator.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift index 963dba5585..7df3eaa048 100644 --- a/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/VoiceBroadcastPlayback/Coordinator/VoiceBroadcastPlaybackCoordinator.swift @@ -57,7 +57,8 @@ final class VoiceBroadcastPlaybackCoordinator: Coordinator, Presentable { } deinit { - viewModel.context.send(viewAction: .redact) + // If init has failed, our viewmodel will be nil. + viewModel?.context.send(viewAction: .redact) } // MARK: - Public From 79d04a82d72ed376eb871aa4f85c752facfd5f1e Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 10 Jan 2023 14:21:37 +0000 Subject: [PATCH 092/160] Translated using Weblate (Hungarian) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/hu/ --- Riot/Assets/hu.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/hu.lproj/Localizable.strings b/Riot/Assets/hu.lproj/Localizable.strings index 82161237e2..fee155510e 100644 --- a/Riot/Assets/hu.lproj/Localizable.strings +++ b/Riot/Assets/hu.lproj/Localizable.strings @@ -120,3 +120,6 @@ /* New video message from a specific person, not referencing a room. */ "VIDEO_FROM_USER" = "%@ videót küldött"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@ hang közvetítést indított"; From f101507e1a79b5f2be0f41ff17c2e92d89377875 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Tue, 10 Jan 2023 18:00:06 +0000 Subject: [PATCH 093/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/uk/ --- Riot/Assets/uk.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/uk.lproj/Localizable.strings b/Riot/Assets/uk.lproj/Localizable.strings index 276df4c3e1..90e0de28ed 100644 --- a/Riot/Assets/uk.lproj/Localizable.strings +++ b/Riot/Assets/uk.lproj/Localizable.strings @@ -118,3 +118,6 @@ /* New file message from a specific person, not referencing a room. */ "LOCATION_FROM_USER" = "%@ надсилає дані про своє місцеперебування"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@ розпочинає голосову трансляцію"; From d3baadf95f683c1347ab97777ae4df50121a4aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Tue, 10 Jan 2023 18:37:04 +0000 Subject: [PATCH 094/160] Translated using Weblate (Estonian) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/et/ --- Riot/Assets/et.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/et.lproj/Localizable.strings b/Riot/Assets/et.lproj/Localizable.strings index 9f10028001..b3a015217f 100644 --- a/Riot/Assets/et.lproj/Localizable.strings +++ b/Riot/Assets/et.lproj/Localizable.strings @@ -118,3 +118,6 @@ /* New file message from a specific person, not referencing a room. */ "LOCATION_FROM_USER" = "%@ jagas oma asukohta"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@ alustas ringhäälingukõnet"; From 4e5954f0b13b0a3f9d9b957203bea384c08ffb06 Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Tue, 10 Jan 2023 17:16:49 +0000 Subject: [PATCH 095/160] Translated using Weblate (Slovak) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/sk/ --- Riot/Assets/sk.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/sk.lproj/Localizable.strings b/Riot/Assets/sk.lproj/Localizable.strings index 612c4f691e..02c0860658 100644 --- a/Riot/Assets/sk.lproj/Localizable.strings +++ b/Riot/Assets/sk.lproj/Localizable.strings @@ -168,3 +168,6 @@ /* New file message from a specific person, not referencing a room. */ "LOCATION_FROM_USER" = "%@ zdieľal/a svoju polohu"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@ začal/a hlasové vysielanie"; From d3e345e1787adf1ca4dac636856b25353442f04b Mon Sep 17 00:00:00 2001 From: LinAGKar Date: Thu, 12 Jan 2023 19:47:36 +0000 Subject: [PATCH 096/160] Translated using Weblate (Swedish) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/sv/ --- Riot/Assets/sv.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/sv.lproj/Localizable.strings b/Riot/Assets/sv.lproj/Localizable.strings index 5b3e918dda..fc7c18b9ea 100644 --- a/Riot/Assets/sv.lproj/Localizable.strings +++ b/Riot/Assets/sv.lproj/Localizable.strings @@ -118,3 +118,6 @@ /* New file message from a specific person, not referencing a room. */ "LOCATION_FROM_USER" = "%@ delade sin plats"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@ påbörjade en röstsändning"; From 02ecb5b168d9a1ba97e51cc654d54831c669c1f0 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 10 Jan 2023 14:22:00 +0000 Subject: [PATCH 097/160] Translated using Weblate (Hungarian) Currently translated at 100.0% (2352 of 2352 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index 53debbedba..654254007f 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2688,3 +2688,4 @@ "poll_timeline_decryption_error" = "Visszafejtési hibák miatt néhány szavazat nem kerül beszámításra"; "voice_message_broadcast_in_progress_message" = "Nem lehet hang üzenetet indítani élő közvetítés felvétele közben. Az élő közvetítés bejezése szükséges a hang üzenet indításához"; "voice_message_broadcast_in_progress_title" = "Hang üzenetet nem lehet elindítani"; +"poll_timeline_ended_text" = "Szavazás vége"; From d5f717641f6fe51ea16ee629fc5b20bab68df0aa Mon Sep 17 00:00:00 2001 From: random Date: Fri, 13 Jan 2023 14:42:20 +0000 Subject: [PATCH 098/160] Translated using Weblate (Italian) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/it/ --- Riot/Assets/it.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/it.lproj/Localizable.strings b/Riot/Assets/it.lproj/Localizable.strings index bb8b3e7078..3232ff2a45 100644 --- a/Riot/Assets/it.lproj/Localizable.strings +++ b/Riot/Assets/it.lproj/Localizable.strings @@ -118,3 +118,6 @@ /* New file message from a specific person, not referencing a room. */ "LOCATION_FROM_USER" = "%@ ha condiviso la sua posizione"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@ ha iniziato una trasmissione vocale"; From 27cdd5c61a4c8465ccc890a069314e72a206d74e Mon Sep 17 00:00:00 2001 From: Linerly Date: Tue, 10 Jan 2023 13:55:29 +0000 Subject: [PATCH 099/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2352 of 2352 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index d6449680c6..821491fb2e 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2895,3 +2895,4 @@ "poll_timeline_decryption_error" = "Karena kesalahan enkripsi, beberapa suara mungkin tidak terhitung"; "voice_message_broadcast_in_progress_message" = "Anda tidak dapat memulai sebuah pesan suara selagi Anda merekam sebuah siaran langsung. Silakan mengakhiri siaran langsung Anda untuk memulai merekam sebuah pesan suara"; "voice_message_broadcast_in_progress_title" = "Tidak dapat memulai pesan suara"; +"poll_timeline_ended_text" = "Mengakhiri pemungutan suara"; From aa407eb98cbbeca97784cd664da5e062e56c010d Mon Sep 17 00:00:00 2001 From: xrh0905 <1014930533@qq.com> Date: Fri, 20 Jan 2023 00:27:49 +0000 Subject: [PATCH 100/160] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/zh_Hans/ --- Riot/Assets/zh_Hans.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/zh_Hans.lproj/Localizable.strings b/Riot/Assets/zh_Hans.lproj/Localizable.strings index 1e13dc6f68..2b4f707e24 100644 --- a/Riot/Assets/zh_Hans.lproj/Localizable.strings +++ b/Riot/Assets/zh_Hans.lproj/Localizable.strings @@ -123,3 +123,6 @@ /* New file message from a specific person, not referencing a room. */ "LOCATION_FROM_USER" = "%@ 分享了他们的位置"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@开始语音广播"; From 7f4a91d584ae38a38eeaafc175a228ae13cad9de Mon Sep 17 00:00:00 2001 From: Vri Date: Tue, 10 Jan 2023 15:08:34 +0000 Subject: [PATCH 101/160] Translated using Weblate (German) Currently translated at 99.9% (2353 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index f1886a04c2..b4b7991142 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2701,4 +2701,7 @@ "user_other_session_security_recommendation_title" = "Andere Sitzungen"; "voice_message_broadcast_in_progress_title" = "Kann Sprachnachricht nicht beginnen"; "poll_timeline_decryption_error" = "Aufgrund von Entschlüsselungsfehlern könnten einige Stimmen nicht gezählt werden"; -"voice_message_broadcast_in_progress_message" = "Du kannst kein Gespräch beginnen, da du im Moment eine Sprachübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen"; +"voice_message_broadcast_in_progress_message" = "Du kannst keine Sprachnachricht beginnen, da du im Moment eine Echtzeitübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen"; +"poll_timeline_ended_text" = "Abstimmung beendet"; +"voice_broadcast_voip_cannot_start_description" = "Du kannst keinen Anruf beginnen, da du im Moment eine Sprachübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen."; +"voice_broadcast_voip_cannot_start_title" = "Kann keinen Anruf beginnen"; From ecc1c0bee67a4fff5e71b22de2943b282b8b02ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sveinn=20=C3=AD=20Felli?= Date: Mon, 23 Jan 2023 10:17:07 +0000 Subject: [PATCH 102/160] Translated using Weblate (Icelandic) Currently translated at 100.0% (50 of 50 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/is/ --- Riot/Assets/is.lproj/Localizable.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/is.lproj/Localizable.strings b/Riot/Assets/is.lproj/Localizable.strings index ec3fdaace0..d471715149 100644 --- a/Riot/Assets/is.lproj/Localizable.strings +++ b/Riot/Assets/is.lproj/Localizable.strings @@ -170,3 +170,6 @@ /* Look, stuff's happened, alright? Just open the app. */ "MSGS_IN_TWO_PLUS_ROOMS" = "%@ ný skilaboð í %@, %@ og fleirum"; + +/* New voice broadcast from a specific person, not referencing a room. */ +"VOICE_BROADCAST_FROM_USER" = "%@ byrjaði talútsendingu"; From e6c2db4f4f8a075d1ce1ae7e21715854c53fba81 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Wed, 11 Jan 2023 10:03:43 +0000 Subject: [PATCH 103/160] Translated using Weblate (Hungarian) Currently translated at 100.0% (2354 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index 654254007f..4c50ec2961 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2689,3 +2689,5 @@ "voice_message_broadcast_in_progress_message" = "Nem lehet hang üzenetet indítani élő közvetítés felvétele közben. Az élő közvetítés bejezése szükséges a hang üzenet indításához"; "voice_message_broadcast_in_progress_title" = "Hang üzenetet nem lehet elindítani"; "poll_timeline_ended_text" = "Szavazás vége"; +"voice_broadcast_voip_cannot_start_description" = "Nem lehet hívást kezdeményezni élő közvetítés felvétele közben. Az élő közvetítés bejezése szükséges a hívás indításához."; +"voice_broadcast_voip_cannot_start_title" = "Nem sikerült hívást indítani"; From 93df57cd71eedbc7985105d9f5c70cefc62a945f Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Tue, 10 Jan 2023 18:08:55 +0000 Subject: [PATCH 104/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2354 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 96e8166d7b..63c432c085 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2893,3 +2893,6 @@ "poll_timeline_decryption_error" = "Через помилки під час розшифрування деякі голоси можуть бути не враховані"; "voice_message_broadcast_in_progress_title" = "Неможливо розпочати запис голосового повідомлення"; "voice_message_broadcast_in_progress_message" = "Ви не можете розпочати запис голосового повідомлення, оскільки зараз триває запис трансляції наживо. Будь ласка, завершіть трансляцію, щоб розпочати запис голосового повідомлення"; +"poll_timeline_ended_text" = "Опитування завершено"; +"voice_broadcast_voip_cannot_start_description" = "Ви не можете розпочати виклик, оскільки зараз відбувається запис трансляції наживо. Завершіть трансляцію, щоб розпочати виклик."; +"voice_broadcast_voip_cannot_start_title" = "Неможливо розпочати виклик"; From fbff22325dddfaec5abb717c7a1f45763c82a9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Tue, 10 Jan 2023 18:35:49 +0000 Subject: [PATCH 105/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2354 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index d84b26c76f..80fee8f729 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2640,3 +2640,6 @@ "poll_timeline_decryption_error" = "Krüptimisvigade tõttu jääb osa hääli lugemata"; "voice_message_broadcast_in_progress_title" = "Häälsõnumi salvestamine või esitamine ei õnnestu"; "voice_message_broadcast_in_progress_message" = "Kuna sa hetkel salvestad ringhäälingukõnet, siis häälsõnumi salvestamine või esitamine ei õnnestu. Selleks palun lõpeta ringhäälingukõne"; +"poll_timeline_ended_text" = "Küsitlus on lõppenud"; +"voice_broadcast_voip_cannot_start_description" = "Kuna sa hetkel salvestad ringhäälingukõnet, siis tavakõne algatamine ei õnnestu. Kõne alustamiseks palun lõpeta ringhäälingukõne."; +"voice_broadcast_voip_cannot_start_title" = "Kõne algatamine ei õnnestu"; From c3036fc75d4edec1dcf93cd9fb0b07746d231fc1 Mon Sep 17 00:00:00 2001 From: Linerly Date: Tue, 10 Jan 2023 23:40:59 +0000 Subject: [PATCH 106/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2354 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index 821491fb2e..bbc02ec1ab 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2893,6 +2893,8 @@ "notice_voice_broadcast_live" = "Siaran langsung"; "user_other_session_security_recommendation_title" = "Sesi lainnya"; "poll_timeline_decryption_error" = "Karena kesalahan enkripsi, beberapa suara mungkin tidak terhitung"; -"voice_message_broadcast_in_progress_message" = "Anda tidak dapat memulai sebuah pesan suara selagi Anda merekam sebuah siaran langsung. Silakan mengakhiri siaran langsung Anda untuk memulai merekam sebuah pesan suara"; +"voice_message_broadcast_in_progress_message" = "Anda tidak dapat memulai sebuah pesan suara karena Anda saat ini merekam sebuah siaran langsung. Silakan mengakhiri siaran langsung Anda untuk memulai merekam sebuah pesan suara"; "voice_message_broadcast_in_progress_title" = "Tidak dapat memulai pesan suara"; "poll_timeline_ended_text" = "Mengakhiri pemungutan suara"; +"voice_broadcast_voip_cannot_start_description" = "Anda tidak dapat memulai sebuah panggilan karena Anda saat ini merekam sebuah siaran langsung. Mohon akhiri siaran langsung Anda untuk memulai sebuah panggilan."; +"voice_broadcast_voip_cannot_start_title" = "Tidak dapat memulai sebuah panggilan"; From 453df1efeb671011d7d1fdb709703767589ac85a Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Tue, 10 Jan 2023 17:18:13 +0000 Subject: [PATCH 107/160] Translated using Weblate (Slovak) Currently translated at 100.0% (2354 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index 87edea36c0..c3c8a3c104 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2891,3 +2891,6 @@ "poll_timeline_decryption_error" = "Z dôvodu chýb v dešifrovaní sa niektoré hlasy nemusia započítať"; "voice_message_broadcast_in_progress_message" = "Nemôžete spustiť hlasovú správu, pretože práve nahrávate živé vysielanie. Ukončite prosím živé vysielanie, aby ste mohli začať nahrávať hlasovú správu"; "voice_message_broadcast_in_progress_title" = "Nemožno spustiť hlasovú správu"; +"poll_timeline_ended_text" = "Ukončil anketu"; +"voice_broadcast_voip_cannot_start_description" = "Nemôžete spustiť hovor, pretože práve nahrávate živé vysielanie. Ukončite živé vysielanie, aby ste mohli začať hovor."; +"voice_broadcast_voip_cannot_start_title" = "Nie je možné začať hovor"; From f5a676941925a8b0e8264d26717a2dbffae89a2f Mon Sep 17 00:00:00 2001 From: RS-Nocsi <13570286865@163.com> Date: Thu, 12 Jan 2023 05:25:03 +0000 Subject: [PATCH 108/160] Translated using Weblate (Chinese (Simplified)) Currently translated at 82.4% (1940 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/zh_Hans/ --- Riot/Assets/zh_Hans.lproj/Vector.strings | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Riot/Assets/zh_Hans.lproj/Vector.strings b/Riot/Assets/zh_Hans.lproj/Vector.strings index d7a775d4bc..bcd7213566 100644 --- a/Riot/Assets/zh_Hans.lproj/Vector.strings +++ b/Riot/Assets/zh_Hans.lproj/Vector.strings @@ -2231,3 +2231,44 @@ "onboarding_congratulations_home_button" = "带我到主页"; "onboarding_use_case_message" = "我们将帮助你连接"; "invite_to" = "邀请到%@"; +"threads_empty_title" = "保持讨论的有条理性"; +"threads_action_my_threads" = "我的线程"; +"threads_action_all_threads" = "所有线程"; +"threads_title" = "线程"; +"thread_copy_link_to_thread" = "将链接复制到线程"; + +// MARK: Threads +"room_thread_title" = "线程"; +"room_accessibility_record_voice_message_hint" = "双击并保持录音。"; +"room_accessibility_record_voice_message" = "录制语音消息"; +"room_accessibility_thread_more" = "更多"; +"room_accessibility_threads" = "线程"; +"room_event_copy_link_info" = "链接复制到剪贴板。"; +"room_event_action_reply_in_thread" = "线程"; +"room_event_action_view_in_room" = "在房间浏览"; +"room_first_message_placeholder" = "发送您的第一条消息……"; +"room_participants_invite_prompt_to_msg" = "您确定要邀请%@ 到 %@吗?"; +"room_participants_leave_success" = "离开房间"; +"room_participants_leave_processing" = "离开"; +"search_filter_placeholder" = "过滤"; +"password_policy_pwd_in_dict_error" = "此密码已在字典中找到,不允许使用。"; +"password_policy_weak_pwd_error" = "此密码太弱了。它必须包含至少8个字符,每种类型至少有一个字符: 大写、小写、数字和特殊字符。"; + +// MARK: Password policy errors +"password_policy_too_short_pwd_error" = "密码过短"; +"authentication_qr_login_failure_retry" = "再试一次"; +"authentication_qr_login_failure_request_timed_out" = "连接没有在规定的时间内完成。"; +"authentication_qr_login_failure_request_denied" = "请求在另一个设备上被拒绝。"; +"authentication_qr_login_failure_invalid_qr" = "二维码无效。"; +"authentication_qr_login_failure_title" = "连接失败"; +"authentication_qr_login_loading_signed_in" = "您现在已经登录到另一个设备上。"; +"authentication_qr_login_loading_waiting_signin" = "等待设备登录。"; +"authentication_qr_login_loading_connecting_device" = "连接到设备"; +"authentication_qr_login_confirm_alert" = "请确保您知道此代码的来源。通过连接设备,您将为某人提供对您帐户的完全访问权限。"; +"authentication_qr_login_confirm_subtitle" = "确认下面的代码与您的其他设备匹配:"; +"authentication_qr_login_confirm_title" = "建立安全连接"; +"authentication_qr_login_scan_subtitle" = "将二维码放置在下面的方框中"; +"authentication_qr_login_scan_title" = "扫描二维码"; +"authentication_qr_login_display_step2" = "选择“以二维码登入”"; +"authentication_qr_login_display_step1" = "在您的其它设备中打开Element"; +"onboarding_splash_page_4_title_no_pun" = "为您的团队发送消息。"; From 1e728f76505f53b3558e3ee39200348236873f8e Mon Sep 17 00:00:00 2001 From: Vri Date: Thu, 12 Jan 2023 10:50:24 +0000 Subject: [PATCH 109/160] Translated using Weblate (German) Currently translated at 99.9% (2353 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index b4b7991142..ccab1a9ca8 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2702,6 +2702,6 @@ "voice_message_broadcast_in_progress_title" = "Kann Sprachnachricht nicht beginnen"; "poll_timeline_decryption_error" = "Aufgrund von Entschlüsselungsfehlern könnten einige Stimmen nicht gezählt werden"; "voice_message_broadcast_in_progress_message" = "Du kannst keine Sprachnachricht beginnen, da du im Moment eine Echtzeitübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen"; -"poll_timeline_ended_text" = "Abstimmung beendet"; +"poll_timeline_ended_text" = "Umfrage beendet"; "voice_broadcast_voip_cannot_start_description" = "Du kannst keinen Anruf beginnen, da du im Moment eine Sprachübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen."; "voice_broadcast_voip_cannot_start_title" = "Kann keinen Anruf beginnen"; From d7a48ce36ca0a69751357a3b314cdd2686ed5079 Mon Sep 17 00:00:00 2001 From: random Date: Fri, 13 Jan 2023 14:41:47 +0000 Subject: [PATCH 110/160] Translated using Weblate (Italian) Currently translated at 100.0% (2354 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ --- Riot/Assets/it.lproj/Vector.strings | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Riot/Assets/it.lproj/Vector.strings b/Riot/Assets/it.lproj/Vector.strings index 35bd94c354..4a649f1c46 100644 --- a/Riot/Assets/it.lproj/Vector.strings +++ b/Riot/Assets/it.lproj/Vector.strings @@ -2665,3 +2665,9 @@ "notice_voice_broadcast_live" = "Trasmissione in diretta"; "wysiwyg_composer_format_action_inline_code" = "Applica formato codice interlinea"; "user_other_session_security_recommendation_title" = "Altre sessioni"; +"poll_timeline_ended_text" = "Sondaggio terminato"; +"poll_timeline_decryption_error" = "A causa di errori di decifrazione, alcuni voti potrebbero non venire contati"; +"voice_broadcast_voip_cannot_start_description" = "Non puoi avviare una chiamata perché stai registrando una trasmissione in diretta. Termina la trasmissione per potere iniziare una chiamata."; +"voice_broadcast_voip_cannot_start_title" = "Impossibile avviare una chiamata"; +"voice_message_broadcast_in_progress_title" = "Impossibile iniziare il messaggio vocale"; +"voice_message_broadcast_in_progress_message" = "Non puoi iniziare un messaggio vocale perché stai registrando una trasmissione in diretta. Termina la trasmissione per potere iniziare un messaggio vocale"; From 100d8b4234cf47673a8fa5620c8f42252e0ee255 Mon Sep 17 00:00:00 2001 From: LinAGKar Date: Fri, 13 Jan 2023 21:39:44 +0000 Subject: [PATCH 111/160] Translated using Weblate (Swedish) Currently translated at 93.9% (2212 of 2354 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sv/ --- Riot/Assets/sv.lproj/Vector.strings | 111 +++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/sv.lproj/Vector.strings b/Riot/Assets/sv.lproj/Vector.strings index 53b8d822f9..872645f667 100644 --- a/Riot/Assets/sv.lproj/Vector.strings +++ b/Riot/Assets/sv.lproj/Vector.strings @@ -2310,7 +2310,7 @@ "authentication_terms_policy_url_error" = "Kan inte hitta den valda policyn. Vänligen pröva igen senare."; /* The placeholder will show the homeserver's domain */ "authentication_terms_message" = "Vänligen läs villkor och policyer för %@"; -"authentication_terms_title" = "Serverpolicyer"; +"authentication_terms_title" = "Sekretesspolicyer"; "authentication_verify_msisdn_invalid_phone_number" = "Ogiltigt telefonnummer"; "authentication_verify_msisdn_waiting_button" = "Skicka kod igen"; /* The placeholder will show the phone number that was entered. */ @@ -2363,3 +2363,112 @@ // MARK: Authentication "authentication_registration_title" = "Skapa ditt konto"; +"voice_broadcast_time_left" = "%@ kvar"; +"all_chats_empty_list_placeholder_title" = "Du är ikapp."; +"all_chats_empty_view_information" = "Den säkra allt-i-ett-chattappen för lag, vänner och organisationer. Skapa en chatt, eller gå med i ett existerande rum, för att komma igång."; +"all_chats_empty_space_information" = "Utrymmen är ett nytt sätt att gruppera rum och personer. Lägg till ett existerande rum, eller skapa ett nytt, med knappen nere till höger."; +"all_chats_empty_view_title" = "%@\nser lite tom ut."; +"all_chats_all_filter" = "Alla"; +"all_chats_edit_layout_alphabetical_order" = "Sortera A-Ö"; +"all_chats_edit_layout_activity_order" = "Sortera efter aktivitet"; +"all_chats_edit_layout_show_filters" = "Visa filter"; +"all_chats_edit_layout_show_recents" = "Visa nyliga"; +"all_chats_edit_layout_sorting_options_title" = "Sortera meddelanden efter"; +"all_chats_edit_layout_pin_spaces_title" = "Fäst dina utrymmen"; +"all_chats_edit_layout_add_filters_message" = "Filtrera automatiskt dina meddelanden i valfria kategorier"; +"all_chats_edit_layout_add_filters_title" = "Filtrera dina meddelanden"; +"all_chats_edit_layout_add_section_message" = "Fäst sektioner till hem för enkel åtkomst"; +"all_chats_edit_layout_add_section_title" = "Lägg till sektion i hem"; +"all_chats_edit_layout_unreads" = "Olästa"; +"all_chats_edit_layout_recents" = "Nyliga"; +"all_chats_edit_layout" = "Layoutalternativ"; +"all_chats_section_title" = "Chattar"; + +// MARK: - All Chats + +"all_chats_title" = "Alla chattar"; +"voice_broadcast_voip_cannot_start_description" = "Du kan inte starta ett samtal eftersom att du för närvarande spelar in en direktsändning. Vänligen avsluta din direktsändning för att starta ett samtal."; +"voice_broadcast_voip_cannot_start_title" = "Kan inte starta ett samtal"; +"voice_broadcast_stop_alert_agree_button" = "Ja, avsluta"; +"voice_broadcast_stop_alert_description" = "Är du säker på att du vill avsluta din direktsändning? Det här kommer att avsluta sändningen, och den fulla inspelningen kommer att bli tillgänglig i rummet."; +"voice_broadcast_stop_alert_title" = "Avsluta direktsändning?"; +"voice_broadcast_buffering" = "Buffrar…"; +"voice_broadcast_tile" = "Röstsändning"; +"voice_broadcast_live" = "Live"; +"voice_broadcast_playback_loading_error" = "Kunde inte spela den här röstsändningen."; +"voice_broadcast_already_in_progress_message" = "Du spelar redan in en röstsändning. Vänligen avsluta din nuvarande röstsändning för att starta en ny."; +"voice_broadcast_blocked_by_someone_else_message" = "Någon annan spelar redan in en röstsändning. Vänta på att deras röstsändning avslutas för att starta en ny."; +"voice_broadcast_permission_denied_message" = "Du har inte behörigheten som krävs för att starta en röstsändning i det här rummet. Kontakta en rumsadministratör för att uppgradera din behörighet."; + +// MARK: - Voice Broadcast +"voice_broadcast_unauthorized_title" = "Du kan inte starta en ny röstsändning"; +"voice_message_broadcast_in_progress_message" = "Du kan inte starta ett röstmeddelande eftersom att du för närvarande spelar in en direktsändning. Vänligen avsluta din direktsändning för att börja spela in ett röstmeddelande"; +"voice_message_broadcast_in_progress_title" = "Kan inte starta röstmeddelande"; +"spaces_subspace_creation_visibility_message" = "Det skapade utrymmet kommer att läggas till i %@."; +"spaces_subspace_creation_visibility_title" = "Vad för sorts utrymme vill du skapa?"; +"spaces_explore_rooms_format" = "Utforska %@"; +"spaces_create_subspace_title" = "Skapa ett underutrymme"; +"spaces_add_subspace_title" = "Skapa utrymme inuti %@"; +"launch_loading_processing_response" = "Hanterar data\n%@ %%"; +"launch_loading_server_syncing_nth_attempt" = "Synkar med servern\n(%@ försök)"; + +// MARK: - Launch loading + +"launch_loading_server_syncing" = "Synkar med servern"; +"key_verification_alert_body" = "Granska för att försäkra att ditt konto är säkert."; + +// Unverified sessions +"key_verification_alert_title" = "Du har overifierade sessioner"; +"sign_out_confirmation_message" = "Är du säker på att du vill logga ut?"; + +// MARK: Sign out warning + +"sign_out" = "Logga ut"; +// User sessions management +"user_sessions_settings" = "Hantera sessioner"; +"manage_session_sign_out_other_sessions" = "Logga ut ur alla andra sessioner"; +"manage_session_rename" = "Döp om session"; +"manage_session_name_info_link" = "Läs mer"; +/* The placeholder will be replaces with manage_session_name_info_link */ +"manage_session_name_info" = "Observera att sessionsnamn också är synliga för personer du pratar med. %@"; +"manage_session_name_hint" = "Anpassade sessionsnamn kan hjälpa dig att känna igen dina enheter lättare."; +"settings_labs_enable_voice_broadcast" = "Röstsändning"; +"settings_labs_enable_wysiwyg_composer" = "Pröva den nya riktextredigeraren"; +"settings_labs_enable_new_app_layout" = "Ny applikationslayout"; +"settings_labs_enable_new_client_info_feature" = "Spara klientens namn, version och URL för att lättare känna igen sessioner i sessionshanteraren"; +"settings_labs_enable_new_session_manager" = "My sessionshanterare"; +"room_first_message_placeholder" = "Skicka ditt första meddelande…"; +"password_policy_pwd_in_dict_error" = "Det här lösenordet har hittats i en ordlista, och tillåts inte."; +"password_policy_weak_pwd_error" = "Det här lösenordet är för svagt. Det måste innehålla minst 8 tecken, och minst ett tecken av varje typ: stor bokstav, liten bokstav, siffra och specialtecken."; + +// MARK: Password policy errors +"password_policy_too_short_pwd_error" = "För kort lösenord"; +"authentication_qr_login_failure_retry" = "Pröva igen"; +"authentication_qr_login_failure_request_timed_out" = "Länkningen slutfördes inte inom den krävda tiden."; +"authentication_qr_login_failure_request_denied" = "Förfrågan nekades på en andra enheten."; +"authentication_qr_login_failure_invalid_qr" = "QR-kod är ogiltig."; +"authentication_qr_login_failure_title" = "Länkning misslyckades"; +"authentication_qr_login_loading_signed_in" = "Du är nu inloggad på din andra enhet."; +"authentication_qr_login_loading_waiting_signin" = "Väntar på att enheten loggar in."; +"authentication_qr_login_loading_connecting_device" = "Ansluter till enhet"; +"authentication_qr_login_confirm_alert" = "Vänligen försäkra att du känner till källan till den här koden. Genom att länka enheter så ger du någon full åtkomst till ditt konto."; +"authentication_qr_login_confirm_subtitle" = "Bekräfta att koden nedan matchar den andra enheten:"; +"authentication_qr_login_confirm_title" = "Säker kommunikation etablerad"; +"authentication_qr_login_scan_subtitle" = "Placera QR-koden i rutan nedan"; +"authentication_qr_login_scan_title" = "Skanna QR-kod"; +"authentication_qr_login_display_step2" = "Välj 'Logga in med QR-kod'"; +"authentication_qr_login_display_step1" = "Öppna Element på din andra enhet"; +"authentication_qr_login_display_subtitle" = "Skanna QR-koden nedan med din enhet som är utloggad."; +"authentication_qr_login_display_title" = "Länka en enhet"; +"authentication_qr_login_start_display_qr" = "Visa QR-kod på den här enheten"; +"authentication_qr_login_start_need_alternative" = "Behöver du en alternativ metod?"; +"authentication_qr_login_start_step4" = "Välj 'Visa QR-kod på den här enheten'"; +"authentication_qr_login_start_step3" = "Välj 'Länka en enhet'"; +"authentication_qr_login_start_step2" = "Gå till Inställningar -> Säkerhet & sekretess"; +"authentication_qr_login_start_step1" = "Öppna Element på den andra enheten"; +"authentication_qr_login_start_subtitle" = "Använd kameran på den här enheten för att skanna QR-koden som visas på den andra enheten:"; +"authentication_qr_login_start_title" = "Skanna QR-kod"; +"authentication_choose_password_not_verified_message" = "Kolla din inkorg"; +"authentication_choose_password_not_verified_title" = "E-post inte verifierad"; +"authentication_login_with_qr" = "Logga in med QR-kod"; +"invite_to" = "Bjud in till %@"; From 678129422b51661ca9adb13e1fd53263c4fff3f4 Mon Sep 17 00:00:00 2001 From: Vri Date: Mon, 16 Jan 2023 13:11:34 +0000 Subject: [PATCH 112/160] Translated using Weblate (German) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index ccab1a9ca8..35c0383c1e 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2705,3 +2705,13 @@ "poll_timeline_ended_text" = "Umfrage beendet"; "voice_broadcast_voip_cannot_start_description" = "Du kannst keinen Anruf beginnen, da du im Moment eine Sprachübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen."; "voice_broadcast_voip_cannot_start_title" = "Kann keinen Anruf beginnen"; +"poll_history_no_past_poll_text" = "In diesem Raum gibt es keine abgeschlossenen Umfragen"; +"poll_history_no_active_poll_text" = "In diesem Raum gibt es keine aktiven Umfragen"; +"poll_history_past_segment_title" = "Vergangene Umfragen"; +"poll_history_active_segment_title" = "Aktive Umfragen"; + +// MARK: - Polls history + +"poll_history_title" = "Umfrageverlauf"; +"room_details_polls" = "Umfrageverlauf"; +"accessibility_selected" = "ausgewählt"; From 6a797170b3cdabd2dd74a013f1e3b20d13bea423 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Mon, 16 Jan 2023 12:35:16 +0000 Subject: [PATCH 113/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 63c432c085..7bf2ff0fa6 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2896,3 +2896,13 @@ "poll_timeline_ended_text" = "Опитування завершено"; "voice_broadcast_voip_cannot_start_description" = "Ви не можете розпочати виклик, оскільки зараз відбувається запис трансляції наживо. Завершіть трансляцію, щоб розпочати виклик."; "voice_broadcast_voip_cannot_start_title" = "Неможливо розпочати виклик"; +"poll_history_no_past_poll_text" = "У цій кімнаті немає минулих опитувань"; +"poll_history_no_active_poll_text" = "У цій кімнаті немає активних опитувань"; +"poll_history_past_segment_title" = "Минулі опитування"; +"poll_history_active_segment_title" = "Активні опитування"; + +// MARK: - Polls history + +"poll_history_title" = "Історія опитувань"; +"room_details_polls" = "Історія опитувань"; +"accessibility_selected" = "вибрано"; From 99f9ddd2016659c5c8c52c5b539ea17ac689fc3d Mon Sep 17 00:00:00 2001 From: Linerly Date: Mon, 16 Jan 2023 12:14:00 +0000 Subject: [PATCH 114/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index bbc02ec1ab..f666917c3d 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2898,3 +2898,13 @@ "poll_timeline_ended_text" = "Mengakhiri pemungutan suara"; "voice_broadcast_voip_cannot_start_description" = "Anda tidak dapat memulai sebuah panggilan karena Anda saat ini merekam sebuah siaran langsung. Mohon akhiri siaran langsung Anda untuk memulai sebuah panggilan."; "voice_broadcast_voip_cannot_start_title" = "Tidak dapat memulai sebuah panggilan"; +"poll_history_no_past_poll_text" = "Tidak ada pemungutan suara masa lalu di ruangan ini"; +"poll_history_no_active_poll_text" = "Tidak ada pemungutan suara yang aktifk di ruangan ini"; +"poll_history_past_segment_title" = "Pemungutan suara sebelumnya"; +"poll_history_active_segment_title" = "Pemungutan suara aktif"; + +// MARK: - Polls history + +"poll_history_title" = "Riwayat pemungutan suara"; +"room_details_polls" = "Riwayat pemungutan suara"; +"accessibility_selected" = "dipilih"; From 6204fa5508542c181aeccff9943bb87df9c346ef Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Mon, 16 Jan 2023 14:25:50 +0000 Subject: [PATCH 115/160] Translated using Weblate (Slovak) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index c3c8a3c104..e417691428 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2894,3 +2894,13 @@ "poll_timeline_ended_text" = "Ukončil anketu"; "voice_broadcast_voip_cannot_start_description" = "Nemôžete spustiť hovor, pretože práve nahrávate živé vysielanie. Ukončite živé vysielanie, aby ste mohli začať hovor."; "voice_broadcast_voip_cannot_start_title" = "Nie je možné začať hovor"; +"poll_history_no_past_poll_text" = "V tejto miestnosti nie sú žiadne predchádzajúce ankety"; +"poll_history_no_active_poll_text" = "V tejto miestnosti nie sú žiadne aktívne ankety"; +"poll_history_past_segment_title" = "Predchádzajúce ankety"; +"poll_history_active_segment_title" = "Aktívne ankety"; + +// MARK: - Polls history + +"poll_history_title" = "História ankety"; +"room_details_polls" = "História ankety"; +"accessibility_selected" = "vybrané"; From b1fb4e5f326675de08d0c6afec85d2607b4926f0 Mon Sep 17 00:00:00 2001 From: Vri Date: Mon, 16 Jan 2023 20:26:27 +0000 Subject: [PATCH 116/160] Translated using Weblate (German) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 35c0383c1e..65e18d6392 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2700,7 +2700,7 @@ "notice_voice_broadcast_live" = "Echtzeitübertragung"; "user_other_session_security_recommendation_title" = "Andere Sitzungen"; "voice_message_broadcast_in_progress_title" = "Kann Sprachnachricht nicht beginnen"; -"poll_timeline_decryption_error" = "Aufgrund von Entschlüsselungsfehlern könnten einige Stimmen nicht gezählt werden"; +"poll_timeline_decryption_error" = "Evtl. werden infolge von Entschlüsselungsfehlern einige Stimmen nicht gezählt"; "voice_message_broadcast_in_progress_message" = "Du kannst keine Sprachnachricht beginnen, da du im Moment eine Echtzeitübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen"; "poll_timeline_ended_text" = "Umfrage beendet"; "voice_broadcast_voip_cannot_start_description" = "Du kannst keinen Anruf beginnen, da du im Moment eine Sprachübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen."; From 1816635ee0955d70984f74ef5d6d1dff59f6997b Mon Sep 17 00:00:00 2001 From: Szimszon Date: Mon, 16 Jan 2023 19:14:13 +0000 Subject: [PATCH 117/160] Translated using Weblate (Hungarian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index 4c50ec2961..80dbe5b3c8 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2691,3 +2691,13 @@ "poll_timeline_ended_text" = "Szavazás vége"; "voice_broadcast_voip_cannot_start_description" = "Nem lehet hívást kezdeményezni élő közvetítés felvétele közben. Az élő közvetítés bejezése szükséges a hívás indításához."; "voice_broadcast_voip_cannot_start_title" = "Nem sikerült hívást indítani"; +"poll_history_no_past_poll_text" = "Nincsenek régi szavazások ebben a szobában"; +"poll_history_no_active_poll_text" = "Nincsenek aktív szavazások ebben a szobában"; +"poll_history_past_segment_title" = "Régi szavazások"; +"poll_history_active_segment_title" = "Aktív szavazások"; + +// MARK: - Polls history + +"poll_history_title" = "Szavazás alakulása"; +"room_details_polls" = "Szavazás alakulása"; +"accessibility_selected" = "kiválasztva"; From 4051fdf24795ac0ebfcf9da994c8412f94502102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sveinn=20=C3=AD=20Felli?= Date: Mon, 16 Jan 2023 21:43:49 +0000 Subject: [PATCH 118/160] Translated using Weblate (Icelandic) Currently translated at 81.2% (1918 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/is/ --- Riot/Assets/is.lproj/Vector.strings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/Assets/is.lproj/Vector.strings b/Riot/Assets/is.lproj/Vector.strings index aba02e2d62..b569fd2813 100644 --- a/Riot/Assets/is.lproj/Vector.strings +++ b/Riot/Assets/is.lproj/Vector.strings @@ -1283,7 +1283,7 @@ "settings_add_3pid_invalid_password_message" = "Ógild auðkenni"; "settings_add_3pid_password_title_msidsn" = "Bæta við símanúmeri"; "settings_add_3pid_password_title_email" = "Bæta við tölvupóstfangi"; -"settings_labs_enable_threads" = "Skilaboð í spjallþráðum"; +"settings_labs_enable_threads" = "Spjallþræðir skilaboða"; "settings_labs_enabled_polls" = "Kannanir"; "settings_integrations_allow_button" = "Sýsla með samþættingar"; "settings_new_keyword" = "Bæta við nýju stikkorði"; @@ -2317,7 +2317,7 @@ "device_name_mobile" = "%@ fyrir farsíma"; "device_name_web" = "%@ á vefnum"; "device_name_desktop" = "%@ fyrir einkatölvur"; -"user_session_item_details" = "%@ · Síðasta virkni %@"; +"user_session_item_details" = "%1$@ · %2$@"; "location_sharing_live_loading" = "Hleð inn rauntímastaðsetningu..."; "location_sharing_live_list_item_time_left" = "%@ fór"; "location_sharing_map_credits_title" = "© Höfundarréttur"; From 62ba883af652a76ee121532ef7d56a1954831b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Tue, 17 Jan 2023 06:56:18 +0000 Subject: [PATCH 119/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2361 of 2361 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 80fee8f729..abe430b8f1 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2643,3 +2643,13 @@ "poll_timeline_ended_text" = "Küsitlus on lõppenud"; "voice_broadcast_voip_cannot_start_description" = "Kuna sa hetkel salvestad ringhäälingukõnet, siis tavakõne algatamine ei õnnestu. Kõne alustamiseks palun lõpeta ringhäälingukõne."; "voice_broadcast_voip_cannot_start_title" = "Kõne algatamine ei õnnestu"; +"poll_history_no_past_poll_text" = "Selles jututoas pole varasemaid küsitlusi"; +"poll_history_no_active_poll_text" = "Selles jututoas pole käimasolevaid küsitlusi"; +"poll_history_past_segment_title" = "Varasemad küsitlused"; +"poll_history_active_segment_title" = "Käimasolevad küsitlused"; + +// MARK: - Polls history + +"poll_history_title" = "Küsitluste ajalugu"; +"room_details_polls" = "Küsitluste ajalugu"; +"accessibility_selected" = "valitud"; From 60fef575031fd69fcd9cef03168f43373a351f6c Mon Sep 17 00:00:00 2001 From: Vri Date: Tue, 17 Jan 2023 10:00:51 +0000 Subject: [PATCH 120/160] Translated using Weblate (German) Currently translated at 100.0% (2362 of 2362 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 65e18d6392..3e96b83e0b 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2715,3 +2715,4 @@ "poll_history_title" = "Umfrageverlauf"; "room_details_polls" = "Umfrageverlauf"; "accessibility_selected" = "ausgewählt"; +"voice_broadcast_playback_lock_screen_placeholder" = "Sprachübertragung"; From d13f02da0749fe8606d4b7230c639e8a574aaba4 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Tue, 17 Jan 2023 10:40:51 +0000 Subject: [PATCH 121/160] Translated using Weblate (Albanian) Currently translated at 99.5% (2351 of 2362 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sq/ --- Riot/Assets/sq.lproj/Vector.strings | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Riot/Assets/sq.lproj/Vector.strings b/Riot/Assets/sq.lproj/Vector.strings index f484f7275b..b2a297d078 100644 --- a/Riot/Assets/sq.lproj/Vector.strings +++ b/Riot/Assets/sq.lproj/Vector.strings @@ -2676,3 +2676,14 @@ "notice_voice_broadcast_ended" = "%@ përfundoi një transmetim zanor."; "notice_voice_broadcast_live" = "Transmetim i drejtëpërdrejtë"; "user_other_session_security_recommendation_title" = "Sesione të tjerë"; +"poll_timeline_ended_text" = "Përfundoi pyetësori"; +"poll_timeline_decryption_error" = "Për shkak gabimesh shfshehtëzimi, mund të mos jenë numëruar disa vota"; +"poll_history_no_past_poll_text" = "Në këtë dhomë s’ka pyetësorë të dikurshëm"; +"poll_history_no_active_poll_text" = "Në këtë dhomë s’ka pyetësorë aktivë"; +"poll_history_past_segment_title" = "Pyetësorë të dikurshëm"; +"poll_history_active_segment_title" = "Pyetësorë aktivë"; +"voice_broadcast_playback_lock_screen_placeholder" = "Transmetim zanor"; +"voice_broadcast_voip_cannot_start_description" = "S’mund të niset thirrje, ngaqë aktualisht po regjistroni një transmetim të drejtpërdrejtë. Ju lutemi, përfundoni transmetimin e drejtpërdrejtë, që të mund të nisni një thirrje."; +"voice_broadcast_voip_cannot_start_title" = "S’niset dot një thirrje"; +"voice_message_broadcast_in_progress_message" = "S’mund të niset mesazh zanor, ngaqë aktualisht po regjistroni një transmetim të drejtpërdrejtë. Ju lutemi, përfundoni transmetimin e drejtpërdrejtë, që të mund të nisni regjistrimin e një mesazhi zanor"; +"voice_message_broadcast_in_progress_title" = "S’niset dot mesazh zanor"; From 5d71801c2006a0573058f3395d6d67f26ec8dd59 Mon Sep 17 00:00:00 2001 From: random Date: Tue, 17 Jan 2023 09:58:16 +0000 Subject: [PATCH 122/160] Translated using Weblate (Italian) Currently translated at 100.0% (2362 of 2362 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ --- Riot/Assets/it.lproj/Vector.strings | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Riot/Assets/it.lproj/Vector.strings b/Riot/Assets/it.lproj/Vector.strings index 4a649f1c46..b5e7ba84fe 100644 --- a/Riot/Assets/it.lproj/Vector.strings +++ b/Riot/Assets/it.lproj/Vector.strings @@ -2671,3 +2671,14 @@ "voice_broadcast_voip_cannot_start_title" = "Impossibile avviare una chiamata"; "voice_message_broadcast_in_progress_title" = "Impossibile iniziare il messaggio vocale"; "voice_message_broadcast_in_progress_message" = "Non puoi iniziare un messaggio vocale perché stai registrando una trasmissione in diretta. Termina la trasmissione per potere iniziare un messaggio vocale"; +"poll_history_no_past_poll_text" = "In questa stanza non ci sono sondaggi passati"; +"poll_history_no_active_poll_text" = "In questa stanza non ci sono sondaggi attivi"; +"poll_history_past_segment_title" = "Sondaggi passati"; +"poll_history_active_segment_title" = "Sondaggi attivi"; + +// MARK: - Polls history + +"poll_history_title" = "Cronologia sondaggi"; +"voice_broadcast_playback_lock_screen_placeholder" = "Trasmissione vocale"; +"room_details_polls" = "Cronologia sondaggi"; +"accessibility_selected" = "selezionato"; From 7ceb5f908a957a246477ae1bd1eb944ab05e8127 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Tue, 17 Jan 2023 14:16:47 +0000 Subject: [PATCH 123/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2362 of 2362 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 7bf2ff0fa6..92f0606a2e 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2906,3 +2906,4 @@ "poll_history_title" = "Історія опитувань"; "room_details_polls" = "Історія опитувань"; "accessibility_selected" = "вибрано"; +"voice_broadcast_playback_lock_screen_placeholder" = "Голосові трансляції"; From 16d32a88744795b15bfd521e444911b2d6223459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Tue, 17 Jan 2023 12:46:50 +0000 Subject: [PATCH 124/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2362 of 2362 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index abe430b8f1..46123bd4ec 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2653,3 +2653,4 @@ "poll_history_title" = "Küsitluste ajalugu"; "room_details_polls" = "Küsitluste ajalugu"; "accessibility_selected" = "valitud"; +"voice_broadcast_playback_lock_screen_placeholder" = "Ringhäälingukõne"; From 8424b14c847855b8495059d4958196446b881a21 Mon Sep 17 00:00:00 2001 From: Linerly Date: Tue, 17 Jan 2023 10:21:33 +0000 Subject: [PATCH 125/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2362 of 2362 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index f666917c3d..375f5f3ebf 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2908,3 +2908,4 @@ "poll_history_title" = "Riwayat pemungutan suara"; "room_details_polls" = "Riwayat pemungutan suara"; "accessibility_selected" = "dipilih"; +"voice_broadcast_playback_lock_screen_placeholder" = "Siaran suara"; From 45e7037fd09b78a1189e5a16ef5ebff410b70e9b Mon Sep 17 00:00:00 2001 From: Vri Date: Tue, 17 Jan 2023 17:46:07 +0000 Subject: [PATCH 126/160] Translated using Weblate (German) Currently translated at 100.0% (2364 of 2364 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 3e96b83e0b..ee49f37f1f 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2716,3 +2716,5 @@ "room_details_polls" = "Umfrageverlauf"; "accessibility_selected" = "ausgewählt"; "voice_broadcast_playback_lock_screen_placeholder" = "Sprachübertragung"; +"voice_broadcast_connection_error_message" = "Leider ist es aktuell nicht möglich, eine Aufnahme zu beginnen. Bitte versuche es später erneut."; +"voice_broadcast_connection_error_title" = "Verbindungsfehler"; From 463f7ae56c5739432f08e5bc4e58bfa7df421789 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Tue, 17 Jan 2023 20:25:53 +0000 Subject: [PATCH 127/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2364 of 2364 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 92f0606a2e..ee38e4637a 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2907,3 +2907,5 @@ "room_details_polls" = "Історія опитувань"; "accessibility_selected" = "вибрано"; "voice_broadcast_playback_lock_screen_placeholder" = "Голосові трансляції"; +"voice_broadcast_connection_error_message" = "На жаль, ми не можемо розпочати запис прямо зараз. Повторіть спробу пізніше."; +"voice_broadcast_connection_error_title" = "Помилка з'єднання"; From ad1186068298f5dae2257e92821def10f6a20b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Tue, 17 Jan 2023 15:34:11 +0000 Subject: [PATCH 128/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2364 of 2364 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 46123bd4ec..c581b99fa7 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2654,3 +2654,5 @@ "room_details_polls" = "Küsitluste ajalugu"; "accessibility_selected" = "valitud"; "voice_broadcast_playback_lock_screen_placeholder" = "Ringhäälingukõne"; +"voice_broadcast_connection_error_message" = "Kahjuks me ei saa hetkel salvestamist alustada. Palun proovi hiljem uuesti."; +"voice_broadcast_connection_error_title" = "Ühenduse viga"; From 78c92fcfce971dac3bd49542ec1d859309c3ef72 Mon Sep 17 00:00:00 2001 From: Demo337 Date: Tue, 17 Jan 2023 16:58:33 +0000 Subject: [PATCH 129/160] Translated using Weblate (Arabic) Currently translated at 37.8% (895 of 2364 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ar/ --- Riot/Assets/ar.lproj/Vector.strings | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index a9a7b2cb62..7810fc3ccf 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -455,7 +455,7 @@ "sign_up" = "الاِشتِراك"; "dismiss" = "إبعَاد"; "discard" = "اِستِبعاد"; -"abort" = "إِجهَاض"; +"abort" = "إنهاء"; "yes" = "نَعَم"; // Action @@ -1078,3 +1078,8 @@ /* The placeholder will show the email address that was entered. */ "authentication_verify_email_waiting_message" = "اتبع التعليمات المرسلة إلى %@"; "invite_to" = "الدعوة إلى %@"; +"password_policy_pwd_in_dict_error" = "تم العثور على كلمة المرور هذه في القاموس لدينا، وهي كلمة مرور غير مسموح في استخدامها."; + +// Others +"or" = "أو"; +"accessibility_selected" = "تم تحديده"; From b2ff9bef8ee450788640e072443d5179e068c98e Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Tue, 17 Jan 2023 17:16:29 +0000 Subject: [PATCH 130/160] Translated using Weblate (Slovak) Currently translated at 100.0% (2364 of 2364 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index e417691428..269e57f0af 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2904,3 +2904,6 @@ "poll_history_title" = "História ankety"; "room_details_polls" = "História ankety"; "accessibility_selected" = "vybrané"; +"voice_broadcast_connection_error_message" = "Bohužiaľ teraz nemôžeme spustiť nahrávanie. Skúste to prosím neskôr."; +"voice_broadcast_connection_error_title" = "Chyba pripojenia"; +"voice_broadcast_playback_lock_screen_placeholder" = "Hlasové vysielanie"; From 2ee7334658e3300e8a5336267912f55c6db42596 Mon Sep 17 00:00:00 2001 From: Vri Date: Wed, 18 Jan 2023 10:13:33 +0000 Subject: [PATCH 131/160] Translated using Weblate (German) Currently translated at 100.0% (2368 of 2368 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index ee49f37f1f..92fb0aa462 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2718,3 +2718,7 @@ "voice_broadcast_playback_lock_screen_placeholder" = "Sprachübertragung"; "voice_broadcast_connection_error_message" = "Leider ist es aktuell nicht möglich, eine Aufnahme zu beginnen. Bitte versuche es später erneut."; "voice_broadcast_connection_error_title" = "Verbindungsfehler"; +"wysiwyg_composer_format_action_code_block" = "Quelltextblock umschalten"; +"wysiwyg_composer_format_action_quote" = "Zitat umschalten"; +"wysiwyg_composer_format_action_ordered_list" = "Nummerierte Liste umschalten"; +"wysiwyg_composer_format_action_unordered_list" = "Unsortierte Liste umschalten"; From cb5a75e65b8d50379854b4685e8c774128e2773d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Wed, 18 Jan 2023 09:53:51 +0000 Subject: [PATCH 132/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2368 of 2368 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index c581b99fa7..9e8c253291 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2656,3 +2656,7 @@ "voice_broadcast_playback_lock_screen_placeholder" = "Ringhäälingukõne"; "voice_broadcast_connection_error_message" = "Kahjuks me ei saa hetkel salvestamist alustada. Palun proovi hiljem uuesti."; "voice_broadcast_connection_error_title" = "Ühenduse viga"; +"wysiwyg_composer_format_action_quote" = "Lülita tsiteerimine sisse/välja"; +"wysiwyg_composer_format_action_code_block" = "Lülita koodiblokk sisse/välja"; +"wysiwyg_composer_format_action_ordered_list" = "Lülita nummerdatud loend sisse/välja"; +"wysiwyg_composer_format_action_unordered_list" = "Lülita täpploend sisse/välja"; From d279ffe3626e88af6bfb626eb6304891fd6d12a1 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Wed, 18 Jan 2023 13:01:50 +0000 Subject: [PATCH 133/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2368 of 2368 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index ee38e4637a..b1ba624690 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2909,3 +2909,7 @@ "voice_broadcast_playback_lock_screen_placeholder" = "Голосові трансляції"; "voice_broadcast_connection_error_message" = "На жаль, ми не можемо розпочати запис прямо зараз. Повторіть спробу пізніше."; "voice_broadcast_connection_error_title" = "Помилка з'єднання"; +"wysiwyg_composer_format_action_quote" = "Перемкнути цитування"; +"wysiwyg_composer_format_action_code_block" = "Перемкнути блок коду"; +"wysiwyg_composer_format_action_ordered_list" = "Перемкнути на нумерований список"; +"wysiwyg_composer_format_action_unordered_list" = "Перемкнути на маркований список"; From 4f94e91b0ac0bcfb40c211fe81efba67498c76c3 Mon Sep 17 00:00:00 2001 From: Linerly Date: Wed, 18 Jan 2023 13:42:47 +0000 Subject: [PATCH 134/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2368 of 2368 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index 375f5f3ebf..0fcb766eb0 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2909,3 +2909,9 @@ "room_details_polls" = "Riwayat pemungutan suara"; "accessibility_selected" = "dipilih"; "voice_broadcast_playback_lock_screen_placeholder" = "Siaran suara"; +"wysiwyg_composer_format_action_quote" = "Saklar kutipan"; +"wysiwyg_composer_format_action_code_block" = "Saklar blok kode"; +"wysiwyg_composer_format_action_ordered_list" = "Saklar daftar bernomor"; +"wysiwyg_composer_format_action_unordered_list" = "Saklar daftar bulat"; +"voice_broadcast_connection_error_message" = "Sayangnya kami tidak dapat memulai sebuah rekaman saat ini. Silakan coba lagi nanti."; +"voice_broadcast_connection_error_title" = "Kesalahan koneksi"; From b07fa3c2e8ad52a993fddff6979cfc95f3027799 Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Wed, 18 Jan 2023 11:59:19 +0000 Subject: [PATCH 135/160] Translated using Weblate (Slovak) Currently translated at 100.0% (2368 of 2368 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index 269e57f0af..0775c77ad4 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2907,3 +2907,7 @@ "voice_broadcast_connection_error_message" = "Bohužiaľ teraz nemôžeme spustiť nahrávanie. Skúste to prosím neskôr."; "voice_broadcast_connection_error_title" = "Chyba pripojenia"; "voice_broadcast_playback_lock_screen_placeholder" = "Hlasové vysielanie"; +"wysiwyg_composer_format_action_quote" = "Prepínanie citácie"; +"wysiwyg_composer_format_action_code_block" = "Prepnutie bloku kódu"; +"wysiwyg_composer_format_action_ordered_list" = "Prepínanie číslovaného zoznamu"; +"wysiwyg_composer_format_action_unordered_list" = "Prepnúť zoznam s odrážkami"; From 1690802a63f94f43793d79ed01584805cce94b37 Mon Sep 17 00:00:00 2001 From: Vri Date: Wed, 18 Jan 2023 17:48:34 +0000 Subject: [PATCH 136/160] Translated using Weblate (German) Currently translated at 100.0% (2369 of 2369 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 92fb0aa462..c162e0484a 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2722,3 +2722,4 @@ "wysiwyg_composer_format_action_quote" = "Zitat umschalten"; "wysiwyg_composer_format_action_ordered_list" = "Nummerierte Liste umschalten"; "wysiwyg_composer_format_action_unordered_list" = "Unsortierte Liste umschalten"; +"voice_broadcast_recorder_connection_error" = "Verbindungsfehler – Aufzeichnung pausiert"; From a7b4427738e94945e95bdc64cb9ec0bf93d530e7 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Wed, 18 Jan 2023 18:34:46 +0000 Subject: [PATCH 137/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2369 of 2369 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index b1ba624690..02aaeed86a 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2913,3 +2913,4 @@ "wysiwyg_composer_format_action_code_block" = "Перемкнути блок коду"; "wysiwyg_composer_format_action_ordered_list" = "Перемкнути на нумерований список"; "wysiwyg_composer_format_action_unordered_list" = "Перемкнути на маркований список"; +"voice_broadcast_recorder_connection_error" = "Помилка з'єднання - Запис призупинено"; From 5c25b11be2365b39b4bc2c3563c8a2f534e26bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Wed, 18 Jan 2023 17:34:31 +0000 Subject: [PATCH 138/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2369 of 2369 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 9e8c253291..2db1f21d93 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2660,3 +2660,4 @@ "wysiwyg_composer_format_action_code_block" = "Lülita koodiblokk sisse/välja"; "wysiwyg_composer_format_action_ordered_list" = "Lülita nummerdatud loend sisse/välja"; "wysiwyg_composer_format_action_unordered_list" = "Lülita täpploend sisse/välja"; +"voice_broadcast_recorder_connection_error" = "Viga võrguühenduses - salvestamine on peatatud"; From a6f7e178bda5495792845a7a8c7caa82bde1a8bf Mon Sep 17 00:00:00 2001 From: Linerly Date: Wed, 18 Jan 2023 16:32:40 +0000 Subject: [PATCH 139/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2369 of 2369 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index 0fcb766eb0..8a0e440982 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2915,3 +2915,4 @@ "wysiwyg_composer_format_action_unordered_list" = "Saklar daftar bulat"; "voice_broadcast_connection_error_message" = "Sayangnya kami tidak dapat memulai sebuah rekaman saat ini. Silakan coba lagi nanti."; "voice_broadcast_connection_error_title" = "Kesalahan koneksi"; +"voice_broadcast_recorder_connection_error" = "Kesalahan koneksi - Perekaman dijeda"; From 9e64998b2f8744853c6d696d59c3cf7e2974905a Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Wed, 18 Jan 2023 18:39:55 +0000 Subject: [PATCH 140/160] Translated using Weblate (Slovak) Currently translated at 100.0% (2369 of 2369 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index 0775c77ad4..65a907e73c 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2911,3 +2911,4 @@ "wysiwyg_composer_format_action_code_block" = "Prepnutie bloku kódu"; "wysiwyg_composer_format_action_ordered_list" = "Prepínanie číslovaného zoznamu"; "wysiwyg_composer_format_action_unordered_list" = "Prepnúť zoznam s odrážkami"; +"voice_broadcast_recorder_connection_error" = "Chyba pripojenia - nahrávanie pozastavené"; From 370c214facf4cd5919306365793351d21b0b5e9d Mon Sep 17 00:00:00 2001 From: Vri Date: Thu, 19 Jan 2023 12:54:02 +0000 Subject: [PATCH 141/160] Translated using Weblate (German) Currently translated at 100.0% (2370 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index c162e0484a..a5b6629f29 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2723,3 +2723,4 @@ "wysiwyg_composer_format_action_ordered_list" = "Nummerierte Liste umschalten"; "wysiwyg_composer_format_action_unordered_list" = "Unsortierte Liste umschalten"; "voice_broadcast_recorder_connection_error" = "Verbindungsfehler – Aufzeichnung pausiert"; +"poll_timeline_reply_ended_poll" = "Beendete Umfrage"; From 29e43452e694e6fff809912ad3045f243a89464d Mon Sep 17 00:00:00 2001 From: xrh0905 <1014930533@qq.com> Date: Fri, 20 Jan 2023 00:29:57 +0000 Subject: [PATCH 142/160] Translated using Weblate (Chinese (Simplified)) Currently translated at 81.9% (1943 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/zh_Hans/ --- Riot/Assets/zh_Hans.lproj/Vector.strings | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/zh_Hans.lproj/Vector.strings b/Riot/Assets/zh_Hans.lproj/Vector.strings index bcd7213566..7294bf84ed 100644 --- a/Riot/Assets/zh_Hans.lproj/Vector.strings +++ b/Riot/Assets/zh_Hans.lproj/Vector.strings @@ -196,7 +196,7 @@ "room_event_action_copy" = "复制"; "room_event_action_quote" = "引用"; "room_event_action_redact" = "移除"; -"room_event_action_more" = "移动"; +"room_event_action_more" = "更多"; "room_event_action_share" = "分享"; "room_event_action_permalink" = "复制消息的链接"; "room_event_action_view_source" = "查看源数据"; @@ -2272,3 +2272,6 @@ "authentication_qr_login_display_step2" = "选择“以二维码登入”"; "authentication_qr_login_display_step1" = "在您的其它设备中打开Element"; "onboarding_splash_page_4_title_no_pun" = "为您的团队发送消息。"; +"user_session_learn_more" = "了解更多"; +"manage_session_name_info_link" = "了解更多"; +"threads_beta_information_link" = "了解更多"; From 17ffbdccba638725bcd65de66e2c91bd867181e6 Mon Sep 17 00:00:00 2001 From: Suguru Hirahara Date: Sat, 21 Jan 2023 18:15:54 +0000 Subject: [PATCH 143/160] Translated using Weblate (Japanese) Currently translated at 64.8% (1536 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ja/ --- Riot/Assets/ja.lproj/Vector.strings | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Riot/Assets/ja.lproj/Vector.strings b/Riot/Assets/ja.lproj/Vector.strings index 88f0760eee..2a82d520cc 100644 --- a/Riot/Assets/ja.lproj/Vector.strings +++ b/Riot/Assets/ja.lproj/Vector.strings @@ -1763,13 +1763,13 @@ "home_context_menu_favourite" = "お気に入り"; "all_chats_user_menu_settings" = "ユーザー設定"; "all_chats_edit_layout_show_filters" = "フィルターを表示"; -"all_chats_edit_layout_show_recents" = "最近使用したものを表示"; +"all_chats_edit_layout_show_recents" = "最近の履歴を表示"; "all_chats_edit_layout_alphabetical_order" = "アルファベット順で並び替え"; "all_chats_edit_layout_activity_order" = "アクティビティで並び替え"; "space_selector_create_space" = "スペースを作成"; -"space_selector_empty_view_information" = "スペースは、ルームや連絡先をグループ化する方法です。以下からスペースを作成できます。"; +"space_selector_empty_view_information" = "スペースは、ルームと連絡先をまとめる方法です。はじめに、スペースを作成しましょう。"; "all_chats_all_filter" = "全て"; -"all_chats_edit_layout_recents" = "最近"; +"all_chats_edit_layout_recents" = "履歴"; "all_chats_edit_layout_unreads" = "未読"; "all_chats_section_title" = "チャット"; @@ -1799,3 +1799,5 @@ "service_terms_modal_information_title_identity_server" = "IDサーバー"; "location_sharing_invalid_power_level_message" = "位置情報(ライブ)の共有には適切な権限が必要です。"; "location_sharing_live_error" = "位置情報(ライブ)のエラー"; +"all_chats_onboarding_page_title3" = "フィードバックを送信"; +"all_chats_edit_layout" = "レイアウトの設定"; From 5ed3689a0d77a57377d418c0502b4c87743d502d Mon Sep 17 00:00:00 2001 From: Szimszon Date: Thu, 19 Jan 2023 12:14:57 +0000 Subject: [PATCH 144/160] Translated using Weblate (Hungarian) Currently translated at 100.0% (2370 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index 80dbe5b3c8..6dd053e547 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2701,3 +2701,12 @@ "poll_history_title" = "Szavazás alakulása"; "room_details_polls" = "Szavazás alakulása"; "accessibility_selected" = "kiválasztva"; +"wysiwyg_composer_format_action_quote" = "Idézet be/ki"; +"wysiwyg_composer_format_action_code_block" = "Kód blokk be/ki"; +"wysiwyg_composer_format_action_ordered_list" = "Számozott lista ki-,bekapcsolása"; +"wysiwyg_composer_format_action_unordered_list" = "Lista ki-,bekapcsolása"; +"poll_timeline_reply_ended_poll" = "Lezárt szavazások"; +"voice_broadcast_recorder_connection_error" = "Kapcsolódási hiba – Felvétel szüneteltetve"; +"voice_broadcast_connection_error_message" = "Sajnos most nem lehet elindítani a felvételt. Próbálja meg később."; +"voice_broadcast_connection_error_title" = "Kapcsolat hiba"; +"voice_broadcast_playback_lock_screen_placeholder" = "Hang közvetítés"; From 55b3a4ba7e6480bad30375f34007a0c2e4f52657 Mon Sep 17 00:00:00 2001 From: random Date: Sat, 21 Jan 2023 08:52:33 +0000 Subject: [PATCH 145/160] Translated using Weblate (Italian) Currently translated at 100.0% (2370 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ --- Riot/Assets/it.lproj/Vector.strings | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Riot/Assets/it.lproj/Vector.strings b/Riot/Assets/it.lproj/Vector.strings index b5e7ba84fe..8dbc7f07a3 100644 --- a/Riot/Assets/it.lproj/Vector.strings +++ b/Riot/Assets/it.lproj/Vector.strings @@ -2682,3 +2682,11 @@ "voice_broadcast_playback_lock_screen_placeholder" = "Trasmissione vocale"; "room_details_polls" = "Cronologia sondaggi"; "accessibility_selected" = "selezionato"; +"wysiwyg_composer_format_action_quote" = "Attiva/disattiva citazione"; +"wysiwyg_composer_format_action_code_block" = "Attiva/disattiva blocco di codice"; +"wysiwyg_composer_format_action_ordered_list" = "Attiva/disattiva elenco numerato"; +"wysiwyg_composer_format_action_unordered_list" = "Attiva/disattiva elenco puntato"; +"poll_timeline_reply_ended_poll" = "Sondaggio terminato"; +"voice_broadcast_recorder_connection_error" = "Errore di connessione - Registrazione in pausa"; +"voice_broadcast_connection_error_message" = "Sfortunatamente non riusciamo ad iniziare una registrazione al momento. Riprova più tardi."; +"voice_broadcast_connection_error_title" = "Errore di connessione"; From db6e12c9e8f1e85ecae9754decf4e7c1b78d42aa Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Thu, 19 Jan 2023 12:05:21 +0000 Subject: [PATCH 146/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2370 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 02aaeed86a..4840931209 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2914,3 +2914,4 @@ "wysiwyg_composer_format_action_ordered_list" = "Перемкнути на нумерований список"; "wysiwyg_composer_format_action_unordered_list" = "Перемкнути на маркований список"; "voice_broadcast_recorder_connection_error" = "Помилка з'єднання - Запис призупинено"; +"poll_timeline_reply_ended_poll" = "Завершене опитування"; From 3c923d650e5f0a6fcda2f1f958a0fe1f080b5561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Thu, 19 Jan 2023 11:05:30 +0000 Subject: [PATCH 147/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2370 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 2db1f21d93..063de0b207 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2661,3 +2661,4 @@ "wysiwyg_composer_format_action_ordered_list" = "Lülita nummerdatud loend sisse/välja"; "wysiwyg_composer_format_action_unordered_list" = "Lülita täpploend sisse/välja"; "voice_broadcast_recorder_connection_error" = "Viga võrguühenduses - salvestamine on peatatud"; +"poll_timeline_reply_ended_poll" = "Lõppenud küsitlus"; From b00c4472689b4973b933fb8cf4fb54ddd44192d8 Mon Sep 17 00:00:00 2001 From: Linerly Date: Thu, 19 Jan 2023 09:51:08 +0000 Subject: [PATCH 148/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2370 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index 8a0e440982..efb28c6d7e 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2916,3 +2916,4 @@ "voice_broadcast_connection_error_message" = "Sayangnya kami tidak dapat memulai sebuah rekaman saat ini. Silakan coba lagi nanti."; "voice_broadcast_connection_error_title" = "Kesalahan koneksi"; "voice_broadcast_recorder_connection_error" = "Kesalahan koneksi - Perekaman dijeda"; +"poll_timeline_reply_ended_poll" = "Pemungutan suara berakhir"; From 70ec52bf80512c1b6ba8df71159ee7ffd33c83e6 Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Fri, 20 Jan 2023 00:30:12 +0000 Subject: [PATCH 149/160] Translated using Weblate (Slovak) Currently translated at 100.0% (2370 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index 65a907e73c..d34e26d648 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2912,3 +2912,4 @@ "wysiwyg_composer_format_action_ordered_list" = "Prepínanie číslovaného zoznamu"; "wysiwyg_composer_format_action_unordered_list" = "Prepnúť zoznam s odrážkami"; "voice_broadcast_recorder_connection_error" = "Chyba pripojenia - nahrávanie pozastavené"; +"poll_timeline_reply_ended_poll" = "Ukončená anketa"; From 69e9df66d6143b5e28d85d551ef0419bb906c811 Mon Sep 17 00:00:00 2001 From: phardyle Date: Mon, 23 Jan 2023 04:45:31 +0000 Subject: [PATCH 150/160] Translated using Weblate (Chinese (Simplified)) Currently translated at 81.9% (1943 of 2370 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/zh_Hans/ --- Riot/Assets/zh_Hans.lproj/Vector.strings | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Riot/Assets/zh_Hans.lproj/Vector.strings b/Riot/Assets/zh_Hans.lproj/Vector.strings index 7294bf84ed..f7fd8166c9 100644 --- a/Riot/Assets/zh_Hans.lproj/Vector.strings +++ b/Riot/Assets/zh_Hans.lproj/Vector.strings @@ -2232,19 +2232,19 @@ "onboarding_use_case_message" = "我们将帮助你连接"; "invite_to" = "邀请到%@"; "threads_empty_title" = "保持讨论的有条理性"; -"threads_action_my_threads" = "我的线程"; -"threads_action_all_threads" = "所有线程"; -"threads_title" = "线程"; -"thread_copy_link_to_thread" = "将链接复制到线程"; +"threads_action_my_threads" = "我的消息列"; +"threads_action_all_threads" = "所有消息列"; +"threads_title" = "消息列"; +"thread_copy_link_to_thread" = "将链接复制到消息列"; // MARK: Threads -"room_thread_title" = "线程"; +"room_thread_title" = "消息列"; "room_accessibility_record_voice_message_hint" = "双击并保持录音。"; "room_accessibility_record_voice_message" = "录制语音消息"; "room_accessibility_thread_more" = "更多"; -"room_accessibility_threads" = "线程"; -"room_event_copy_link_info" = "链接复制到剪贴板。"; -"room_event_action_reply_in_thread" = "线程"; +"room_accessibility_threads" = "消息列"; +"room_event_copy_link_info" = "链接已复制到剪贴板。"; +"room_event_action_reply_in_thread" = "消息列"; "room_event_action_view_in_room" = "在房间浏览"; "room_first_message_placeholder" = "发送您的第一条消息……"; "room_participants_invite_prompt_to_msg" = "您确定要邀请%@ 到 %@吗?"; From 88b1761f87d248460ab89c49e63f005d4fd636b6 Mon Sep 17 00:00:00 2001 From: Vri Date: Mon, 23 Jan 2023 11:21:15 +0000 Subject: [PATCH 151/160] Translated using Weblate (German) Currently translated at 100.0% (2374 of 2374 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index a5b6629f29..bb52fc5ea0 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -2724,3 +2724,10 @@ "wysiwyg_composer_format_action_unordered_list" = "Unsortierte Liste umschalten"; "voice_broadcast_recorder_connection_error" = "Verbindungsfehler – Aufzeichnung pausiert"; "poll_timeline_reply_ended_poll" = "Beendete Umfrage"; + +// MARK: - Launch loading + +"launch_loading_migrating_data" = "Migriere Daten\n%@ %%"; +"settings_labs_disable_crypto_sdk" = "Krypto-SDK ist aktiviert. Zum Deaktivieren, bitte die App neu installieren"; +"settings_labs_confirm_crypto_sdk" = "Dies kann nicht rückgängig gemacht werden"; +"settings_labs_enable_crypto_sdk" = "Rust-basiertes Krypto-SDK aktivieren"; From 8db34521e09b87c599532dcf69ace07da245ec7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sveinn=20=C3=AD=20Felli?= Date: Mon, 23 Jan 2023 10:16:05 +0000 Subject: [PATCH 152/160] Translated using Weblate (Icelandic) Currently translated at 84.7% (2013 of 2374 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/is/ --- Riot/Assets/is.lproj/Vector.strings | 116 ++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/Riot/Assets/is.lproj/Vector.strings b/Riot/Assets/is.lproj/Vector.strings index b569fd2813..10722ec1b8 100644 --- a/Riot/Assets/is.lproj/Vector.strings +++ b/Riot/Assets/is.lproj/Vector.strings @@ -2368,3 +2368,119 @@ // MARK: Authentication "authentication_registration_title" = "Búðu til aðganginn þinn"; +"notice_voice_broadcast_ended_by_you" = "Þú endaðir talútsendingu."; +"notice_voice_broadcast_ended" = "%@ endaði talútsendingu."; +"notice_voice_broadcast_live" = "Bein útsending"; +"deselect_all" = "Afvelja allt"; +"wysiwyg_composer_link_action_edit_title" = "Breyta tengli"; +"wysiwyg_composer_link_action_create_title" = "Búa til tengil"; +"wysiwyg_composer_link_action_link" = "Tengill"; + + + +// Links +"wysiwyg_composer_link_action_text" = "Texti"; +"wysiwyg_composer_start_action_voice_broadcast" = "Útvörpun tals"; +"wysiwyg_composer_start_action_text_formatting" = "Sníðing texta"; +"wysiwyg_composer_start_action_camera" = "Myndavél"; +"wysiwyg_composer_start_action_location" = "Staðsetning"; +"wysiwyg_composer_start_action_polls" = "Kannanir"; +"wysiwyg_composer_start_action_attachments" = "Viðhengi"; +"wysiwyg_composer_start_action_stickers" = "Límmerki"; + + +// MARK: - WYSIWYG Composer + +// Send Media Actions +"wysiwyg_composer_start_action_media_picker" = "Ljósmyndasafn"; +"user_session_overview_session_details_button_title" = "Nánar um setuna"; +"user_session_overview_session_title" = "Seta"; +"user_session_overview_current_session_title" = "Núverandi seta"; +"user_session_details_application_url" = "Slóð (URL)"; +"user_session_details_application_version" = "Útgáfa"; +"user_session_details_application_name" = "Heiti"; +"user_session_details_device_os" = "Stýrikerfi"; +"user_session_details_device_browser" = "Vafri"; +"user_session_details_device_model" = "Gerð"; +"user_session_details_device_ip_location" = "Staðsetning IP-vistfangs"; +"user_session_details_device_ip_address" = "IP-vistfang"; +"user_session_details_last_activity" = "Síðasta virkni"; +"user_session_details_session_id" = "Auðkenni setu"; +"user_session_details_session_name" = "Nafn á setu"; +"user_session_details_device_section_header" = "Tæki"; +"user_session_details_application_section_header" = "Forrit"; +"user_session_details_session_section_header" = "Seta"; +"user_session_details_title" = "Nánar um setuna"; +"device_type_name_unknown" = "Óþekkt"; +"device_type_name_mobile" = "Farsími"; +"device_type_name_web" = "Vefur"; +"device_type_name_desktop" = "Borðtölva"; +"user_other_session_selected_count" = "%@ valið"; +"user_other_session_clear_filter" = "Hreinsa síu"; +"user_other_session_no_unverified_sessions" = "Engar óstaðfestar setur fundust."; +"user_other_session_no_verified_sessions" = "Engar staðfestar setur fundust."; +"user_other_session_no_inactive_sessions" = "Engar óvirkar setur fundust."; +"user_other_session_filter_menu_inactive" = "Óvirkt"; +"user_other_session_filter_menu_unverified" = "Óstaðfestar"; +"user_other_session_filter_menu_verified" = "Staðfestar"; +"user_other_session_filter_menu_all" = "Allar setur"; +"user_other_session_filter" = "Sía"; +"user_other_session_security_recommendation_title" = "Aðrar setur"; +"user_session_inactive_session_title" = "Óvirkar setur"; +"user_session_unverified_session_title" = "Óstaðfest seta"; +"user_session_verified_session_title" = "Sannreyndar setur"; +"user_session_got_it" = "Náði því"; +"user_session_push_notifications" = "Ýti-tilkynningar"; +"user_session_verification_unknown_short" = "Óþekkt"; +"user_session_verification_unknown" = "Óþekkt staða sannvottunar"; +"user_sessions_view_all_action" = "Skoða öll (%d)"; +"user_sessions_overview_link_device" = "Tengja tæki"; +"user_sessions_overview_current_session_section_title" = "Núverandi seta"; +"user_sessions_hide_location_info" = "Fela IP-vistfang"; +"user_sessions_show_location_info" = "Birta IP-vistfang"; +"user_sessions_overview_other_sessions_section_title" = "Aðrar setur"; +"user_sessions_overview_security_recommendations_inactive_title" = "Óvirkar setur"; +"user_sessions_overview_security_recommendations_unverified_title" = "Óstaðfestar setur"; +"user_sessions_overview_security_recommendations_section_title" = "Ráðleggingar varðandi öryggi"; + +// MARK: User sessions management + +// Parameter is the application display name (e.g. "Element") +"user_sessions_default_session_display_name" = "%@ iOS"; +"location_sharing_live_lab_promotion_activation" = "Virkja deilingu rauntímastaðsetninga"; +"location_sharing_live_timer_incoming" = "Í beinni til %@"; +"poll_timeline_reply_ended_poll" = "Lauk könnun"; +"poll_timeline_ended_text" = "Lauk könnuninni"; +"poll_history_past_segment_title" = "Fyrri kannanir"; +"poll_history_active_segment_title" = "Virkar kannanir"; + +// MARK: - Polls history + +"poll_history_title" = "Breytingaskrá könnunar"; +"all_chats_user_menu_accessibility_label" = "Valmynd notandans"; +"voice_broadcast_connection_error_title" = "Villa í tengingu"; +"voice_broadcast_voip_cannot_start_title" = "Get ekki hafið símtal"; +"voice_broadcast_stop_alert_agree_button" = "Já, stöðva"; +"voice_broadcast_buffering" = "Hleð í biðminni..."; +"voice_broadcast_time_left" = "%@ eftir"; +"voice_broadcast_tile" = "Útvörpun tals"; +"voice_broadcast_live" = "Beint"; +"voice_broadcast_playback_lock_screen_placeholder" = "Útvörpun tals"; + +// Unverified sessions +"key_verification_alert_title" = "Þú ert með óstaðfestar setur"; +"sign_out_confirmation_message" = "Ertu viss um að þú viljir skrá þig út?"; + +// MARK: Sign out warning + +"sign_out" = "Skrá út"; +"secure_key_backup_setup_cancel_alert_message" = "Ef þú hættir við núna, geturðu tapað dulrituðum skilaboðum og gögnum ef þú missir aðgang að innskráningum þínum.\n\nÞú getur víka sett upp örugga afritun og sýslað með dulritunarlyklana þína í stillingunum."; +"room_details_polls" = "Breytingaskrá könnunar"; +"manage_session_sign_out_other_sessions" = "Skrá út úr öllum öðrum setum"; +"manage_session_rename" = "Endurnefna setu"; +"settings_labs_enable_voice_broadcast" = "Útvörpun tals"; +"authentication_qr_login_failure_retry" = "Reyna aftur"; +"authentication_qr_login_loading_connecting_device" = "Tengist við tæki"; +"authentication_qr_login_scan_title" = "Skanna QR-kóða"; +"authentication_qr_login_start_title" = "Skanna QR-kóða"; +"authentication_login_with_qr" = "Skrá inn með QR-kóða"; From 7cc9cb6a2b043bd5dc86f3d863432a5553b2bc92 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Mon, 23 Jan 2023 11:38:32 +0000 Subject: [PATCH 153/160] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2374 of 2374 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 4840931209..95c51d890c 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2915,3 +2915,10 @@ "wysiwyg_composer_format_action_unordered_list" = "Перемкнути на маркований список"; "voice_broadcast_recorder_connection_error" = "Помилка з'єднання - Запис призупинено"; "poll_timeline_reply_ended_poll" = "Завершене опитування"; + +// MARK: - Launch loading + +"launch_loading_migrating_data" = "Перенесення даних\n%@ %%"; +"settings_labs_disable_crypto_sdk" = "Crypto SDK увімкнено. Щоб вимкнути, перевстановіть застосунок"; +"settings_labs_confirm_crypto_sdk" = "Дію не можна скасувати"; +"settings_labs_enable_crypto_sdk" = "Увімкнути новий заснований на rust Crypto SDK"; From 0bd9892de8d5a3f7a0adb01121def6914a752bcd Mon Sep 17 00:00:00 2001 From: Linerly Date: Mon, 23 Jan 2023 09:30:50 +0000 Subject: [PATCH 154/160] Translated using Weblate (Indonesian) Currently translated at 100.0% (2374 of 2374 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index efb28c6d7e..508d3eb7d1 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2917,3 +2917,10 @@ "voice_broadcast_connection_error_title" = "Kesalahan koneksi"; "voice_broadcast_recorder_connection_error" = "Kesalahan koneksi - Perekaman dijeda"; "poll_timeline_reply_ended_poll" = "Pemungutan suara berakhir"; + +// MARK: - Launch loading + +"launch_loading_migrating_data" = "Memigrasikan data\n%@ %%"; +"settings_labs_disable_crypto_sdk" = "SDK Kripto diaktifkan. Untuk menonaktifkan, mohon memasang ulang aplikasi"; +"settings_labs_confirm_crypto_sdk" = "Tindakan ini tidak dapat diurungkan"; +"settings_labs_enable_crypto_sdk" = "Aktifkan SDK Kripto baru berbasis Rust"; From 217a57bba74d3fbaae2b08c38b1d34a7576ebef9 Mon Sep 17 00:00:00 2001 From: Suguru Hirahara Date: Mon, 23 Jan 2023 16:40:41 +0000 Subject: [PATCH 155/160] Translated using Weblate (Japanese) Currently translated at 64.7% (1536 of 2374 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ja/ --- Riot/Assets/ja.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/ja.lproj/Vector.strings b/Riot/Assets/ja.lproj/Vector.strings index 2a82d520cc..9c76e1920b 100644 --- a/Riot/Assets/ja.lproj/Vector.strings +++ b/Riot/Assets/ja.lproj/Vector.strings @@ -1720,7 +1720,7 @@ "pin_protection_reset_alert_action_reset" = "リセット"; "authentication_recaptcha_title" = "あなたは人間ですか?"; "authentication_verify_msisdn_waiting_button" = "コードを再送信"; -"authentication_choose_password_submit_button" = "パスワードをリセット"; +"authentication_choose_password_submit_button" = "パスワードを再設定"; "authentication_choose_password_signout_all_devices" = "全ての端末からサインアウト"; "authentication_choose_password_text_field_placeholder" = "新しいパスワード"; "authentication_terms_title" = "プライバシーポリシー"; From e26439b14e3c111e163a6821c15abbbe80c3a93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Mon, 23 Jan 2023 15:55:24 +0000 Subject: [PATCH 156/160] Translated using Weblate (Estonian) Currently translated at 100.0% (2374 of 2374 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 063de0b207..71ea69ebf2 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2662,3 +2662,10 @@ "wysiwyg_composer_format_action_unordered_list" = "Lülita täpploend sisse/välja"; "voice_broadcast_recorder_connection_error" = "Viga võrguühenduses - salvestamine on peatatud"; "poll_timeline_reply_ended_poll" = "Lõppenud küsitlus"; + +// MARK: - Launch loading + +"launch_loading_migrating_data" = "Tõstame andmeid ümber\n%@ %%"; +"settings_labs_disable_crypto_sdk" = "Uus Crypto SDK on kasutusel. Tema väljalülitamiseks palun paigalda rakendus uuesti"; +"settings_labs_confirm_crypto_sdk" = "Seda toimingut ei saa tagasi pöörata"; +"settings_labs_enable_crypto_sdk" = "Võta kasutusele uus Rust-keelel põhinev Crypto SDK"; From 6685531cd63977d780e9e2862188bec1bdf6d314 Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Mon, 23 Jan 2023 22:39:48 +0000 Subject: [PATCH 157/160] Translated using Weblate (Slovak) Currently translated at 100.0% (2374 of 2374 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index d34e26d648..83b316cf8d 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2913,3 +2913,10 @@ "wysiwyg_composer_format_action_unordered_list" = "Prepnúť zoznam s odrážkami"; "voice_broadcast_recorder_connection_error" = "Chyba pripojenia - nahrávanie pozastavené"; "poll_timeline_reply_ended_poll" = "Ukončená anketa"; + +// MARK: - Launch loading + +"launch_loading_migrating_data" = "Migrácia údajov\n%@ %%"; +"settings_labs_disable_crypto_sdk" = "Crypto SDK je povolené. Ak to chcete vypnúť, preinštalujte prosím aplikáciu"; +"settings_labs_confirm_crypto_sdk" = "Túto akciu nemožno vrátiť späť"; +"settings_labs_enable_crypto_sdk" = "Zapnúť nové Crypto SDK využívajúce Rust"; From 02d44065253da85818396be6967b62d55b6e048f Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 24 Jan 2023 12:39:28 +0000 Subject: [PATCH 158/160] changelog.d: Upgrade MatrixSDK version ([v0.24.8](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.8)). --- Podfile | 2 +- changelog.d/x-nolink-0.change | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/x-nolink-0.change diff --git a/Podfile b/Podfile index 02f9e605f5..35ba935b2a 100644 --- a/Podfile +++ b/Podfile @@ -16,7 +16,7 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK 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 -$matrixSDKVersion = '= 0.24.7' +$matrixSDKVersion = '= 0.24.8' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } diff --git a/changelog.d/x-nolink-0.change b/changelog.d/x-nolink-0.change new file mode 100644 index 0000000000..4c12806ec6 --- /dev/null +++ b/changelog.d/x-nolink-0.change @@ -0,0 +1 @@ +Upgrade MatrixSDK version ([v0.24.8](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.8)). \ No newline at end of file From 5bb8f224f6c2644339d8d2c71ca6339435db87b0 Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 24 Jan 2023 12:39:29 +0000 Subject: [PATCH 159/160] version++ --- CHANGES.md | 40 +++++++++++++++++++++++++++++++++++ changelog.d/5148.bugfix | 1 - changelog.d/7222.bugfix | 1 - changelog.d/7229.change | 1 - changelog.d/7234.change | 1 - changelog.d/7238.feature | 1 - changelog.d/7252.bugfix | 1 - changelog.d/7261.bugfix | 1 - changelog.d/7263.bugfix | 1 - changelog.d/7271.feature | 1 - changelog.d/7279.change | 1 - changelog.d/7280.change | 1 - changelog.d/7283.feature | 1 - changelog.d/7285.change | 1 - changelog.d/pr-7225.change | 1 - changelog.d/pr-7256.build | 1 - changelog.d/pr-7257.bugfix | 1 - changelog.d/pr-7267.change | 1 - changelog.d/pr-7268.bugfix | 1 - changelog.d/pr-7272.change | 1 - changelog.d/pr-7273.change | 1 - changelog.d/pr-7275.change | 1 - changelog.d/pr-7278.change | 1 - changelog.d/pr-7284.change | 1 - changelog.d/pr-7286.change | 1 - changelog.d/x-nolink-0.change | 1 - 26 files changed, 40 insertions(+), 25 deletions(-) delete mode 100644 changelog.d/5148.bugfix delete mode 100644 changelog.d/7222.bugfix delete mode 100644 changelog.d/7229.change delete mode 100644 changelog.d/7234.change delete mode 100644 changelog.d/7238.feature delete mode 100644 changelog.d/7252.bugfix delete mode 100644 changelog.d/7261.bugfix delete mode 100644 changelog.d/7263.bugfix delete mode 100644 changelog.d/7271.feature delete mode 100644 changelog.d/7279.change delete mode 100644 changelog.d/7280.change delete mode 100644 changelog.d/7283.feature delete mode 100644 changelog.d/7285.change delete mode 100644 changelog.d/pr-7225.change delete mode 100644 changelog.d/pr-7256.build delete mode 100644 changelog.d/pr-7257.bugfix delete mode 100644 changelog.d/pr-7267.change delete mode 100644 changelog.d/pr-7268.bugfix delete mode 100644 changelog.d/pr-7272.change delete mode 100644 changelog.d/pr-7273.change delete mode 100644 changelog.d/pr-7275.change delete mode 100644 changelog.d/pr-7278.change delete mode 100644 changelog.d/pr-7284.change delete mode 100644 changelog.d/pr-7286.change delete mode 100644 changelog.d/x-nolink-0.change diff --git a/CHANGES.md b/CHANGES.md index f62115f7c1..e4d8ef4d86 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,43 @@ +## Changes in 1.9.16 (2023-01-24) + +✨ Features + +- Rich Text Composer: Enable bulleted/numbered lists support ([#7238](https://github.com/vector-im/element-ios/issues/7238)) +- Rich Text Composer: Enable quote & code blocks support ([#7271](https://github.com/vector-im/element-ios/issues/7271)) +- Voice Broadcast: When deleting a voice broadcast, all data is now deleted on server side (MSC3912 implementation). ([#7283](https://github.com/vector-im/element-ios/issues/7283)) + +🙌 Improvements + +- Labs: VoiceBroadcast: Handle VoIP buttons when VB is used ([#7225](https://github.com/vector-im/element-ios/pull/7225)) +- Polls: add UI for active poll history. ([#7267](https://github.com/vector-im/element-ios/pull/7267)) +- CryptoSDK: Add labs settings to enable Crypto SDK ([#7272](https://github.com/vector-im/element-ios/pull/7272)) +- Voice Broadcast: Improved detection of voice broadcast completion during playback. ([#7273](https://github.com/vector-im/element-ios/pull/7273)) +- Remove "Leave" button on Room details screen ([#7275](https://github.com/vector-im/element-ios/pull/7275)) +- Polls: poll history UI for past polls. ([#7278](https://github.com/vector-im/element-ios/pull/7278)) +- Polls: render replies to poll events better. ([#7284](https://github.com/vector-im/element-ios/pull/7284)) +- CryptoV2: Display migration progress during startup ([#7286](https://github.com/vector-im/element-ios/pull/7286)) +- Upgrade MatrixSDK version ([v0.24.8](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.8)). +- Voice broadcast connection error handling while recording. ([#7229](https://github.com/vector-im/element-ios/issues/7229)) +- Handle a connection issue when we try to start a new voice broadcast. ([#7234](https://github.com/vector-im/element-ios/issues/7234)) +- Rich Text Editor: https:// or mailto: scheme is automatically added when creating a link if no scheme is specified. ([#7279](https://github.com/vector-im/element-ios/issues/7279)) +- Rich Text Editor: Adding a link over a blank selection, prompts the user to create a new link with new text to replace such selection. ([#7280](https://github.com/vector-im/element-ios/issues/7280)) +- Voice Broadcast: handle the lost of connectivity with the homeserver while recording. ([#7285](https://github.com/vector-im/element-ios/issues/7285)) + +🐛 Bugfixes + +- Voice Broadcast: The Now Playing Info Center now displays a voice broadcast instead of a voice message when a user is listening to a voice broadcast. ([#7257](https://github.com/vector-im/element-ios/pull/7257)) +- Fix a crash caused by the missing Avatar Service dependency. ([#7268](https://github.com/vector-im/element-ios/pull/7268)) +- The (edited) tag for messages is now light grey like on web and Android. ([#5148](https://github.com/vector-im/element-ios/issues/5148)) +- Live Location Sharing does not work on first selection after granting "Allow always" location permission. ([#7222](https://github.com/vector-im/element-ios/issues/7222)) +- Voice Broadcast: Fixed an issue where the voice broadcast audio player progress bar behaved unexpectedly. ([#7252](https://github.com/vector-im/element-ios/issues/7252)) +- Voice Broadcast: VoiceBroadcast chunks are no longer resent as voice messages ([#7261](https://github.com/vector-im/element-ios/issues/7261)) +- Timeline's links and hyperlinks match now the blue colour of Android and Web. ([#7263](https://github.com/vector-im/element-ios/issues/7263)) + +🧱 Build + +- Fix Element Alpha workflow not being able to run. ([#7256](https://github.com/vector-im/element-ios/pull/7256)) + + ## Changes in 1.9.15 (2023-01-10) ✨ Features diff --git a/changelog.d/5148.bugfix b/changelog.d/5148.bugfix deleted file mode 100644 index 7f1ddcb3e4..0000000000 --- a/changelog.d/5148.bugfix +++ /dev/null @@ -1 +0,0 @@ -The (edited) tag for messages is now light grey like on web and Android. \ No newline at end of file diff --git a/changelog.d/7222.bugfix b/changelog.d/7222.bugfix deleted file mode 100644 index e1402cb0da..0000000000 --- a/changelog.d/7222.bugfix +++ /dev/null @@ -1 +0,0 @@ -Live Location Sharing does not work on first selection after granting "Allow always" location permission. diff --git a/changelog.d/7229.change b/changelog.d/7229.change deleted file mode 100644 index 7099b85005..0000000000 --- a/changelog.d/7229.change +++ /dev/null @@ -1 +0,0 @@ -Voice broadcast connection error handling while recording. diff --git a/changelog.d/7234.change b/changelog.d/7234.change deleted file mode 100644 index 52af7685d9..0000000000 --- a/changelog.d/7234.change +++ /dev/null @@ -1 +0,0 @@ -Handle a connection issue when we try to start a new voice broadcast. diff --git a/changelog.d/7238.feature b/changelog.d/7238.feature deleted file mode 100644 index 173f1195ed..0000000000 --- a/changelog.d/7238.feature +++ /dev/null @@ -1 +0,0 @@ -Rich Text Composer: Enable bulleted/numbered lists support diff --git a/changelog.d/7252.bugfix b/changelog.d/7252.bugfix deleted file mode 100644 index 0e823509f0..0000000000 --- a/changelog.d/7252.bugfix +++ /dev/null @@ -1 +0,0 @@ -Voice Broadcast: Fixed an issue where the voice broadcast audio player progress bar behaved unexpectedly. diff --git a/changelog.d/7261.bugfix b/changelog.d/7261.bugfix deleted file mode 100644 index 3594c59803..0000000000 --- a/changelog.d/7261.bugfix +++ /dev/null @@ -1 +0,0 @@ -Voice Broadcast: VoiceBroadcast chunks are no longer resent as voice messages diff --git a/changelog.d/7263.bugfix b/changelog.d/7263.bugfix deleted file mode 100644 index 425e2dd95f..0000000000 --- a/changelog.d/7263.bugfix +++ /dev/null @@ -1 +0,0 @@ -Timeline's links and hyperlinks match now the blue colour of Android and Web. \ No newline at end of file diff --git a/changelog.d/7271.feature b/changelog.d/7271.feature deleted file mode 100644 index f2ae089f9f..0000000000 --- a/changelog.d/7271.feature +++ /dev/null @@ -1 +0,0 @@ -Rich Text Composer: Enable quote & code blocks support diff --git a/changelog.d/7279.change b/changelog.d/7279.change deleted file mode 100644 index c605f89208..0000000000 --- a/changelog.d/7279.change +++ /dev/null @@ -1 +0,0 @@ -Rich Text Editor: https:// or mailto: scheme is automatically added when creating a link if no scheme is specified. diff --git a/changelog.d/7280.change b/changelog.d/7280.change deleted file mode 100644 index d387d563da..0000000000 --- a/changelog.d/7280.change +++ /dev/null @@ -1 +0,0 @@ -Rich Text Editor: Adding a link over a blank selection, prompts the user to create a new link with new text to replace such selection. diff --git a/changelog.d/7283.feature b/changelog.d/7283.feature deleted file mode 100644 index d139728d5a..0000000000 --- a/changelog.d/7283.feature +++ /dev/null @@ -1 +0,0 @@ -Voice Broadcast: When deleting a voice broadcast, all data is now deleted on server side (MSC3912 implementation). diff --git a/changelog.d/7285.change b/changelog.d/7285.change deleted file mode 100644 index 9d3f369ae8..0000000000 --- a/changelog.d/7285.change +++ /dev/null @@ -1 +0,0 @@ -Voice Broadcast: handle the lost of connectivity with the homeserver while recording. diff --git a/changelog.d/pr-7225.change b/changelog.d/pr-7225.change deleted file mode 100644 index df6cfd7a70..0000000000 --- a/changelog.d/pr-7225.change +++ /dev/null @@ -1 +0,0 @@ -Labs: VoiceBroadcast: Handle VoIP buttons when VB is used diff --git a/changelog.d/pr-7256.build b/changelog.d/pr-7256.build deleted file mode 100644 index 9a2cd140b7..0000000000 --- a/changelog.d/pr-7256.build +++ /dev/null @@ -1 +0,0 @@ -Fix Element Alpha workflow not being able to run. diff --git a/changelog.d/pr-7257.bugfix b/changelog.d/pr-7257.bugfix deleted file mode 100644 index 8a41b21c87..0000000000 --- a/changelog.d/pr-7257.bugfix +++ /dev/null @@ -1 +0,0 @@ -Voice Broadcast: The Now Playing Info Center now displays a voice broadcast instead of a voice message when a user is listening to a voice broadcast. diff --git a/changelog.d/pr-7267.change b/changelog.d/pr-7267.change deleted file mode 100644 index cab02bc6a6..0000000000 --- a/changelog.d/pr-7267.change +++ /dev/null @@ -1 +0,0 @@ -Polls: add UI for active poll history. diff --git a/changelog.d/pr-7268.bugfix b/changelog.d/pr-7268.bugfix deleted file mode 100644 index b6af7cd578..0000000000 --- a/changelog.d/pr-7268.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix a crash caused by the missing Avatar Service dependency. diff --git a/changelog.d/pr-7272.change b/changelog.d/pr-7272.change deleted file mode 100644 index 04a8dcc2e1..0000000000 --- a/changelog.d/pr-7272.change +++ /dev/null @@ -1 +0,0 @@ -CryptoSDK: Add labs settings to enable Crypto SDK diff --git a/changelog.d/pr-7273.change b/changelog.d/pr-7273.change deleted file mode 100644 index 2c3d47b2e1..0000000000 --- a/changelog.d/pr-7273.change +++ /dev/null @@ -1 +0,0 @@ -Voice Broadcast: Improved detection of voice broadcast completion during playback. diff --git a/changelog.d/pr-7275.change b/changelog.d/pr-7275.change deleted file mode 100644 index 6435f2f71d..0000000000 --- a/changelog.d/pr-7275.change +++ /dev/null @@ -1 +0,0 @@ -Remove "Leave" button on Room details screen diff --git a/changelog.d/pr-7278.change b/changelog.d/pr-7278.change deleted file mode 100644 index f7254ebb92..0000000000 --- a/changelog.d/pr-7278.change +++ /dev/null @@ -1 +0,0 @@ -Polls: poll history UI for past polls. diff --git a/changelog.d/pr-7284.change b/changelog.d/pr-7284.change deleted file mode 100644 index edab718561..0000000000 --- a/changelog.d/pr-7284.change +++ /dev/null @@ -1 +0,0 @@ -Polls: render replies to poll events better. diff --git a/changelog.d/pr-7286.change b/changelog.d/pr-7286.change deleted file mode 100644 index ff8cbb8204..0000000000 --- a/changelog.d/pr-7286.change +++ /dev/null @@ -1 +0,0 @@ -CryptoV2: Display migration progress during startup diff --git a/changelog.d/x-nolink-0.change b/changelog.d/x-nolink-0.change deleted file mode 100644 index 4c12806ec6..0000000000 --- a/changelog.d/x-nolink-0.change +++ /dev/null @@ -1 +0,0 @@ -Upgrade MatrixSDK version ([v0.24.8](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.8)). \ No newline at end of file From c0b819f89548b00e0be4e0b0127a7e498fac1f4b Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 24 Jan 2023 14:13:59 +0000 Subject: [PATCH 160/160] finish version++ --- Podfile.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index dbc139f682..24b937005f 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -55,9 +55,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.24.7): - - MatrixSDK/Core (= 0.24.7) - - MatrixSDK/Core (0.24.7): + - MatrixSDK (0.24.8): + - MatrixSDK/Core (= 0.24.8) + - MatrixSDK/Core (0.24.8): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -65,12 +65,12 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/CryptoSDK (0.24.7): - - MatrixSDKCrypto (= 0.1.7) - - MatrixSDK/JingleCallStack (0.24.7): + - MatrixSDK/CryptoSDK (0.24.8): + - MatrixSDKCrypto (= 0.1.8) + - MatrixSDK/JingleCallStack (0.24.8): - JitsiMeetSDK (= 5.0.2) - MatrixSDK/Core - - MatrixSDKCrypto (0.1.7) + - MatrixSDKCrypto (0.1.8) - OLMKit (3.2.12): - OLMKit/olmc (= 3.2.12) - OLMKit/olmcpp (= 3.2.12) @@ -122,8 +122,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.24.7) - - MatrixSDK/JingleCallStack (= 0.24.7) + - MatrixSDK (= 0.24.8) + - MatrixSDK/JingleCallStack (= 0.24.8) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -197,7 +197,7 @@ CHECKOUT OPTIONS: :git: https://github.com/matrix-org/matrix-analytics-events.git SPEC CHECKSUMS: - AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce + AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 AnalyticsEvents: 0cc8cf52da2fd464a2f39b788a295988151116ce BlueCryptor: b0aee3d9b8f367b49b30de11cda90e1735571c24 BlueECC: 0d18e93347d3ec6d41416de21c1ffa4d4cd3c2cc @@ -220,8 +220,8 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 895929fad10b7ec9aa96d557403b44c5e3522211 - MatrixSDKCrypto: 2bd9ca41b2c644839f4e680a64897d56b3f95392 + MatrixSDK: cf1c1b2a9742f7f4fad21e94bd94cd8f13c47369 + MatrixSDKCrypto: 862d9b4dbb6861da030943f5a18c39258ed7345b OLMKit: da115f16582e47626616874e20f7bb92222c7a51 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -241,6 +241,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 56782e2abd382278b3c5b23824ca74994fd0a97e +PODFILE CHECKSUM: 079b57b800c666ad864e1f059ae69e150a98a4f0 COCOAPODS: 1.11.3