mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-21 17:12:45 +02:00
2cf68dd262
* 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 * 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 (#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 * Updated templates readme.md file * Add private var for avatar menu * Cleanup createAvatarButtonItem method * Add multiple fallbacks in AvatarViewDataProtocol * Changelog * Prepare for new sprint * Add changelog.d file * Remove space * Init voice broadcast playing service * Add some comments * Add chunks in TimelineVoiceBroadcastDetails * Check user id to prevent fake ckunk * Rename TimelineVoiceBroadcastCoordinator to controller It has nothing todo with a coordinator. Start to follow the same naming as VoiceMessage. Remove SwiftUI VoiceBroadcastChunk to make it build * Removed VoiceBroadcastProtocol We do not need to abstract it * Simplify TimelineVoiceBroadcastDetails struct * Rename some existing voice broadcast files to VoiceBroadcastPlayback Record will happen in separate files * Renamed back to VoiceBroadcastPlaybackCoordinator The logic will be moved to the view model. This file will just serve the SwiftUI view * Fix text view height issue * Add changelog.d file * Aggregate chunks in voice broacast * VB: Move view logic to the view model * Add device_id and record tag * VB: Playback starts to work but only the first chunk if it is ogg * Translated using Weblate (Hungarian) 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/hu/ * updated the package * Remove clips to bounds for text views inside bubbles * Improve http url interaction ux * Edit mode * Add changelog.d file * VB: Improve playback states * added placeholder to the viewModel * Expose better broadcast details to the view Starting from the sender name but we can add more things. This is up to the design expectation * Session selection state * Update the Voice Broadcast Labs flag description * Device-to-device verification * rich text composer placeholder text implemented using the same logic of the normal composer * Support mp4 audio file format * added a simple test * improving code * VB: Make the view model aware of every chunk new coming this reactive approach will help to cache and reorder them by sequence * fixing a legacy issue that sometime removed the placeholder * improved old code * improved old code further * - Fix the RoomBubbleCellData tag management (Record/Playback/NoDisplay) - Force the VB display even if the Labs flag is disabled. The Labs flag is only used now to block VB recording and sending - Fix: Release VBService when the user stops the broadcast * VoiceMessageAudioPlayer: Add support of URLs queue playback To be used for voice broadcast * VB: Support multi chunks playback * Display info dialogs when we prevent the user from starting a new voice broadcast - Update the existing implementation used to start/stop a voice broadcast in order to handle the different cases where voice broadcast is denied - Add the optional Voice broadcast action to the new wysiwyg composer * Init voice broadcast playing service * Add some comments * Add chunks in TimelineVoiceBroadcastDetails * Check user id to prevent fake ckunk * Rename TimelineVoiceBroadcastCoordinator to controller It has nothing todo with a coordinator. Start to follow the same naming as VoiceMessage. Remove SwiftUI VoiceBroadcastChunk to make it build * Removed VoiceBroadcastProtocol We do not need to abstract it * Simplify TimelineVoiceBroadcastDetails struct * Rename some existing voice broadcast files to VoiceBroadcastPlayback Record will happen in separate files * Renamed back to VoiceBroadcastPlaybackCoordinator The logic will be moved to the view model. This file will just serve the SwiftUI view * Aggregate chunks in voice broacast * VB: Move view logic to the view model * Add device_id and record tag * VB: Playback starts to work but only the first chunk if it is ogg * VB: Improve playback states * Expose better broadcast details to the view Starting from the sender name but we can add more things. This is up to the design expectation * Update the Voice Broadcast Labs flag description * Support mp4 audio file format * VB: Make the view model aware of every chunk new coming this reactive approach will help to cache and reorder them by sequence * VoiceMessageAudioPlayer: Add support of URLs queue playback To be used for voice broadcast * VB: Support multi chunks playback * - Fix the RoomBubbleCellData tag management (Record/Playback/NoDisplay) - Force the VB display even if the Labs flag is disabled. The Labs flag is only used now to block VB recording and sending - Fix: Release VBService when the user stops the broadcast * Fixes after rebase on develop Update voice broadcast playback UI * Add voice broadcast error view * Remove matrixsdk import * VB: Manage playback completion properly Make VoiceManager audioPlayerDidFinishPlaying called when the last item of the playlist has been played * VB: Introduce VoiceBroadcastState for the UI * Add issue automation for PS features teams * Update issue automation for design Put only high priority issues in front of the design team, all of which the design team will aim to action to keep the queue at zero * Clarify issue automation conditions Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * Removed sections * VB: Started live playback * VB: Support live playback from the beginning or with go live * VB: Own code review * UI fixes * Fix infinite layout loops on timeline (#6942) * Remove `forceZeroSageAreaInsets` from `VectorHostingController` * Fix layout issues when adding hosting views into the content view * Use the new api when adding views into the content * Add changelog * VB: Remove a done TODO * Display live voice broadcast * Fix crash * VB: Fix playLive after pause * Fixes after rebase from develop * VB: Hack to make the project build for SwiftUI tests We need to rework the view model to remove its dependency on MatrixSDK * Update UI * VB: Moved the VM temporary under a MatrixSDK to avoid to use it on the SwiftUI build * the voice message toolbar now appears * First part of the voice broadcast recording feature * Fix missing parts on Voice broadcast recorder service * Update recorder view and content * Add sequence value when sending chunk files * Update recorder service * Fix recorder service for audio node after stopping a record * Fix UI status at record startup and depending on the recording status * Send the last chunk file after stopping or pausing a record * Update recording state after stopping voice broadcast on every cases * BF Ignore redacted voice broadcast state event (their content is empty) * Update first chunk number * Remove temporary code for stopping recording * Update sequence number associated to chunk file sending * Add AAC to M4A converter and now convert chunks before sending them * Remove useless log in VoiceBroadcastRecorderService * Fix a potential crash when trying to send a nil chunk file (in case of stop immediately after pause) * Set voice broadcast recording to pause when the app goes in background and when the RVC will disappear * Enhance RoomBubbleCellData handling - detect correctly an actual live recording - update the tile display at the end of a live recording * Add missing update state after switching to resumed state * Fix API change for VectorHostingController * Update record UI to be in sync with other platforms * Remove useless imports * voice messages implemented * fix * Clean code * Enhance chunk sending mecanism in recorder service * voice message support added to the rich text composer * Select All * fix for tests * new pushed mic asset * Unit tests * should fix the CI UI tests failing * Changelog * reimplemented but the animation and the spacing needs some fixing * fixing view not returning in place * animation * More UI tests * improving anim, however it only works with swiftui build * Code review fixes * minor adjustments * Stop running UI tests on pushes to develop, they already run on PRs * Fixes #6879 - Xcode 14 resource bundle signing errors * Translated using Weblate (German) Currently translated at 100.0% (2307 of 2307 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Persian) Currently translated at 45.1% (1042 of 2307 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/fa/ * Translated using Weblate (Slovak) Currently translated at 100.0% (2307 of 2307 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ * Translated using Weblate (German) Currently translated at 100.0% (2308 of 2308 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.0% (1870 of 2308 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% (2308 of 2308 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2308 of 2308 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% (2308 of 2308 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 100.0% (2308 of 2308 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% (2308 of 2308 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% (2308 of 2308 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% (2308 of 2308 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Translated using Weblate (German) Currently translated at 100.0% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ * Translated using Weblate (Polish) Currently translated at 94.1% (2175 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pl/ * Translated using Weblate (Indonesian) Currently translated at 100.0% (2311 of 2311 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% (2311 of 2311 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% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ * Define MXCrypto and MXCrossSigning as protocols * Translated using Weblate (Ukrainian) Currently translated at 100.0% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ * speeding the animation a bit * tests and identifier improvements * fix * changelog * removed unused code * comment * Curate MXCrypto protocol methods * Complete MXCryptoV2 implementation * Switch the CI to code 14 and the iOS 14 simulator, fix UI tests * Fixes #6987 - Prevent ZXing from unnecessarily requesting camera access * Fixes #6988 - Prevent actor switching when tearing down the rendezvous * add Z-Labs tag or rich text editor and update to the new label naming * changelog * Hide old sessions list when the new dm is enabled * Add changelog.d file * CryptoV2 changes * Display crypto version * Add issue automation for the VoIP team * Fix typo in issue automation * Translations update from Weblate (#7017) * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ * Translated using Weblate (Estonian) Currently translated at 100.0% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ * Translated using Weblate (German) Currently translated at 100.0% (2311 of 2311 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% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/de/ * Translated using Weblate (Dutch) Currently translated at 100.0% (2311 of 2311 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/nl/ Co-authored-by: lvre <7uu3qrbvm@relay.firefox.com> Co-authored-by: Priit Jõerüüt <riot@joeruut.com> Co-authored-by: Vri <element@vrifox.cc> Co-authored-by: Johan Smits <johan@smitsmail.net> * changelog.d: Upgrade MatrixSDK version ([v0.24.2](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.2)). * version++ Co-authored-by: Mauro Romito <mauro.romito@element.io> Co-authored-by: Alfonso Grillo <alfogrillo@element.io> Co-authored-by: David Langley <langley.dave@gmail.com> Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com> Co-authored-by: Hugh Nimmo-Smith <hughns@element.io> Co-authored-by: Aleksandrs Proskurins <paleksandrs@gmail.com> Co-authored-by: Aleksandrs Proskurins <aleksandrsp@element.io> Co-authored-by: Stefan Ceriu <stefanc@matrix.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: 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: Element Translate Bot <admin@riot.im> Co-authored-by: Alfonso Grillo <alfogrillo@gmail.com> Co-authored-by: yostyle <y.pintas@gmail.com> Co-authored-by: manuroe <manu@matrix.org> Co-authored-by: Giom Foret <giom@matrix.org> Co-authored-by: Andy Uhnak <andyuhnak@gmail.com> Co-authored-by: giomfo <gforet@matrix.org> Co-authored-by: Kat Gerasimova <ekaterinag@element.io> Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> Co-authored-by: Doug <douglase@element.io> Co-authored-by: Philippe Loriaux <philippel@element.io> Co-authored-by: manuroe <manuroe@users.noreply.github.com> Co-authored-by: mmehdishafiee <mmhdishafiee@gmail.com> Co-authored-by: Bartosz <barpaw@gmail.com> Co-authored-by: Johan Smits <johan@smitsmail.net> Co-authored-by: gulekismail <ismailgulek0@gmail.com>
1450 lines
51 KiB
Objective-C
1450 lines
51 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.voiceBroadcastInfoContentKeyType])
|
|
{
|
|
VoiceBroadcastInfo *voiceBroadcastInfo = [VoiceBroadcastInfo modelFromJSON: event.content];
|
|
if ([VoiceBroadcastInfo isStartedFor:voiceBroadcastInfo.state])
|
|
{
|
|
// This state event corresponds to the beginning of a voice broadcast
|
|
// Check whether this is a local live broadcast to display it with the recorder view or not
|
|
// Note: Because of race condition, the voiceBroadcastService may be running without id here (the sync response may be received before
|
|
// the success of the event sending), in that case, we will display a recorder view by default to let the user be able to stop a potential record.
|
|
if ([event.sender isEqualToString: self.mxSession.myUserId] &&
|
|
[voiceBroadcastInfo.deviceId isEqualToString:self.mxSession.myDeviceId] &&
|
|
self.mxSession.voiceBroadcastService != nil &&
|
|
([event.eventId isEqualToString: self.mxSession.voiceBroadcastService.voiceBroadcastInfoEventId] ||
|
|
self.mxSession.voiceBroadcastService.voiceBroadcastInfoEventId == nil))
|
|
{
|
|
self.tag = RoomBubbleCellDataTagVoiceBroadcastRecord;
|
|
}
|
|
else
|
|
{
|
|
self.tag = RoomBubbleCellDataTagVoiceBroadcastPlayback;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.tag = RoomBubbleCellDataTagVoiceBroadcastNoDisplay;
|
|
|
|
if ([VoiceBroadcastInfo isStoppedFor:voiceBroadcastInfo.state])
|
|
{
|
|
// This state event corresponds to the end of a voice broadcast
|
|
// Force the tag of the potential cellData which corresponds to the started event to switch the display from recorder to listener
|
|
id<MXKRoomBubbleCellDataStoring> bubbleData = [roomDataSource cellDataOfEventWithEventId:voiceBroadcastInfo.eventId];
|
|
bubbleData.tag = RoomBubbleCellDataTagVoiceBroadcastPlayback;
|
|
}
|
|
}
|
|
self.collapsable = NO;
|
|
self.collapsed = NO;
|
|
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case MXEventTypeRoomMessage:
|
|
{
|
|
if (event.location)
|
|
{
|
|
self.tag = RoomBubbleCellDataTagLocation;
|
|
self.collapsable = NO;
|
|
self.collapsed = NO;
|
|
}
|
|
else if (event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType])
|
|
{
|
|
self.tag = RoomBubbleCellDataTagVoiceBroadcastNoDisplay;
|
|
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 RoomBubbleCellDataTagVoiceBroadcastRecord:
|
|
case RoomBubbleCellDataTagVoiceBroadcastPlayback:
|
|
hasNoDisplay = NO;
|
|
break;
|
|
case RoomBubbleCellDataTagVoiceBroadcastNoDisplay:
|
|
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 RoomBubbleCellDataTagVoiceBroadcastRecord:
|
|
case RoomBubbleCellDataTagVoiceBroadcastPlayback:
|
|
case RoomBubbleCellDataTagVoiceBroadcastNoDisplay:
|
|
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.voiceBroadcastInfoContentKeyType]) {
|
|
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
|