mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-26 19:34:25 +02:00
2fc0832ca8
* Login with QR UI components (#6790) * Display QR button on login screen if HS supports * Create start screen * Add build flag * Connect start screen to the login * QR display screen * Move `LabelledDividerView` into separate file * Show display QR screen on button tap * Add swift concurreny to CameraAccessManager * Introduce `QRLoginServiceProtocol` * Use new service in screens * Introduce scan QR code screen * Remove hardcoded service availability * Remove unnecessary import * Add confirmation screen * Add loading screen * Fix ZXingObjc targets * Add failure screen * Add strings * Various UI tweaks, navigation according to the service state * Fix tests * Add string for invalid QR error * Add QR login service mode * dark mode support almost completed * 'View all' button in other sessions list * Changelog * Only use device type name as fallback for session display name * Add changelog * Revert translation changes * Fix copyright year * updated the package and added a circle background to the + button * QR login from device manager (#6818) * Add link device button into the sessions overview screen * Run Swift format * Fix tests * Fix a crash in tests * Fix PR remark * Bring back English string for now to unbreak the build * pr comment addressed * Fix composer resizing animations * Remove prefix from tests * Add back generated user session name string * Fixed swiftformat warnings * Remove current app name from device type name * updated package version * QR Login additional flags (#6825) * Include app name in default session display name * Add changelog * edit is displayed in the WYSIWYG, but the send button still sends a new message instead of correcting the edit * Move composer send media selection to it's own coordinator and us e ioS 15 api for sheet * fix newline in pod lockfile * fix newline * Add labs flag and strings * Translated using Weblate (Italian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Estonian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (German) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Icelandic) Currently translated at 86.0% (1919 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/is/ * Split out models, add some tests and fix some formatting. * Fixed formatting * Expose AuthenticationRestClient async login token generation method (MSC3882) * Only update the nav bar from the top SwiftUI view. * Bugfix: Element freezes after searching in a room #6762 * Tidy-up formatting. * Hide Maximise button as animations not working correctly * Remove the ffmpeg pod. * created the replace formatted text function * Fix authentication tests. * Translated using Weblate (Swedish) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/sv/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translations update from Weblate (#6843) * Translated using Weblate (Italian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Estonian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (German) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Icelandic) Currently translated at 86.0% (1919 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/is/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2229 of 2229 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Thomas Schmidt <thomas@thsmdt.com> Co-authored-by: Sveinn í Felli <sv1@fellsnet.is> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Weblate <noreply@weblate.org> * Translations update from Weblate (#6844) * Translated using Weblate (Icelandic) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/is/ * Translated using Weblate (Swedish) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/sv/ Co-authored-by: Sveinn í Felli <sv1@fellsnet.is> Co-authored-by: LinAGKar <linus.kardell@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> * edit works functionally (no UI changes yet) * package update * formatted reply support * error logging improvement * code improvements * improving code * improving overall code * Filter button * Verified sessions * reverting the xcscheme file * revert * todo reminder * Ignore OS version from web based sessions (PSG-826) (#6852) * Ignore OS version from web based sessions * Add changelog * Clear filter button * Device Manager: Rename Session (#6826) * Publish the user sessions overview data. * Add UserSessionName screen. * Update logout action to match Figma more closely. * UI and unit tests * Device Manager: Verify session (#6832) * Initial implementation * Add verificationState to UserSessionInfo * Listen for changes device changes in the service. * Remove loader for static location sharing * Remove loader for live location sharing * Move completions around * Add changelog.d file * edit mode changes the send button * right assets * color improvements and implementing the cancel callback * implemented cancel, but I need to actually need to solve a problem where the previous text is not stored in case of cancel of the reply/edit * edit reply completed, just need to polish the UI a bit more. * Renamed OtherUserSessionsFilter to UserOtherSessionsFilter * Changelog * Formating * some UI tweaks * Add voice broadcast state event (#6785) * Tidy up TabBarCoordinator now that AllChatsCoordinator exists. * Update Riot/Assets/en.lproj/Vector.strings Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Update RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsModels.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Single scale image * Renamed filerWasChanged to filterWasChanged * Revert collections update * Added accessibility label to filter menu * pr comment + some design improvements * should now be aligned to the designs * get rid of additional UIHostingController. Cleanup and comments. * legacy sendMode code separation to have RiotSwiftUI be able to build. * Added last activity item to session details screen * fix * More comments * Update strings for unknown sessions. * Fix RiotTests. * code improvements * wiftlint * Remove verify session button for other sessions when the current session is unverified * Implement login with scanned QR code flows * Fix initiator flows and e2e tests * Add missing rendezvousServerBaseURL buildSetting * Add changelog * Remove extra step as no longer required * Fix typo * Remove now unnecessary creator public key publishing. Rebuilt flows and fixed tests * Fix UI tests for features currently disabled * composer code improvement * improving code * unit tests * Tests completed! The only doubt I have left is about testing the string content considering the localisations in tests * code improvement * code improvement * ui tests should now work on CI * ui test should work now * ui tests fix on ci * ui test improvements * Correct verificationStatusAdditionalInfoText for other session * Changelog * Correct label for other verified session * Formating fixes * Update enhancement issue template Link to discussions for cross-platform and feature requests * Updates based on comments. * more comment updates * unit tests improved! * improved UI tests * Add a SignOutFlowPresenter. (#6854) Used in AllChats, UserSessions and Settings. (TabBarCoordinator is unnecessary as signout will be removed from there). * Additional translations and accessiblity labels * Added E2EE support on sessions created through QR code login * Fixed various SwiftFormat warnings * Remove unnecessary private key requests as it already happens automatically when marking the existing device as verified * Allow the login with qr button to be shown on the login screen if the currently selected homeserver supports it * Check login intents match between QR code and current flow * Fix authentication unit tests * Login against the homeserver provided through the QR code * Navigating to session overview goes to session details * Changelog * Fix typo * custom tint + blinking dark theme text color issue fix * Identify inactive sessions * Changelog * Translated using Weblate (German) Currently translated at 100.0% (2269 of 2269 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (French) Currently translated at 100.0% (2269 of 2269 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/fr/ * Translated using Weblate (Italian) Currently translated at 100.0% (2269 of 2269 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2269 of 2269 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2269 of 2269 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2269 of 2269 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2269 of 2269 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * opacity transition implemented * 0.15 animation * updated UI tests * project yml with the latest working version of the package * "Notifications on this device" not refreshed in user settings screen * Update tools. • Un-pin versions to update tools on each release. • Switch to SwiftFormat as a pod. * All chats shows no rooms in the list - Fixed * added the grabber and the corner radius * the right corner radius value * ios 16 custom detent * height value * Revert "height value" This reverts commit fae63c6f768d2dd375d431bc16acca31e2dd56bb. * Revert "ios 16 custom detent" This reverts commit 758dacc00e77c57b787aae71405a1f90c03c3666. * better padding * Update Wysiwyg dep and use new focused param on WysiwygComposerView * Filter out application section if needed * Add changelog.d file * design improvements! * designs are perfect now * Fix bubble cell visibility (#6893) * updated the swiftpm * package resolved * Set inputAccessoryViewForKeyboard so that interactive dismissal works. * [Voice Broadcast] Aggregate the chunks of voice messages in room timeline (#6891) * Add missing changelogs * changelog * changelog * changelog linked to an issue * Add weak self reference to closure * spacing improved further * Use unstable prefixes for QR code login * Changelog * Force update client information * Changelog * Fix incorrect Task creation for processing scanned qr codes * Check and mark the received MSK as trusted before locally verifying the existing device * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> * Translations update from Weblate (#6908) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> * Translations update from Weblate (#6909) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (49 of 49 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> * Translations update from Weblate (#6908) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> * Translations update from Weblate (#6910) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translations update from Weblate (#6908) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> * Translations update from Weblate (#6909) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (49 of 49 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> * Translations update from Weblate (#6908) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> * Translations update from Weblate (#6911) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6909) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (49 of 49 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> * Translations update from Weblate (#6908) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> * Translations update from Weblate (#6910) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translations update from Weblate (#6908) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> * Translations update from Weblate (#6909) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (49 of 49 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> * Translations update from Weblate (#6908) * Translated using Weblate (Bulgarian) Currently translated at 100.0% (8 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/bg/ * Translations update from Weblate (#6907) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> * Translations update from Weblate (#6915) * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Russian) Currently translated at 81.2% (1870 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Bulgarian) Currently translated at 66.4% (1529 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/bg/ * Translated using Weblate (Italian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * Translated using Weblate (Estonian) Currently translated at 97.5% (2245 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2301 of 2301 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (Italian) Currently translated at 100.0% (2302 of 2302 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Weblate <noreply@weblate.org> * Missing change from fix * changelog * Only running alpha builds when PR labeled with `Trigger-PR-Build` * Configure codecov flags and have them be carried forward * Add pull request change types for triggering alpha builds * changelog.d: Upgrade MatrixSDK version ([v0.24.1](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.1)). * version++ Co-authored-by: Anderas <andyuhnak@gmail.com> Co-authored-by: Mauro Romito <mauro.romito@element.io> Co-authored-by: Aleksandrs Proskurins <paleksandrs@gmail.com> Co-authored-by: Johannes Marbach <johannesm@element.io> Co-authored-by: aringenbach <arnaudr@element.io> Co-authored-by: David Langley <langley.dave@gmail.com> Co-authored-by: random <dictionary@tutamail.com> Co-authored-by: Jozef Gaal <preklady@mayday.sk> Co-authored-by: Linerly <linerly@protonmail.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Thomas Schmidt <thomas@thsmdt.com> Co-authored-by: Sveinn í Felli <sv1@fellsnet.is> Co-authored-by: Stefan Ceriu <stefanc@matrix.org> Co-authored-by: Aleksandrs Proskurins <aleksandrsp@element.io> Co-authored-by: Doug <douglase@element.io> Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> Co-authored-by: Shunmugaraj <toshanmugaraj@gmail.com> Co-authored-by: LinAGKar <linus.kardell@gmail.com> Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Element Translate Bot <admin@riot.im> Co-authored-by: Alfonso Grillo <alfogrillo@gmail.com> Co-authored-by: Alfonso Grillo <alfogrillo@element.io> Co-authored-by: Yoan Pintas <y.pintas@gmail.com> Co-authored-by: Gil Eluard <gile@element.io> Co-authored-by: Hugh Nimmo-Smith <hughns@element.io> Co-authored-by: Kat Gerasimova <ekaterinag@element.io> Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com> Co-authored-by: Thibault Martin <mail@thibaultmart.in> Co-authored-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Nui Harime <harime.nui@yandex.ru> Co-authored-by: Szimszon <github@oregpreshaz.eu> Co-authored-by: Slavi Pantaleev <slavi@devture.com> Co-authored-by: gulekismail <ismailgulek0@gmail.com>
1420 lines
49 KiB
Objective-C
1420 lines
49 KiB
Objective-C
/*
|
|
Copyright 2015 OpenMarket Ltd
|
|
Copyright 2019 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 "RoomBubbleCellData.h"
|
|
|
|
#import "EventFormatter.h"
|
|
|
|
#import "AvatarGenerator.h"
|
|
#import "Tools.h"
|
|
#import "RoomReactionsViewSizer.h"
|
|
|
|
#import "GeneratedInterface-Swift.h"
|
|
|
|
static NSAttributedString *timestampVerticalWhitespace = nil;
|
|
|
|
NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotification";
|
|
|
|
@interface RoomBubbleCellData()
|
|
|
|
@property(nonatomic, readonly) BOOL addVerticalWhitespaceForSelectedComponentTimestamp;
|
|
@property(nonatomic, readwrite) CGFloat additionalContentHeight;
|
|
@property(nonatomic) BOOL shouldUpdateAdditionalContentHeight;
|
|
|
|
// Flags to "Show All" reactions for an event
|
|
@property(nonatomic) NSMutableSet<NSString* /* eventId */> *eventsToShowAllReactions;
|
|
|
|
@end
|
|
|
|
@implementation RoomBubbleCellData
|
|
|
|
- (BOOL)addVerticalWhitespaceForSelectedComponentTimestamp
|
|
{
|
|
return self.showTimestampForSelectedComponent && !self.displayTimestampForSelectedComponentOnLeftWhenPossible;
|
|
}
|
|
|
|
#pragma mark - Override MXKRoomBubbleCellData
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (self)
|
|
{
|
|
_eventsToShowAllReactions = [NSMutableSet set];
|
|
_componentIndexOfSentMessageTick = -1;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithEvent:(MXEvent *)event andRoomState:(MXRoomState *)roomState andRoomDataSource:(MXKRoomDataSource *)roomDataSource
|
|
{
|
|
self = [super initWithEvent:event andRoomState:roomState andRoomDataSource:roomDataSource];
|
|
|
|
if (self)
|
|
{
|
|
self.displayTimestampForSelectedComponentOnLeftWhenPossible = YES;
|
|
|
|
switch (event.eventType)
|
|
{
|
|
case MXEventTypeRoomMember:
|
|
{
|
|
// Membership events have their own cell type
|
|
self.tag = RoomBubbleCellDataTagMembership;
|
|
|
|
// Membership events can be collapsed together
|
|
self.collapsable = YES;
|
|
|
|
// Collapse them by default
|
|
self.collapsed = YES;
|
|
|
|
// find the room create event in stateEvents
|
|
MXEvent *roomCreateEvent = [roomState.stateEvents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"wireType == %@", kMXEventTypeStringRoomCreate]].firstObject;
|
|
NSString *creatorUserId = [MXRoomCreateContent modelFromJSON:roomCreateEvent.content].creatorUserId;
|
|
if (creatorUserId)
|
|
{
|
|
MXRoomMemberEventContent *content = [MXRoomMemberEventContent modelFromJSON:event.content];
|
|
if ([kMXMembershipStringJoin isEqualToString:content.membership] &&
|
|
[creatorUserId isEqualToString:event.sender])
|
|
{
|
|
// join event of the room creator
|
|
// group it with room creation events
|
|
self.tag = RoomBubbleCellDataTagRoomCreateConfiguration;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MXEventTypeRoomCreate:
|
|
{
|
|
MXRoomCreateContent *createContent = [MXRoomCreateContent modelFromJSON:event.content];
|
|
|
|
if (createContent.roomPredecessorInfo)
|
|
{
|
|
self.tag = RoomBubbleCellDataTagRoomCreateWithPredecessor;
|
|
}
|
|
else
|
|
{
|
|
self.tag = RoomBubbleCellDataTagRoomCreationIntro;
|
|
}
|
|
|
|
// Membership events can be collapsed together
|
|
self.collapsable = YES;
|
|
|
|
// Collapse them by default
|
|
self.collapsed = YES;
|
|
}
|
|
break;
|
|
case MXEventTypeRoomTopic:
|
|
case MXEventTypeRoomName:
|
|
case MXEventTypeRoomEncryption:
|
|
case MXEventTypeRoomHistoryVisibility:
|
|
case MXEventTypeRoomGuestAccess:
|
|
case MXEventTypeRoomAvatar:
|
|
case MXEventTypeRoomJoinRules:
|
|
{
|
|
self.tag = RoomBubbleCellDataTagRoomCreateConfiguration;
|
|
|
|
// Membership events can be collapsed together
|
|
self.collapsable = YES;
|
|
|
|
// Collapse them by default
|
|
self.collapsed = YES;
|
|
}
|
|
break;
|
|
case MXEventTypeCallInvite:
|
|
case MXEventTypeCallAnswer:
|
|
case MXEventTypeCallHangup:
|
|
case MXEventTypeCallReject:
|
|
{
|
|
self.tag = RoomBubbleCellDataTagCall;
|
|
|
|
// Call events can be collapsed together
|
|
self.collapsable = YES;
|
|
|
|
// Collapse them by default
|
|
self.collapsed = YES;
|
|
|
|
// Show timestamps always on right
|
|
self.displayTimestampForSelectedComponentOnLeftWhenPossible = NO;
|
|
break;
|
|
}
|
|
case MXEventTypePollStart:
|
|
{
|
|
self.tag = RoomBubbleCellDataTagPoll;
|
|
self.collapsable = NO;
|
|
self.collapsed = NO;
|
|
|
|
break;
|
|
}
|
|
case MXEventTypeBeaconInfo:
|
|
{
|
|
self.tag = RoomBubbleCellDataTagLiveLocation;
|
|
self.collapsable = NO;
|
|
self.collapsed = NO;
|
|
|
|
[self updateBeaconInfoSummaryWithId:event.eventId andEvent:event];
|
|
break;
|
|
}
|
|
case MXEventTypeCustom:
|
|
{
|
|
if ([event.type isEqualToString:kWidgetMatrixEventTypeString]
|
|
|| [event.type isEqualToString:kWidgetModularEventTypeString])
|
|
{
|
|
Widget *widget = [[Widget alloc] initWithWidgetEvent:event inMatrixSession:roomDataSource.mxSession];
|
|
if ([widget.type isEqualToString:kWidgetTypeJitsiV1] ||
|
|
[widget.type isEqualToString:kWidgetTypeJitsiV2])
|
|
{
|
|
self.tag = RoomBubbleCellDataTagGroupCall;
|
|
|
|
// Show timestamps always on right
|
|
self.displayTimestampForSelectedComponentOnLeftWhenPossible = NO;
|
|
}
|
|
}
|
|
else if ([event.type isEqualToString:VoiceBroadcastSettings.eventType])
|
|
{
|
|
self.tag = RoomBubbleCellDataTagVoiceBroadcast;
|
|
self.collapsable = NO;
|
|
self.collapsed = NO;
|
|
|
|
MXLogDebug(@"VB incoming initWithEvent")
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case MXEventTypeRoomMessage:
|
|
{
|
|
if (event.location)
|
|
{
|
|
self.tag = RoomBubbleCellDataTagLocation;
|
|
self.collapsable = NO;
|
|
self.collapsed = NO;
|
|
}
|
|
else if (event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType])
|
|
{
|
|
self.tag = RoomBubbleCellDataTagVoiceBroadcast;
|
|
self.collapsable = NO;
|
|
self.collapsed = NO;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
[self keyVerificationDidUpdate];
|
|
|
|
// Increase maximum number of components
|
|
self.maxComponentCount = 20;
|
|
|
|
// Indicate that the text message layout should be recomputed.
|
|
[self invalidateTextLayout];
|
|
|
|
// Load a url preview if necessary.
|
|
[self refreshURLPreviewForEventId:event.eventId];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (NSUInteger)updateEvent:(NSString *)eventId withEvent:(MXEvent *)event
|
|
{
|
|
NSUInteger retVal = [super updateEvent:eventId withEvent:event];
|
|
|
|
// Update any URL preview data as necessary.
|
|
[self refreshURLPreviewForEventId:event.eventId];
|
|
|
|
if (self.tag == RoomBubbleCellDataTagLiveLocation)
|
|
{
|
|
[self updateBeaconInfoSummaryWithId:eventId andEvent:event];
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
- (void)prepareBubbleComponentsPosition
|
|
{
|
|
if (shouldUpdateComponentsPosition)
|
|
{
|
|
// The bubble layout depends on the room read receipts which must be retrieved on the main thread to prevent us from race conditions.
|
|
// Check here the current thread, this is just a sanity check because this method is called during the rendering step
|
|
// which takes place on the main thread.
|
|
if ([NSThread currentThread] != [NSThread mainThread])
|
|
{
|
|
MXLogDebug(@"[RoomBubbleCellData] prepareBubbleComponentsPosition called on wrong thread");
|
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
[self refreshBubbleComponentsPosition];
|
|
});
|
|
}
|
|
else
|
|
{
|
|
[self refreshBubbleComponentsPosition];
|
|
}
|
|
|
|
shouldUpdateComponentsPosition = NO;
|
|
}
|
|
|
|
[self updateAdditionalContentHeightIfNeeded];
|
|
}
|
|
|
|
- (NSAttributedString*)attributedTextMessage
|
|
{
|
|
[self buildAttributedStringIfNeeded];
|
|
|
|
return attributedTextMessage;
|
|
}
|
|
|
|
- (NSAttributedString*)attributedTextMessageWithoutPositioningSpace
|
|
{
|
|
[self buildAttributedStringIfNeeded];
|
|
|
|
return attributedTextMessageWithoutPositioningSpace;
|
|
}
|
|
|
|
- (BOOL)hasNoDisplay
|
|
{
|
|
BOOL hasNoDisplay = YES;
|
|
|
|
switch (self.tag)
|
|
{
|
|
case RoomBubbleCellDataTagKeyVerificationNoDisplay:
|
|
hasNoDisplay = YES;
|
|
break;
|
|
case RoomBubbleCellDataTagRoomCreationIntro:
|
|
hasNoDisplay = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagPoll:
|
|
if (!self.events.lastObject.isEditEvent)
|
|
{
|
|
hasNoDisplay = NO;
|
|
}
|
|
|
|
break;
|
|
case RoomBubbleCellDataTagLocation:
|
|
hasNoDisplay = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagLiveLocation:
|
|
// Show the cell only if the summary exists
|
|
if (self.beaconInfoSummary)
|
|
{
|
|
hasNoDisplay = NO;
|
|
}
|
|
|
|
break;
|
|
case RoomBubbleCellDataTagVoiceBroadcast:
|
|
if (RiotSettings.shared.enableVoiceBroadcast == YES &&
|
|
[VoiceBroadcastInfo isStartedFor:[VoiceBroadcastInfo modelFromJSON:self.events.lastObject.content].state])
|
|
{
|
|
hasNoDisplay = NO;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
hasNoDisplay = [super hasNoDisplay];
|
|
break;
|
|
}
|
|
|
|
return hasNoDisplay;
|
|
}
|
|
|
|
- (BOOL)hasThreadRoot
|
|
{
|
|
if (!RiotSettings.shared.enableThreads)
|
|
{
|
|
// do not consider this cell data if threads not enabled in the timeline
|
|
return NO;
|
|
}
|
|
|
|
if (roomDataSource.threadId)
|
|
{
|
|
// do not consider this cell data if in a thread view
|
|
return NO;
|
|
}
|
|
|
|
return super.hasThreadRoot;
|
|
}
|
|
|
|
- (BOOL)mergeWithBubbleCellData:(id<MXKRoomBubbleCellDataStoring>)bubbleCellData
|
|
{
|
|
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
|
|
if (NO == [timelineConfiguration.currentStyle canMergeWithCellData:bubbleCellData into:self]) {
|
|
return NO;
|
|
}
|
|
|
|
return [super mergeWithBubbleCellData:bubbleCellData];
|
|
}
|
|
|
|
#pragma mark - Bubble collapsing
|
|
|
|
- (BOOL)collapseWith:(id<MXKRoomBubbleCellDataStoring>)cellData
|
|
{
|
|
if (self.tag == RoomBubbleCellDataTagMembership
|
|
&& cellData.tag == RoomBubbleCellDataTagMembership)
|
|
{
|
|
// For now, do not merge VoIP conference events
|
|
if (![MXCallManager isConferenceUser:cellData.events.firstObject.stateKey])
|
|
{
|
|
// Keep a pagination between events of different days
|
|
NSString *bubbleDateString = [roomDataSource.eventFormatter dateStringFromDate:self.date withTime:NO];
|
|
NSString *eventDateString = [roomDataSource.eventFormatter dateStringFromDate:((RoomBubbleCellData*)cellData).date withTime:NO];
|
|
if (bubbleDateString && eventDateString && [bubbleDateString isEqualToString:eventDateString])
|
|
{
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
else if (self.tag == RoomBubbleCellDataTagRoomCreateConfiguration && cellData.tag == RoomBubbleCellDataTagRoomCreateConfiguration)
|
|
{
|
|
return YES;
|
|
}
|
|
else if (self.tag == RoomBubbleCellDataTagCall && cellData.tag == RoomBubbleCellDataTagCall)
|
|
{
|
|
// Check if the same call
|
|
MXEvent * event1 = self.events.firstObject;
|
|
MXCallEventContent *eventContent1 = [MXCallEventContent modelFromJSON:event1.content];
|
|
|
|
MXEvent * event2 = cellData.events.firstObject;
|
|
MXCallEventContent *eventContent2 = [MXCallEventContent modelFromJSON:event2.content];
|
|
|
|
return [eventContent1.callId isEqualToString:eventContent2.callId];
|
|
}
|
|
|
|
if (self.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor || cellData.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor)
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
return [super collapseWith:cellData];
|
|
}
|
|
|
|
- (void)setCollapsed:(BOOL)collapsed
|
|
{
|
|
if (collapsed != self.collapsed)
|
|
{
|
|
super.collapsed = collapsed;
|
|
|
|
// Refresh only cells series header
|
|
if (self.collapsedAttributedTextMessage && self.nextCollapsableCellData)
|
|
{
|
|
[self invalidateTextLayout];
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)invalidateLayout
|
|
{
|
|
[self invalidateTextLayout];
|
|
[self setNeedsUpdateAdditionalContentHeight];
|
|
}
|
|
|
|
- (void)buildAttributedString
|
|
{
|
|
// CAUTION: This method must be called on the main thread.
|
|
|
|
// Return the collapsed string only for cells series header
|
|
if (self.collapsed && self.collapsedAttributedTextMessage && self.nextCollapsableCellData)
|
|
{
|
|
NSAttributedString *attributedString = super.collapsedAttributedTextMessage;
|
|
|
|
self.attributedTextMessage = attributedString;
|
|
self.attributedTextMessageWithoutPositioningSpace = attributedString;
|
|
|
|
return;
|
|
}
|
|
|
|
NSMutableAttributedString *currentAttributedTextMsg;
|
|
|
|
NSMutableAttributedString *currentAttributedTextMsgWithoutVertSpace = [NSMutableAttributedString new];
|
|
|
|
NSInteger selectedComponentIndex = self.selectedComponentIndex;
|
|
NSInteger lastMessageIndex = self.containsLastMessage ? self.mostRecentComponentIndex : NSNotFound;
|
|
|
|
MXKRoomBubbleComponent *component;
|
|
NSAttributedString *componentString;
|
|
NSUInteger index = 0;
|
|
for (; index < bubbleComponents.count; index++)
|
|
{
|
|
component = bubbleComponents[index];
|
|
componentString = component.attributedTextMessage;
|
|
|
|
if (componentString)
|
|
{
|
|
// Check whether another component than this one is selected
|
|
// Note: When a component is selected, it is highlighted by applying an alpha on other components.
|
|
if (selectedComponentIndex != NSNotFound && selectedComponentIndex != index && componentString.length)
|
|
{
|
|
// Apply alpha to blur this component
|
|
componentString = [componentString withTextColorAlpha:.2];
|
|
if (@available(iOS 15.0, *)) {
|
|
[PillsFormatter setPillAlpha:.2 inAttributedString:componentString];
|
|
}
|
|
}
|
|
else if (@available(iOS 15.0, *))
|
|
{
|
|
// PillTextAttachment are not created again every time, we have to set alpha back to standard if needed.
|
|
[PillsFormatter setPillAlpha:1.f inAttributedString:componentString];
|
|
}
|
|
|
|
// Check whether the timestamp is displayed for this component, and check whether a vertical whitespace is required
|
|
if (((selectedComponentIndex == index && self.addVerticalWhitespaceForSelectedComponentTimestamp) || lastMessageIndex == index) && (self.shouldHideSenderInformation || self.shouldHideSenderName))
|
|
{
|
|
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:[RoomBubbleCellData timestampVerticalWhitespace]];
|
|
[currentAttributedTextMsg appendAttributedString:componentString];
|
|
|
|
[currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString];
|
|
}
|
|
else
|
|
{
|
|
// Init attributed string with the first text component
|
|
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:componentString];
|
|
|
|
[currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString];
|
|
}
|
|
|
|
[self addVerticalWhitespaceToString:currentAttributedTextMsg forEvent:component.event.eventId];
|
|
|
|
// The first non empty component has been handled.
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (index++; index < bubbleComponents.count; index++)
|
|
{
|
|
component = bubbleComponents[index];
|
|
componentString = component.attributedTextMessage;
|
|
|
|
if (componentString)
|
|
{
|
|
[currentAttributedTextMsg appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
|
|
|
// Check whether another component than this one is selected
|
|
if (selectedComponentIndex != NSNotFound && selectedComponentIndex != index && componentString.length)
|
|
{
|
|
// Apply alpha to blur this component
|
|
componentString = [componentString withTextColorAlpha:.2];
|
|
if (@available(iOS 15.0, *)) {
|
|
[PillsFormatter setPillAlpha:.2 inAttributedString:componentString];
|
|
}
|
|
}
|
|
else if (@available(iOS 15.0, *))
|
|
{
|
|
// PillTextAttachment are not created again every time, we have to set alpha back to standard if needed.
|
|
[PillsFormatter setPillAlpha:1.f inAttributedString:componentString];
|
|
}
|
|
|
|
// Check whether the timestamp is displayed
|
|
if ((selectedComponentIndex == index && self.addVerticalWhitespaceForSelectedComponentTimestamp) || lastMessageIndex == index)
|
|
{
|
|
[currentAttributedTextMsg appendAttributedString:[RoomBubbleCellData timestampVerticalWhitespace]];
|
|
}
|
|
|
|
// Append attributed text
|
|
[currentAttributedTextMsg appendAttributedString:componentString];
|
|
|
|
[self addVerticalWhitespaceToString:currentAttributedTextMsg forEvent:component.event.eventId];
|
|
|
|
[currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString];
|
|
}
|
|
}
|
|
|
|
// With bubbles the text is truncated with quote messages containing vertical border view
|
|
// Add horizontal space to fix the issue
|
|
if (self.displayFix & MXKRoomBubbleComponentDisplayFixHtmlBlockquote)
|
|
{
|
|
[currentAttributedTextMsgWithoutVertSpace appendString:@" "];
|
|
}
|
|
|
|
self.attributedTextMessage = currentAttributedTextMsg;
|
|
|
|
self.attributedTextMessageWithoutPositioningSpace = currentAttributedTextMsgWithoutVertSpace;
|
|
}
|
|
|
|
- (void)buildAttributedStringIfNeeded
|
|
{
|
|
@synchronized(bubbleComponents)
|
|
{
|
|
if (self.hasAttributedTextMessage && !attributedTextMessage.length)
|
|
{
|
|
// Attributed text message depends on the room read receipts which must be retrieved on the main thread to prevent us from race conditions.
|
|
// Check here the current thread, this is just a sanity check because the attributed text message
|
|
// is requested during the rendering step which takes place on the main thread.
|
|
if ([NSThread currentThread] != [NSThread mainThread])
|
|
{
|
|
MXLogDebug(@"[RoomBubbleCellData] attributedTextMessage called on wrong thread");
|
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
[self buildAttributedString];
|
|
});
|
|
}
|
|
else
|
|
{
|
|
[self buildAttributedString];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSInteger)firstVisibleComponentIndex
|
|
{
|
|
__block NSInteger firstVisibleComponentIndex = NSNotFound;
|
|
|
|
BOOL isPoll = (self.events.firstObject.eventType == MXEventTypePollStart);
|
|
|
|
if ((isPoll || self.attachment) && self.bubbleComponents.count)
|
|
{
|
|
firstVisibleComponentIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
[self.bubbleComponents enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
|
|
MXKRoomBubbleComponent *component = (MXKRoomBubbleComponent*)obj;
|
|
|
|
if (component.attributedTextMessage)
|
|
{
|
|
firstVisibleComponentIndex = idx;
|
|
*stop = YES;
|
|
}
|
|
}];
|
|
}
|
|
|
|
return firstVisibleComponentIndex;
|
|
}
|
|
|
|
- (void)refreshBubbleComponentsPosition
|
|
{
|
|
// CAUTION: This method must be called on the main thread.
|
|
|
|
@synchronized(bubbleComponents)
|
|
{
|
|
NSInteger bubbleComponentsCount = bubbleComponents.count;
|
|
|
|
// Check whether there is at least one component.
|
|
if (bubbleComponentsCount)
|
|
{
|
|
// Set position of the first component
|
|
CGFloat positionY = (self.attachment == nil || self.attachment.type == MXKAttachmentTypeFile || self.attachment.type == MXKAttachmentTypeAudio) ? MXKROOMBUBBLECELLDATA_TEXTVIEW_DEFAULT_VERTICAL_INSET : 0;
|
|
MXKRoomBubbleComponent *component;
|
|
NSUInteger index = 0;
|
|
|
|
// Use same position for first components without render (redacted)
|
|
for (; index < bubbleComponentsCount; index++)
|
|
{
|
|
// Compute the vertical position for next component
|
|
component = bubbleComponents[index];
|
|
|
|
component.position = CGPointMake(0, positionY);
|
|
|
|
if (component.attributedTextMessage)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check whether the position of other components need to be refreshed
|
|
if (!self.attachment && index < bubbleComponentsCount)
|
|
{
|
|
NSMutableAttributedString *attributedString = [NSMutableAttributedString new];
|
|
NSInteger selectedComponentIndex = self.selectedComponentIndex;
|
|
NSInteger lastMessageIndex = self.containsLastMessage ? self.mostRecentComponentIndex : NSNotFound;
|
|
NSInteger visibleMessageIndex = 0;
|
|
|
|
for (; index < bubbleComponentsCount; index++)
|
|
{
|
|
// Compute the vertical position for next component
|
|
component = bubbleComponents[index];
|
|
|
|
if (component.attributedTextMessage)
|
|
{
|
|
// Prepare its attributed string by considering potential vertical margin required to display timestamp.
|
|
NSAttributedString *componentString = component.attributedTextMessage;
|
|
|
|
// Check whether the timestamp is displayed for this component, and check whether a vertical whitespace is required
|
|
|
|
if (((selectedComponentIndex == index && self.addVerticalWhitespaceForSelectedComponentTimestamp) || lastMessageIndex == index)
|
|
&& !(visibleMessageIndex == 0 && !(self.shouldHideSenderInformation || self.shouldHideSenderName)))
|
|
{
|
|
[attributedString appendAttributedString:[RoomBubbleCellData timestampVerticalWhitespace]];
|
|
}
|
|
|
|
// Append this attributed string.
|
|
[attributedString appendAttributedString:componentString];
|
|
|
|
// Compute the height of the resulting string.
|
|
CGFloat cumulatedHeight = [self rawTextHeight:attributedString];
|
|
|
|
// Deduce the position of the beginning of this component.
|
|
positionY = MXKROOMBUBBLECELLDATA_TEXTVIEW_DEFAULT_VERTICAL_INSET + (cumulatedHeight - [self rawTextHeight:componentString]);
|
|
|
|
component.position = CGPointMake(0, positionY);
|
|
|
|
// Vertical whitespace is added in case of read receipts or reactions
|
|
[self addVerticalWhitespaceToString:attributedString forEvent:component.event.eventId];
|
|
|
|
[attributedString appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
|
|
|
visibleMessageIndex++;
|
|
}
|
|
else
|
|
{
|
|
component.position = CGPointMake(0, positionY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)addVerticalWhitespaceToString:(NSMutableAttributedString *)attributedString forEvent:(NSString *)eventId
|
|
{
|
|
CGFloat additionalVerticalHeight = 0;
|
|
|
|
// Add vertical whitespace in case of a url preview.
|
|
additionalVerticalHeight+= [self urlPreviewHeightForEventId:eventId];
|
|
// Add vertical whitespace in case of reactions.
|
|
additionalVerticalHeight+= [self reactionHeightForEventId:eventId];
|
|
// Add vertical whitespace in case of a thread root
|
|
additionalVerticalHeight+= [self threadSummaryViewHeightForEventId:eventId];
|
|
// Add vertical whitespace in case of from a thread
|
|
additionalVerticalHeight+= [self fromAThreadViewHeightForEventId:eventId];
|
|
// Add vertical whitespace in case of read receipts.
|
|
additionalVerticalHeight+= [self readReceiptHeightForEventId:eventId];
|
|
|
|
if (additionalVerticalHeight)
|
|
{
|
|
[attributedString appendAttributedString:[RoomBubbleCellData verticalWhitespaceForHeight: additionalVerticalHeight]];
|
|
}
|
|
}
|
|
|
|
- (CGFloat)computeAdditionalHeight
|
|
{
|
|
CGFloat height = 0;
|
|
|
|
for (MXKRoomBubbleComponent *bubbleComponent in self.bubbleComponents)
|
|
{
|
|
NSString *eventId = bubbleComponent.event.eventId;
|
|
|
|
height+= [self urlPreviewHeightForEventId:eventId];
|
|
height+= [self reactionHeightForEventId:eventId];
|
|
height+= [self threadSummaryViewHeightForEventId:eventId];
|
|
height+= [self fromAThreadViewHeightForEventId:eventId];
|
|
height+= [self readReceiptHeightForEventId:eventId];
|
|
}
|
|
|
|
return height;
|
|
}
|
|
|
|
- (void)updateAdditionalContentHeightIfNeeded;
|
|
{
|
|
if (self.shouldUpdateAdditionalContentHeight)
|
|
{
|
|
void(^updateAdditionalHeight)(void) = ^() {
|
|
self.additionalContentHeight = [self computeAdditionalHeight];
|
|
};
|
|
|
|
// The additional height depends on the room read receipts and reactions view which must be calculated on the main thread.
|
|
// Check here the current thread, this is just a sanity check because this method is called during the rendering step
|
|
// which takes place on the main thread.
|
|
if ([NSThread currentThread] != [NSThread mainThread])
|
|
{
|
|
MXLogDebug(@"[RoomBubbleCellData] prepareBubbleComponentsPosition called on wrong thread");
|
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
updateAdditionalHeight();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
updateAdditionalHeight();
|
|
}
|
|
|
|
self.shouldUpdateAdditionalContentHeight = NO;
|
|
}
|
|
}
|
|
|
|
- (void)setNeedsUpdateAdditionalContentHeight
|
|
{
|
|
self.shouldUpdateAdditionalContentHeight = YES;
|
|
}
|
|
|
|
- (CGFloat)threadSummaryViewHeightForEventId:(NSString*)eventId
|
|
{
|
|
if (!RiotSettings.shared.enableThreads)
|
|
{
|
|
// do not show thread summary view if threads not enabled in the timeline
|
|
return 0;
|
|
}
|
|
if (roomDataSource.threadId)
|
|
{
|
|
// do not show thread summary view on threads
|
|
return 0;
|
|
}
|
|
NSInteger index = [self bubbleComponentIndexForEventId:eventId];
|
|
if (index == NSNotFound)
|
|
{
|
|
return 0;
|
|
}
|
|
MXKRoomBubbleComponent *component = self.bubbleComponents[index];
|
|
if (!component.thread)
|
|
{
|
|
// component is not a thread root
|
|
return 0;
|
|
}
|
|
return PlainRoomCellLayoutConstants.threadSummaryViewTopMargin +
|
|
[ThreadSummaryView contentViewHeightForThread:component.thread fitting:self.maxTextViewWidth];
|
|
}
|
|
|
|
- (CGFloat)fromAThreadViewHeightForEventId:(NSString*)eventId
|
|
{
|
|
if (!RiotSettings.shared.enableThreads)
|
|
{
|
|
// do not show from a thread view if threads not enabled
|
|
return 0;
|
|
}
|
|
if (roomDataSource.threadId)
|
|
{
|
|
// do not show from a thread view on threads
|
|
return 0;
|
|
}
|
|
NSInteger index = [self bubbleComponentIndexForEventId:eventId];
|
|
if (index == NSNotFound)
|
|
{
|
|
return 0;
|
|
}
|
|
MXKRoomBubbleComponent *component = self.bubbleComponents[index];
|
|
if (!component.event.isInThread)
|
|
{
|
|
// event is not in a thread
|
|
return 0;
|
|
}
|
|
return PlainRoomCellLayoutConstants.fromAThreadViewTopMargin +
|
|
[FromAThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth];
|
|
}
|
|
|
|
- (CGFloat)urlPreviewHeightForEventId:(NSString*)eventId
|
|
{
|
|
MXKRoomBubbleComponent *component = [self bubbleComponentWithLinkForEventId:eventId];
|
|
if (!component.showURLPreview)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return PlainRoomCellLayoutConstants.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:component.urlPreviewData
|
|
fitting:self.maxTextViewWidth];
|
|
}
|
|
|
|
- (CGFloat)reactionHeightForEventId:(NSString*)eventId
|
|
{
|
|
CGFloat height = 0;
|
|
|
|
NSUInteger reactionCount = self.reactions[eventId].reactions.count;
|
|
|
|
MXAggregatedReactions *aggregatedReactions = self.reactions[eventId];
|
|
|
|
if (reactionCount)
|
|
{
|
|
CGFloat reactionsViewWidth = self.maxTextViewWidth - 4;
|
|
|
|
static RoomReactionsViewSizer *reactionsViewSizer;
|
|
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
reactionsViewSizer = [RoomReactionsViewSizer new];
|
|
});
|
|
|
|
BOOL showAllReactions = [self.eventsToShowAllReactions containsObject:eventId];
|
|
RoomReactionsViewModel *viewModel = [[RoomReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId showAll:showAllReactions];
|
|
height = [reactionsViewSizer heightForViewModel:viewModel fittingWidth:reactionsViewWidth] + PlainRoomCellLayoutConstants.reactionsViewTopMargin;
|
|
}
|
|
|
|
return height;
|
|
}
|
|
|
|
- (CGFloat)readReceiptHeightForEventId:(NSString*)eventId
|
|
{
|
|
CGFloat height = 0;
|
|
|
|
if (self.readReceipts[eventId].count)
|
|
{
|
|
height = PlainRoomCellLayoutConstants.readReceiptsViewHeight + PlainRoomCellLayoutConstants.readReceiptsViewTopMargin;
|
|
}
|
|
|
|
return height;
|
|
}
|
|
|
|
- (void)setContainsLastMessage:(BOOL)containsLastMessage
|
|
{
|
|
// Check whether there is something to do
|
|
if (_containsLastMessage || containsLastMessage)
|
|
{
|
|
// Update flag
|
|
_containsLastMessage = containsLastMessage;
|
|
|
|
// Indicate that the text message layout should be recomputed.
|
|
[self invalidateTextLayout];
|
|
}
|
|
}
|
|
|
|
- (void)setSelectedEventId:(NSString *)selectedEventId
|
|
{
|
|
// Check whether there is something to do
|
|
if (_selectedEventId || selectedEventId.length)
|
|
{
|
|
// Update flag
|
|
_selectedEventId = selectedEventId;
|
|
|
|
// Indicate that the text message layout should be recomputed.
|
|
[self invalidateTextLayout];
|
|
}
|
|
}
|
|
|
|
- (NSInteger)oldestComponentIndex
|
|
{
|
|
// Update the related component index
|
|
NSInteger oldestComponentIndex = NSNotFound;
|
|
|
|
NSArray *components = self.bubbleComponents;
|
|
NSInteger index = 0;
|
|
while (index < components.count)
|
|
{
|
|
MXKRoomBubbleComponent *component = components[index];
|
|
if (component.attributedTextMessage && component.date)
|
|
{
|
|
oldestComponentIndex = index;
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
return oldestComponentIndex;
|
|
}
|
|
|
|
- (NSInteger)mostRecentComponentIndex
|
|
{
|
|
// Update the related component index
|
|
NSInteger mostRecentComponentIndex = NSNotFound;
|
|
|
|
NSArray *components = self.bubbleComponents;
|
|
NSInteger index = components.count;
|
|
while (index--)
|
|
{
|
|
MXKRoomBubbleComponent *component = components[index];
|
|
if (component.attributedTextMessage && component.date)
|
|
{
|
|
mostRecentComponentIndex = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return mostRecentComponentIndex;
|
|
}
|
|
|
|
- (NSInteger)selectedComponentIndex
|
|
{
|
|
// Update the related component index
|
|
NSInteger selectedComponentIndex = NSNotFound;
|
|
|
|
if (_selectedEventId)
|
|
{
|
|
NSArray *components = self.bubbleComponents;
|
|
NSInteger index = components.count;
|
|
while (index--)
|
|
{
|
|
MXKRoomBubbleComponent *component = components[index];
|
|
if ([component.event.eventId isEqualToString:_selectedEventId])
|
|
{
|
|
selectedComponentIndex = index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return selectedComponentIndex;
|
|
}
|
|
|
|
- (MXKRoomBubbleComponent *)bubbleComponentWithLinkForEventId:(NSString *)eventId
|
|
{
|
|
NSInteger index = [self bubbleComponentIndexForEventId:eventId];
|
|
if (index == NSNotFound)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
MXKRoomBubbleComponent *component = self.bubbleComponents[index];
|
|
if (!component.link)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
return component;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
+ (NSAttributedString *)timestampVerticalWhitespace
|
|
{
|
|
@synchronized(self)
|
|
{
|
|
if (timestampVerticalWhitespace == nil)
|
|
{
|
|
timestampVerticalWhitespace = [[NSAttributedString alloc] initWithString:@"\n" attributes:@{NSForegroundColorAttributeName : [UIColor blackColor],
|
|
NSFontAttributeName: [UIFont systemFontOfSize:12]}];
|
|
}
|
|
}
|
|
return timestampVerticalWhitespace;
|
|
}
|
|
|
|
+ (NSAttributedString *)verticalWhitespaceForHeight:(CGFloat)height
|
|
{
|
|
UIFont *sizingFont = [UIFont systemFontOfSize:2];
|
|
CGFloat returnHeight = sizingFont.lineHeight;
|
|
|
|
NSUInteger returns = (NSUInteger)round(height/returnHeight);
|
|
NSMutableString *returnString = [NSMutableString string];
|
|
|
|
for (NSUInteger i = 0; i < returns; i++)
|
|
{
|
|
[returnString appendString:@"\n"];
|
|
}
|
|
|
|
return [[NSAttributedString alloc] initWithString:returnString attributes:@{NSForegroundColorAttributeName : [UIColor blackColor],
|
|
NSFontAttributeName: sizingFont}];
|
|
}
|
|
|
|
- (BOOL)hasSameSenderAsBubbleCellData:(id<MXKRoomBubbleCellDataStoring>)bubbleCellData
|
|
{
|
|
if (self.tag == RoomBubbleCellDataTagMembership || bubbleCellData.tag == RoomBubbleCellDataTagMembership)
|
|
{
|
|
// We do not want to merge membership event cells with other cell types
|
|
return NO;
|
|
}
|
|
|
|
if (self.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor || bubbleCellData.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor)
|
|
{
|
|
// We do not want to merge room create event cells with other cell types
|
|
return NO;
|
|
}
|
|
|
|
if (self.hasThreadRoot || bubbleCellData.hasThreadRoot)
|
|
{
|
|
// We do not want to merge events containing thread roots
|
|
return NO;
|
|
}
|
|
|
|
return [super hasSameSenderAsBubbleCellData:bubbleCellData];
|
|
}
|
|
|
|
- (BOOL)addEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState
|
|
{
|
|
if (self.hasThreadRoot)
|
|
{
|
|
// We don't want to add any events into this bubble data if it's a thread root
|
|
return NO;
|
|
}
|
|
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
|
|
|
|
if (NO == [timelineConfiguration.currentStyle canAddEvent:event and:roomState to:self]) {
|
|
return NO;
|
|
}
|
|
|
|
BOOL shouldAddEvent = YES;
|
|
|
|
switch (self.tag)
|
|
{
|
|
case RoomBubbleCellDataTagKeyVerificationNoDisplay:
|
|
case RoomBubbleCellDataTagKeyVerificationRequest:
|
|
case RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval:
|
|
case RoomBubbleCellDataTagKeyVerificationConclusion:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagRoomCreateWithPredecessor:
|
|
// We do not want to merge room create event cells with other cell types
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagMembership:
|
|
// One single bubble per membership event
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagCall:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagGroupCall:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagRoomCreateConfiguration:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagRoomCreationIntro:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagPoll:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagLocation:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagLiveLocation:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagVoiceBroadcast:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// If the current bubbleData supports adding events then check
|
|
// if the incoming event can be added in
|
|
if (shouldAddEvent)
|
|
{
|
|
switch (event.eventType)
|
|
{
|
|
case MXEventTypeRoomMessage:
|
|
{
|
|
if (event.location) {
|
|
shouldAddEvent = NO;
|
|
break;
|
|
}
|
|
|
|
NSString *messageType = event.content[kMXMessageTypeKey];
|
|
|
|
if ([messageType isEqualToString:kMXMessageTypeKeyVerificationRequest])
|
|
{
|
|
shouldAddEvent = NO;
|
|
}
|
|
break;
|
|
}
|
|
case MXEventTypeKeyVerificationStart:
|
|
case MXEventTypeKeyVerificationAccept:
|
|
case MXEventTypeKeyVerificationKey:
|
|
case MXEventTypeKeyVerificationMac:
|
|
case MXEventTypeKeyVerificationDone:
|
|
case MXEventTypeKeyVerificationCancel:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case MXEventTypeRoomMember:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case MXEventTypeRoomCreate:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case MXEventTypeRoomTopic:
|
|
case MXEventTypeRoomName:
|
|
case MXEventTypeRoomEncryption:
|
|
case MXEventTypeRoomHistoryVisibility:
|
|
case MXEventTypeRoomGuestAccess:
|
|
case MXEventTypeRoomAvatar:
|
|
case MXEventTypeRoomJoinRules:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case MXEventTypeCallInvite:
|
|
case MXEventTypeCallAnswer:
|
|
case MXEventTypeCallHangup:
|
|
case MXEventTypeCallReject:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case MXEventTypePollStart:
|
|
shouldAddEvent = NO;
|
|
break;
|
|
case MXEventTypeCustom:
|
|
{
|
|
if ([event.type isEqualToString:kWidgetMatrixEventTypeString]
|
|
|| [event.type isEqualToString:kWidgetModularEventTypeString])
|
|
{
|
|
Widget *widget = [[Widget alloc] initWithWidgetEvent:event inMatrixSession:roomDataSource.mxSession];
|
|
if ([widget.type isEqualToString:kWidgetTypeJitsiV1] ||
|
|
[widget.type isEqualToString:kWidgetTypeJitsiV2])
|
|
{
|
|
shouldAddEvent = NO;
|
|
}
|
|
} else if ([event.type isEqualToString:VoiceBroadcastSettings.eventType]) {
|
|
shouldAddEvent = NO;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (shouldAddEvent)
|
|
{
|
|
shouldAddEvent = [super addEvent:event andRoomState:roomState];
|
|
|
|
// If the event was added, load any url preview data if necessary.
|
|
if (shouldAddEvent)
|
|
{
|
|
[self refreshURLPreviewForEventId:event.eventId];
|
|
}
|
|
}
|
|
|
|
return shouldAddEvent;
|
|
}
|
|
|
|
- (void)setKeyVerification:(MXKeyVerification *)keyVerification
|
|
{
|
|
_keyVerification = keyVerification;
|
|
|
|
[self keyVerificationDidUpdate];
|
|
}
|
|
|
|
- (void)keyVerificationDidUpdate
|
|
{
|
|
MXEvent *event = self.getFirstBubbleComponentWithDisplay.event;
|
|
MXKeyVerification *keyVerification = _keyVerification;
|
|
|
|
if (!event)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (event.eventType)
|
|
{
|
|
case MXEventTypeKeyVerificationCancel:
|
|
{
|
|
RoomBubbleCellDataTag cellDataTag;
|
|
|
|
MXTransactionCancelCode *transactionCancelCode = keyVerification.transaction.reasonCancelCode;
|
|
|
|
if (transactionCancelCode
|
|
&& ([transactionCancelCode isEqual:[MXTransactionCancelCode mismatchedSas]]
|
|
|| [transactionCancelCode isEqual:[MXTransactionCancelCode mismatchedKeys]]
|
|
|| [transactionCancelCode isEqual:[MXTransactionCancelCode mismatchedCommitment]]
|
|
)
|
|
)
|
|
{
|
|
cellDataTag = RoomBubbleCellDataTagKeyVerificationConclusion;
|
|
}
|
|
else
|
|
{
|
|
cellDataTag = RoomBubbleCellDataTagKeyVerificationNoDisplay;
|
|
}
|
|
|
|
self.tag = cellDataTag;
|
|
}
|
|
break;
|
|
case MXEventTypeKeyVerificationDone:
|
|
{
|
|
RoomBubbleCellDataTag cellDataTag;
|
|
|
|
// Avoid to display incoming and outgoing done, only display the incoming one.
|
|
if (self.isIncoming && keyVerification && (keyVerification.state == MXKeyVerificationStateVerified))
|
|
{
|
|
cellDataTag = RoomBubbleCellDataTagKeyVerificationConclusion;
|
|
}
|
|
else
|
|
{
|
|
cellDataTag = RoomBubbleCellDataTagKeyVerificationNoDisplay;
|
|
}
|
|
|
|
self.tag = cellDataTag;
|
|
}
|
|
break;
|
|
case MXEventTypeRoomMessage:
|
|
{
|
|
NSString *msgType = event.content[kMXMessageTypeKey];
|
|
|
|
if ([msgType isEqualToString:kMXMessageTypeKeyVerificationRequest])
|
|
{
|
|
RoomBubbleCellDataTag cellDataTag;
|
|
|
|
if (self.isIncoming && !self.isKeyVerificationOperationPending && keyVerification && keyVerification.state == MXKeyVerificationRequestStatePending)
|
|
{
|
|
cellDataTag = RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval;
|
|
}
|
|
else
|
|
{
|
|
cellDataTag = RoomBubbleCellDataTagKeyVerificationRequest;
|
|
}
|
|
|
|
self.tag = cellDataTag;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
#pragma mark - Show all reactions
|
|
|
|
- (BOOL)showAllReactionsForEvent:(NSString*)eventId
|
|
{
|
|
return [self.eventsToShowAllReactions containsObject:eventId];
|
|
}
|
|
|
|
- (void)setShowAllReactions:(BOOL)showAllReactions forEvent:(NSString*)eventId
|
|
{
|
|
if (showAllReactions)
|
|
{
|
|
[self.eventsToShowAllReactions addObject:eventId];
|
|
}
|
|
else
|
|
{
|
|
[self.eventsToShowAllReactions removeObject:eventId];
|
|
}
|
|
}
|
|
|
|
- (NSString *)accessibilityLabel
|
|
{
|
|
NSString *accessibilityLabel;
|
|
|
|
// Only media require manual handling for accessibility
|
|
if (self.attachment)
|
|
{
|
|
NSString *mediaName = [self accessibilityLabelForAttachmentType:self.attachment.type];
|
|
|
|
MXJSONModelSetString(accessibilityLabel, self.events.firstObject.content[kMXMessageBodyKey]);
|
|
if (accessibilityLabel)
|
|
{
|
|
accessibilityLabel = [NSString stringWithFormat:@"%@ %@", mediaName, accessibilityLabel];
|
|
}
|
|
else
|
|
{
|
|
accessibilityLabel = mediaName;
|
|
}
|
|
}
|
|
|
|
return accessibilityLabel;
|
|
}
|
|
|
|
- (NSString*)accessibilityLabelForAttachmentType:(MXKAttachmentType)attachmentType
|
|
{
|
|
NSString *accessibilityLabel;
|
|
switch (attachmentType)
|
|
{
|
|
case MXKAttachmentTypeImage:
|
|
accessibilityLabel = [VectorL10n mediaTypeAccessibilityImage];
|
|
break;
|
|
case MXKAttachmentTypeAudio:
|
|
accessibilityLabel = [VectorL10n mediaTypeAccessibilityAudio];
|
|
break;
|
|
case MXKAttachmentTypeVoiceMessage:
|
|
accessibilityLabel = [VectorL10n mediaTypeAccessibilityAudio];
|
|
break;
|
|
case MXKAttachmentTypeVideo:
|
|
accessibilityLabel = [VectorL10n mediaTypeAccessibilityVideo];
|
|
break;
|
|
case MXKAttachmentTypeFile:
|
|
accessibilityLabel = [VectorL10n mediaTypeAccessibilityFile];
|
|
break;
|
|
case MXKAttachmentTypeSticker:
|
|
accessibilityLabel = [VectorL10n mediaTypeAccessibilitySticker];
|
|
break;
|
|
default:
|
|
accessibilityLabel = @"";
|
|
break;
|
|
}
|
|
|
|
return accessibilityLabel;
|
|
}
|
|
|
|
#pragma mark - URL Previews
|
|
|
|
- (void)refreshURLPreviewForEventId:(NSString *)eventId
|
|
{
|
|
// Get the event's component, but only if it has a link.
|
|
MXKRoomBubbleComponent *component = [self bubbleComponentWithLinkForEventId:eventId];
|
|
if (!component)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Don't show the preview if they're disabled globally or this one has been dismissed previously.
|
|
component.showURLPreview = RiotSettings.shared.roomScreenShowsURLPreviews && [URLPreviewService.shared shouldShowPreviewFor:component.event];
|
|
if (!component.showURLPreview)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If there is existing preview data, the message has been edited.
|
|
// Clear the data to show the loading state when the preview isn't cached.
|
|
if (component.urlPreviewData)
|
|
{
|
|
component.urlPreviewData = nil;
|
|
}
|
|
|
|
// Set the preview data.
|
|
MXWeakify(self);
|
|
|
|
NSDictionary<NSString *, NSString*> *userInfo = @{
|
|
@"eventId": eventId,
|
|
@"roomId": self.roomId
|
|
};
|
|
|
|
[URLPreviewService.shared previewFor:component.link
|
|
and:component.event
|
|
with:self.mxSession
|
|
success:^(URLPreviewData * _Nonnull urlPreviewData) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
// Update the preview data, indicate that the message layout needs refreshing and send a notification for refresh
|
|
component.urlPreviewData = urlPreviewData;
|
|
[self invalidateLayout];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[NSNotificationCenter.defaultCenter postNotificationName:URLPreviewDidUpdateNotification object:nil userInfo:userInfo];
|
|
});
|
|
|
|
} failure:^(NSError * _Nullable error) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
MXLogDebug(@"[RoomBubbleCellData] Failed to get url preview")
|
|
|
|
// Remove the loading URLPreviewView, indicate that the layout needs refreshing and send a notification for refresh
|
|
component.showURLPreview = NO;
|
|
[self invalidateLayout];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[NSNotificationCenter.defaultCenter postNotificationName:URLPreviewDidUpdateNotification object:nil userInfo:userInfo];
|
|
});
|
|
}];
|
|
}
|
|
|
|
- (void)updateBeaconInfoSummaryWithId:(NSString *)eventId andEvent:(MXEvent*)event
|
|
{
|
|
if (event.eventType != MXEventTypeBeaconInfo)
|
|
{
|
|
MXLogErrorDetails(@"[RoomBubbleCellData] Try to update beacon info summary with wrong event type", @{
|
|
@"event_id": eventId ?: @"unknown"
|
|
});
|
|
return;
|
|
}
|
|
|
|
id<MXBeaconInfoSummaryProtocol> beaconInfoSummary = [self.mxSession.aggregations.beaconAggregations beaconInfoSummaryFor:eventId inRoomWithId:self.roomId];
|
|
|
|
if (!beaconInfoSummary)
|
|
{
|
|
MXBeaconInfo *beaconInfo = [[MXBeaconInfo alloc] initWithMXEvent:event];
|
|
|
|
// A start beacon info event (isLive == true) should have an associated BeaconInfoSummary
|
|
if (beaconInfo && beaconInfo.isLive)
|
|
{
|
|
MXLogErrorDetails(@"[RoomBubbleCellData] No beacon info summary found for beacon info start event", @{
|
|
@"event_id": eventId ?: @"unknown"
|
|
});
|
|
}
|
|
}
|
|
|
|
self.beaconInfoSummary = beaconInfoSummary;
|
|
}
|
|
|
|
@end
|