Merge branch 'develop' into aleksandrs/6963_multi_session_logout

This commit is contained in:
paleksandrs 2022-10-31 11:30:12 +02:00
commit c02f144314
45 changed files with 509 additions and 200 deletions

View file

@ -1,9 +1,6 @@
name: UI Tests CI
on:
push:
branches: [ develop ]
pull_request:
workflow_dispatch:

View file

@ -17,7 +17,8 @@ jobs:
contains(github.event.issue.labels.*.name, 'Z-IA') ||
contains(github.event.issue.labels.*.name, 'A-Themes-Custom') ||
contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') ||
contains(github.event.issue.labels.*.name, 'A-Tags')
contains(github.event.issue.labels.*.name, 'A-Tags') ||
contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor')
steps:
- uses: actions/github-script@v5
with:
@ -267,7 +268,7 @@ jobs:
name: Add labelled issues to PS features team 3
runs-on: ubuntu-latest
if: >
contains(github.event.issue.labels.*.name, 'A-Composer-WYSIWYG')
contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor'')
steps:
- uses: octokit/graphql-action@v2.x
id: add_to_project

View file

@ -154,5 +154,14 @@ post_install do |installer|
config.build_settings['WARNING_CFLAGS'] ||= ['$(inherited)','-Wno-nullability-completeness']
config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['$(inherited)', '-Xcc', '-Wno-nullability-completeness']
end
# Fix Xcode 14 resource bundle signing issues
# https://github.com/CocoaPods/CocoaPods/issues/11402#issuecomment-1259231655
if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle"
target.build_configurations.each do |config|
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
end
end
end
end

View file

@ -2639,3 +2639,15 @@
// Send Media Actions
"wysiwyg_composer_start_action_media_picker" = "Fotobibliothek";
"settings_labs_enable_wysiwyg_composer" = "Probiere den Rich-Text-Editor aus (bald auch mit Plain-Text-Modus)";
"wysiwyg_composer_start_action_voice_broadcast" = "Sprachübertragung";
"voice_broadcast_already_in_progress_message" = "Du zeichnest bereits eine Sprachübertragung auf. Bitte beende die laufende Übertragung, um eine neue zu beginnen.";
"voice_broadcast_blocked_by_someone_else_message" = "Jemand anderes nimmt bereits eine Sprachübertragung auf. Warte auf das Ende der Übertragung, bevor du eine neue startest.";
"voice_broadcast_permission_denied_message" = "Du hast nicht die nötigen Berechtigungen, um eine Sprachübertragung in diesem Raum zu starten. Kontaktiere einen Raumadministrator, um deine Berechtigungen anzupassen.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Sprachübertragung kann nicht gestartet werden";
"settings_labs_enable_voice_broadcast" = "Sprachübertragung (in aktiver Entwicklung)";
"voice_broadcast_playback_loading_error" = "Wiedergabe der Sprachübertragung nicht möglich.";
"deselect_all" = "Alle abwählen";
"user_other_session_menu_select_sessions" = "Sitzungen auswählen";
"user_other_session_selected_count" = "%@ ausgewählt";

View file

@ -2506,3 +2506,83 @@
"authentication_qr_login_start_subtitle" = "Kasuta selle seadme kaamerat ja logi sisse teises seadmes kuvatud QR-koodi alusel:";
"authentication_qr_login_start_title" = "Loe QR-koodi";
"authentication_login_with_qr" = "Logi sisse QR-koodi abil";
"wysiwyg_composer_format_action_strikethrough" = "Kasuta allajoonitud kirja";
"wysiwyg_composer_format_action_underline" = "Kasuta läbijoonitud kirja";
"wysiwyg_composer_format_action_italic" = "Kasuta kaldkirja";
// Formatting Actions
"wysiwyg_composer_format_action_bold" = "Kasuta paksu kirja";
"wysiwyg_composer_start_action_voice_broadcast" = "Ringhäälingukõne";
"wysiwyg_composer_start_action_text_formatting" = "Tekstivorming";
"wysiwyg_composer_start_action_camera" = "Kaamera";
"wysiwyg_composer_start_action_location" = "Asukoht";
"wysiwyg_composer_start_action_polls" = "Küsitlused";
"wysiwyg_composer_start_action_attachments" = "Manused";
"wysiwyg_composer_start_action_stickers" = "Kleepsud";
// Mark: - WYSIWYG Composer
// Send Media Actions
"wysiwyg_composer_start_action_media_picker" = "Fotode kogu";
"user_session_details_last_activity" = "Viimati kasutusel";
"device_type_name_unknown" = "Tundmatu seadmetüüp";
"device_type_name_mobile" = "Mobiiltelefon";
"device_type_name_web" = "Veebiliides";
"device_type_name_desktop" = "Töölauarakendus";
"user_inactive_session_item_with_date" = "Pole olnud kasutusel üle 90 päeva (%@)";
"user_inactive_session_item" = "Pole olnud kasutusel üle 90 päeva";
"user_session_item_details_last_activity" = "Viimati kasutusel %@";
"user_other_session_clear_filter" = "Eemalda filter";
"user_other_session_no_unverified_sessions" = "Verifitseerimata sessioone ei leidu.";
"user_other_session_no_verified_sessions" = "Verifitseeritud sessioone ei leidu.";
"user_other_session_no_inactive_sessions" = "Ei leidu sessioone, mis pole aktiivses kasutuses.";
"user_other_session_filter_menu_inactive" = "Pole pidevas kasutuses";
"user_other_session_filter_menu_unverified" = "Verifitseerimata";
"user_other_session_filter_menu_verified" = "Verifitseeritud";
"user_other_session_filter_menu_all" = "Kõik sessioonid";
"user_other_session_filter" = "Filtreeri";
"user_other_session_verified_sessions_header_subtitle" = "Parima turvalisuse nimel logi välja neist sessioonidest, mida sa enam ei kasuta või ei tunne ära.";
"user_other_session_current_session_details" = "Sinu praegune sessioon";
"user_other_session_unverified_sessions_header_subtitle" = "Turvalise sõnumvahetuse nimel verifitseeri kõik oma sessioonid ning logi neist välja, mida sa enam ei kasuta või ei tunne enam ära.";
"user_other_session_security_recommendation_title" = "Turvalisusega seotud soovitused";
"user_other_session_verified_additional_info" = "See sessioon on valmis turvaliseks sõnumivahetuseks.";
"user_other_session_unverified_additional_info" = "Parima turvalisuse ja töökindluse nimel verifitseeri see sessioon või logi ta võrgust välja.";
"user_session_verification_unknown_additional_info" = "Selle sessiooni olekut ei saa tuvastada enne kui oled ta verifitseerinud.";
"user_session_verification_unknown_short" = "Teadmata olek";
"user_session_verification_unknown" = "Verifitseerimise olek on määratlemata";
"user_sessions_overview_link_device" = "Seo teise seadmega";
// MARK: User sessions management
// Parameter is the application display name (e.g. "Element")
"user_sessions_default_session_display_name" = "%@ iOS";
"voice_broadcast_playback_loading_error" = "Selle ringhäälingukõne esitamine ei õnnestu.";
"voice_broadcast_already_in_progress_message" = "Sa juba salvestad ringhäälingukõnet. Uue alustamiseks palun lõpeta eelmine salvestus.";
"voice_broadcast_blocked_by_someone_else_message" = "Keegi juba salvestab ringhäälingukõnet. Uue ringhäälingukõne salvestamiseks palun oota, kuni see teine ringhäälingukõne on lõppenud.";
"voice_broadcast_permission_denied_message" = "Sul pole piisavalt õigusi selles jututoas ringhäälingukõne algatamiseks. Õiguste lisamiseks palun võta ühendust jututoa haldajaga.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Uue ringhäälingukõne alustamine pole võimalik";
"sign_out_confirmation_message" = "Kas sa oled kindel et soovid välja logida?";
// MARK: Sign out warning
"sign_out" = "Logi välja";
"manage_session_rename" = "Muuda sessiooni nime";
"manage_session_name_info_link" = "Lisateave";
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Palun arvesta, et sessioonide nimed on näha ka kõikidele osapooltele, kellega sa suhtled. %@";
"manage_session_name_hint" = "Sinu enda kirjutatud sessiooninimede alusel on sul oma seadmeid lihtsam ära tunda.";
"settings_labs_enable_voice_broadcast" = "Ringhäälingukõne (aktiivses arenduses)";
"settings_labs_enable_wysiwyg_composer" = "Proovi vormindatud teksti alusel töötavat tekstitoimetit (varsti lisandub ka vormindamata teksti režiim)";
"authentication_qr_login_failure_retry" = "Proovi uuesti";
"authentication_qr_login_failure_request_timed_out" = "Sidumine ei lõppenud etteantud aja jooksul.";
"authentication_qr_login_failure_request_denied" = "Teine seade lükkas päringu tagasi.";
"authentication_qr_login_failure_invalid_qr" = "QR-kood on vigane.";
"authentication_qr_login_failure_title" = "Seose loomine ei õnenstunud";
"authentication_qr_login_loading_signed_in" = "Sa oled oma teises seadmes sisse loginud Matrix'i võrku.";
"authentication_qr_login_loading_waiting_signin" = "Ootame, et teine seade logiks võrku.";
"authentication_qr_login_loading_connecting_device" = "Loon ühendust seadmega";
"authentication_qr_login_confirm_alert" = "Palun vaata, et sa kindlasti tead, kust see QR-kood kuvatakse. Sellisel viisil seadmete sidumisel sa annad oma kasutajakontole täiemahulise ligipääsu.";
"authentication_qr_login_confirm_subtitle" = "Kontrolli, et järgnev kood klapib teises seadmes kuvatava koodiga:";

View file

@ -1270,3 +1270,23 @@
"microphone_access_not_granted_for_voice_message" = "جهت ارسال پیام صوتی نیاز به دسترسی به میکروفون وجود دارد اما %@ دسترسی استفاده از آن را ندارد";
"e2e_passphrase_too_short" = "کلمه عبور بیش از حد کوتاه است (حداقل می‌بایست %d کاراکتر باشد)";
"message_reply_to_sender_sent_a_voice_message" = "یک پیام صوتی ارسال کنید.";
"onboarding_splash_page_1_title" = "صاحب گفتگوهای خود شوید.";
"onboarding_splash_login_button_title" = "من از قبل حساب کاربری دارم";
// MARK: Onboarding
"onboarding_splash_register_button_title" = "ساخت حساب کاربری";
"accessibility_button_label" = "دکمه";
"saving" = "در حال ذخیره";
// Activities
"loading" = "در حال بارگزاری";
"invite_to" = "دعوت به %@";
"confirm" = "تأیید";
"edit" = "ویرایش";
"suggest" = "پیشنهاد";
"add" = "افزودن";
"existing" = "خروج";
"new_word" = "جدید";
"stop" = "توقف";
"joining" = "پیوستن";
"enable" = "فعال";

View file

@ -2625,4 +2625,15 @@
"authentication_qr_login_start_subtitle" = "Használd a kamerát ezen az eszközön a másik eszközödön megjelenő QR kód beolvasására:";
"authentication_qr_login_start_title" = "QR kód beolvasása";
"authentication_login_with_qr" = "Belépés QR kóddal";
"settings_labs_enable_voice_broadcast" = "Hang közvetítés (aktív fejlesztés alatt). Jelenleg a hang közvetítést csak a szoba idővonalán jelezzük, egyenlőre nem lehet hangot sugározni vagy belehallgatni a közvetítésbe";
"settings_labs_enable_voice_broadcast" = "Hang közvetítés (aktív fejlesztés alatt)";
"wysiwyg_composer_start_action_voice_broadcast" = "Hang közvetítés";
"voice_broadcast_playback_loading_error" = "A hang közvetítés nem játszható le.";
"voice_broadcast_already_in_progress_message" = "Egy hang közvetítés már folyamatban van. Először fejezd be a jelenlegi közvetítést egy új indításához.";
"voice_broadcast_blocked_by_someone_else_message" = "Valaki már elindított egy hang közvetítést. Várd meg a közvetítés végét az új indításához.";
"voice_broadcast_permission_denied_message" = "Nincs jogosultságod hang közvetítést indítani ebben a szobában. Vedd fel a kapcsolatot a szoba adminisztrátorával a szükséges jogosultság megszerzéséhez.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Az új hang közvetítés nem indítható el";
"deselect_all" = "Semmit nem jelöl ki";
"user_other_session_menu_select_sessions" = "Munkamenetek kiválasztása";
"user_other_session_selected_count" = "%@ kiválasztva";

View file

@ -2832,3 +2832,15 @@
"manage_session_name_info" = "Harap diketahui bahwa nama sesi juga terlihat ke orang-orang yang Anda berkomunikasi. %@";
"manage_session_name_hint" = "Nama sesi khusus dapat membantu Anda mengenal perangkat Anda dengan lebih mudah.";
"settings_labs_enable_wysiwyg_composer" = "Coba editor teks kaya (mode teks biasa akan datang)";
"wysiwyg_composer_start_action_voice_broadcast" = "Siaran suara";
"voice_broadcast_playback_loading_error" = "Tidak dapat memainkan siaran suara ini.";
"voice_broadcast_already_in_progress_message" = "Anda saat ini merekam sebuah siaran suara. Mohon akhiri siaran suara Anda saat ini untuk memulai yang baru.";
"voice_broadcast_blocked_by_someone_else_message" = "Ada orang lain yang saat ini merekam sebuah siaran suara. Tunggu siaran suaranya berakhir untuk memulai yang baru.";
"voice_broadcast_permission_denied_message" = "Anda tidak memiliki izin untuk memulai sebuah siaran suara di ruangan ini. Hubungi sebuah administrator ruangan untuk meningkatkan izin Anda.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Tidak dapat memulai sebuah siaran suara baru";
"settings_labs_enable_voice_broadcast" = "Siaran suara (dalam pengembangan aktif)";
"deselect_all" = "Batalkan Semua Pilihan";
"user_other_session_menu_select_sessions" = "Pilih sesi";
"user_other_session_selected_count" = "%@ dipilih";

View file

@ -2605,4 +2605,15 @@
"manage_session_name_info" = "Ricorda che i nomi di sessione sono anche visibili alle persone con cui comunichi. %@";
"manage_session_name_hint" = "I nomi di sessione personalizzati possono aiutarti a riconoscere i tuoi dispositivi più facilmente.";
"settings_labs_enable_wysiwyg_composer" = "Prova l'editor in rich text (il testo semplice è in arrivo)";
"settings_labs_enable_voice_broadcast" = "Broadcast voce (in sviluppo attivo). Attualmente rileviamo solo il broadcast vocale nella linea temporale della stanza, non è possibile inviare o ascoltare un vero broadcast vocale";
"settings_labs_enable_voice_broadcast" = "Trasmissione vocale (in sviluppo attivo)";
"wysiwyg_composer_start_action_voice_broadcast" = "Trasmissione vocale";
"voice_broadcast_playback_loading_error" = "Impossibile avviare questa trasmissione vocale.";
"voice_broadcast_already_in_progress_message" = "Stai già registrando una trasmissione vocale. Termina quella in corso per iniziarne una nuova.";
"voice_broadcast_blocked_by_someone_else_message" = "Qualcun altro sta già registrando una trasmissione vocale. Aspetta che finisca prima di iniziarne una nuova.";
"voice_broadcast_permission_denied_message" = "Non hai l'autorizzazione necessaria per iniziare un broadcast vocale in questa stanza. Contatta un amministratore della stanza per aggiornare le tue autorizzazioni.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Impossibile iniziare una nuova trasmissione vocale";
"deselect_all" = "Deseleziona tutti";
"user_other_session_menu_select_sessions" = "Seleziona sessioni";
"user_other_session_selected_count" = "%@ selezionate";

View file

@ -751,7 +751,7 @@
"group_participants_invited_section" = "ZAPROSZONY";
"receipt_status_read" = "Odczytano: ";
// Media picker
"media_picker_title" = "Selektor mediów";
"media_picker_title" = "Biblioteka mediów";
// Image picker
"image_picker_action_camera" = "Zrób zdjęcie";
"image_picker_action_library" = "Wybierz z biblioteki";
@ -2569,7 +2569,7 @@
// Mark: - All Chats
"all_chats_title" = "Wszystkie rozmowy";
"all_chats_title" = "Rozmowy";
"spaces_subspace_creation_visibility_message" = "Utworzona przestrzeń zostanie dodana do %@.";
"spaces_subspace_creation_visibility_title" = "Jakiego rodzaju podprzestrzeń chcesz utworzyć?";
"spaces_explore_rooms_format" = "Przeglądaj %@";

View file

@ -2606,3 +2606,12 @@
"manage_session_name_info" = "Por favor esteja ciente que nomes de sessões também são visíveis a pessoas com quem você se comunica. %@";
"manage_session_name_hint" = "Nomes de sessões personalizados podem ajudar você a reconhecer seus dispositivos mais facilmente.";
"settings_labs_enable_wysiwyg_composer" = "Experimente o editor de texto rico (modo de texto puro vindo em breve)";
"wysiwyg_composer_start_action_voice_broadcast" = "Broadcast de voz";
"voice_broadcast_playback_loading_error" = "Incapaz de tocar este broadcast de voz.";
"voice_broadcast_already_in_progress_message" = "Você já está gravando um broadcast de voz. Por favor termine seu broadcast de voz atual para começar um novo.";
"voice_broadcast_blocked_by_someone_else_message" = "Alguma outra pessoa já está gravando um broadcast de voz. Espere que o broadcast de voz dela termine para começar um novo.";
"voice_broadcast_permission_denied_message" = "Você não tem as permissões requeridas para começar um broadcast de voz nesta sala. Contacte um(a) administrador(a) da sala para fazer upgrade de suas permissões.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Não dá para começar um novo broadcast de voz";
"settings_labs_enable_voice_broadcast" = "Broadcast de voz (sob desenvolvimento ativo)";

View file

@ -603,7 +603,7 @@
"key_backup_recover_from_passphrase_passphrase_title" = "Ввод";
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Введите секретную фразу";
"key_backup_recover_from_passphrase_recover_action" = "Разблокировать историю";
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Не знаете вашу секретную фразу для восстановления? Вы можете ";
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Не помните свою мнемоническую фразу? Вы можете ";
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "использовать ключ безопасности";
"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = ".";
"key_backup_recover_from_recovery_key_info" = "Используйте ключ безопасности для разблокировки истории безопасных сообщений";
@ -624,7 +624,7 @@
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Ключ безопасности";
"key_backup_setup_success_from_recovery_key_make_copy_action" = "Сделать копию";
"key_backup_setup_success_from_recovery_key_made_copy_action" = "Я сделал копию";
"key_backup_recover_invalid_passphrase_title" = "Неверная секретная фраза для восстановления";
"key_backup_recover_invalid_passphrase_title" = "Неверная мнемоническая фраза";
"key_backup_recover_invalid_recovery_key_title" = "Несоответствующий ключ безопасности";
"key_backup_setup_banner_title" = "Не теряйте зашифрованные сообщения";
"key_backup_setup_banner_subtitle" = "Начать использовать ключ восстановления";
@ -641,7 +641,7 @@
"key_backup_setup_intro_setup_action_with_existing_backup" = "Использовать ключ восстановления";
"settings_key_backup_info" = "Зашифрованные сообщения защищены сквозным шифрованием. Только вы и получатель(и) имеют ключи для чтения этих сообщений.";
"settings_key_backup_info_signout_warning" = "Сделайте резервную копию ключей перед выходом, чтобы не потерять их.";
"key_backup_setup_passphrase_title" = "Защитите резервную копию секретной фразой";
"key_backup_setup_passphrase_title" = "Защитите резервную копию мнемонической фразой";
"key_backup_setup_passphrase_setup_recovery_key_info" = "Или защитите свою резервную копию с помощью ключа безопасности, сохранив ее в безопасном месте.";
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Расширенный) Настройка с ключом безопасности";
// Success from passphrase
@ -654,7 +654,7 @@
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_title" = "Зашифрованные сообщения будут утеряны";
"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Мне не нужны мои зашифрованные сообщения";
"sign_out_non_existing_key_backup_alert_title" = "Вы потеряете доступ к зашифрованным сообщениям если выйдете сейчас";
"key_backup_recover_invalid_passphrase" = "Невозможно расшифровать резервную копию с помощью этой секретной фразы: убедитесь, что вы ввели верную секретную фразу для восстановления.";
"key_backup_recover_invalid_passphrase" = "Невозможно расшифровать резервную копию с помощью этой фразы: убедитесь, что вы ввели верную мнемоническую фразу.";
"key_backup_recover_invalid_recovery_key" = "Невозможно расшифровать резервную копию с помощью этого ключа: убедитесь, что вы ввели верный ключ безопасности.";
"e2e_key_backup_wrong_version_button_settings" = "Настройки";
"key_backup_setup_intro_manual_export_info" = "(Расширенный)";
@ -986,7 +986,7 @@
"secure_key_backup_setup_intro_info" = "Защитите себя от потери доступа к зашифрованным сообщениям и данным, создав резервную копию ключей шифрования на своём сервере.";
"secure_key_backup_setup_intro_use_security_key_title" = "Используйте ключ безопасности";
"secure_key_backup_setup_intro_use_security_key_info" = "Создайте ключ безопасности для хранения в надежном месте, например в менеджере паролей или сейфе.";
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Использовать секретную фразу";
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Использовать мнемоническую фразу";
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Введите секретную фразу, известную только вам, и создайте ключ для резервного копирования.";
"secure_key_backup_setup_existing_backup_error_title" = "Резервная копия сообщений уже существует";
"secure_key_backup_setup_existing_backup_error_info" = "Разблокируйте его для повторного использования в защищенной резервной копии или удалите для создания новой резервной копии сообщений в защищенной резервной копии.";
@ -1024,7 +1024,7 @@
"device_verification_self_verify_wait_information" = "Подтвердите этот сеанс на одном из других ваших сеансов, предоставив ему доступ к зашифрованным сообщениям.\n\nИспользуйте последнюю версию %@ на других ваших устройствах:";
"device_verification_self_verify_wait_additional_information" = "Это работает с %@ и другими клиентами Matrix с поддержкой кросс-подписи.";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Используйте ключ безопасности";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Используйте секретную фразу или ключ безопасности";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Используйте мнемоническую фразу или бумажный ключ";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Если вы не можете получить доступ к существующему сеансу";
"key_verification_verify_sas_title_emoji" = "Сравните смайлы";
"key_verification_verify_sas_title_number" = "Сравните числа";
@ -1102,17 +1102,17 @@
"user_verification_session_details_verify_action_current_user" = "Интерактивная проверка";
"user_verification_session_details_verify_action_current_user_manually" = "Ручная проверка с помощью текста";
"user_verification_session_details_verify_action_other_user" = "Подтверждение вручную";
"secrets_recovery_with_passphrase_title" = "Секретная фраза";
"secrets_recovery_with_passphrase_title" = "Мнемоническая фраза";
"secrets_recovery_with_passphrase_information_default" = "Получите доступ к своей защищённой истории сообщений и вашей личности с кросс-подписью для проверки других сеансов, введя секретную фразу.";
"secrets_recovery_with_passphrase_information_verify_device" = "Используйте секретную фразу, чтобы проверить это устройство.";
"secrets_recovery_with_passphrase_information_verify_device" = "Используйте свою мнемоническую фразу, чтобы заверить эту сессию.";
"secrets_recovery_with_passphrase_passphrase_title" = "Ввод";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Введите секретную фразу";
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Введите мнемоническую фразу";
"secrets_recovery_with_passphrase_recover_action" = "Использовать секретную фразу";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Не знаете вашу секретную фразу? Вы можете ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "использовать ключ безопасности";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Не помните свою мнемоническую фразу? Вы можете ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "использовать бумажный ключ";
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Невозможно получить доступ к секретному хранилищу";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Убедитесь, что вы ввели правильную секретную фразу.";
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Убедитесь, что вы ввели верную мнемоническую фразу.";
"secrets_recovery_with_key_title" = "Ключ безопасности";
"secrets_recovery_with_key_information_default" = "Получите доступ к своей защищённой истории сообщений и вашей личности с кросс-подписью для проверки других сеансов, введя ключ безопасности.";
"secrets_recovery_with_key_information_verify_device" = "Используйте ключ безопасности, чтобы проверить это устройство.";
@ -1128,11 +1128,11 @@
"secrets_setup_recovery_key_done_action" = "Готово";
"secrets_setup_recovery_key_storage_alert_title" = "Храните его в безопасности";
"secrets_setup_recovery_key_storage_alert_message" = "✓ Распечатайте и храните в безопасном месте\n✓ Сохраните его на USB-носителе или резервном носителе\n✓ Скопируйте его в свое личное облачное хранилище";
"secrets_setup_recovery_passphrase_title" = "Задайте секретную фразу";
"secrets_setup_recovery_passphrase_title" = "Задайте мнемоническую фразу";
"secrets_setup_recovery_passphrase_information" = "Введите секретную фразу, известную только вам, для защиты данных на вашем сервере.";
"secrets_setup_recovery_passphrase_additional_information" = "Не используйте пароль своей учетной записи.";
"secrets_setup_recovery_passphrase_validate_action" = "Готово";
"secrets_setup_recovery_passphrase_confirm_information" = "Для подтверждения введите вашу секретную фразу ещё раз.";
"secrets_setup_recovery_passphrase_confirm_information" = "Введите мнемоническую фразу ещё раз, чтобы подтвердить её.";
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Подтвердить";
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Подтвердить секретную фразу";
"cross_signing_setup_banner_title" = "Настройка шифрования";
@ -1238,8 +1238,8 @@
// MARK: - Home
"home_empty_view_title" = "Добро пожаловать в %@,\n%@";
"secrets_setup_recovery_passphrase_summary_information" = "Запомните свою секретную фразу. Её можно использовать для разблокировки ваших зашифрованных сообщений и данных.";
"secrets_setup_recovery_passphrase_summary_title" = "Сохраните вашу секретную фразу";
"secrets_setup_recovery_passphrase_summary_information" = "Запомните свою мнемоническую фразу. Её можно использовать для разблокировки ваших зашифрованных сообщений и данных.";
"secrets_setup_recovery_passphrase_summary_title" = "Сохраните свою мнемоническую фразу";
"favourites_empty_view_information" = "Вы можете добавить в избранное несколькими способами - самый быстрый - просто нажать и удерживать. Нажмите на звёздочку, и они автоматически появятся здесь, и вы их навсегда сохраните.";
// MARK: - Favourites
@ -1355,7 +1355,7 @@
"space_feature_unavailable_title" = "Пространств ещё нет";
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Введите свой ключ безопасности, чтобы продолжить.";
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Введите секретную фразу, чтобы продолжить.";
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Введите мнемоническую фразу, чтобы продолжить.";
"key_verification_verify_qr_code_scan_code_other_device_action" = "Сканирование с помощью этого устройства";
// Success from secure backup

View file

@ -2828,3 +2828,15 @@
"manage_session_name_info" = "Uvedomte si, že názvy relácií sú viditeľné aj pre ľudí, s ktorými komunikujete. %@";
"manage_session_name_hint" = "Vlastné názvy relácií vám pomôžu ľahšie rozpoznať vaše zariadenia.";
"settings_labs_enable_wysiwyg_composer" = "Vyskúšajte rozšírený textový editor (čistý textový režim sa objaví čoskoro)";
"wysiwyg_composer_start_action_voice_broadcast" = "Hlasové vysielanie";
"voice_broadcast_already_in_progress_message" = "Už nahrávate hlasové vysielanie. Ukončite aktuálne hlasové vysielanie a spustite nové.";
"voice_broadcast_blocked_by_someone_else_message" = "Niekto iný už nahráva hlasové vysielanie. Počkajte, kým sa skončí jeho hlasové vysielanie, a potom spustite nové.";
"voice_broadcast_permission_denied_message" = "Nemáte požadované oprávnenia na spustenie hlasového vysielania v tejto miestnosti. Obráťte sa na správcu miestnosti, aby vám rozšíril oprávnenia.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Nie je možné spustiť nové hlasové vysielanie";
"settings_labs_enable_voice_broadcast" = "Hlasové vysielanie (v štádiu aktívneho vývoja)";
"voice_broadcast_playback_loading_error" = "Toto hlasové vysielanie nie je možné prehrať.";
"deselect_all" = "Zrušiť výber všetkých";
"user_other_session_selected_count" = "%@ vybratých";
"user_other_session_menu_select_sessions" = "Vyberte relácie";

View file

@ -2830,3 +2830,15 @@
"manage_session_name_info" = "Зауважте, що назви сеансів також видно людям, з якими ви спілкуєтесь. %@";
"manage_session_name_hint" = "Власні назви сеансів допоможуть вам легше розпізнавати ваші пристрої.";
"settings_labs_enable_wysiwyg_composer" = "Спробуйте розширений текстовий редактор (незабаром з'явиться режим звичайного тексту)";
"wysiwyg_composer_start_action_voice_broadcast" = "Голосові повідомлення";
"voice_broadcast_playback_loading_error" = "Неможливо відтворити це голосове повідомлення.";
"voice_broadcast_already_in_progress_message" = "Ви вже записуєте голосове повідомлення. Завершіть поточну трансляцію, щоб розпочати нову.";
"voice_broadcast_blocked_by_someone_else_message" = "Хтось інший вже записує голосове повідомлення. Зачекайте, поки закінчиться трансляція, щоб розпочати нову.";
"voice_broadcast_permission_denied_message" = "Ви не маєте необхідних дозволів для початку трансляції голосового повідомлення в цій кімнаті. Зверніться до адміністратора кімнати, щоб оновити ваші дозволи.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Не вдалося розпочати трансляцію нового голосового повідомлення";
"settings_labs_enable_voice_broadcast" = "Голосові повідомлення (в активній розробці)";
"deselect_all" = "Скасувати вибір усіх";
"user_other_session_menu_select_sessions" = "Вибрати сеанси";
"user_other_session_selected_count" = "Вибрано %@";

View file

@ -329,7 +329,7 @@
{
if (self.mxSession.crypto)
{
[self.mxSession.crypto trustLevelSummaryForUserIds:@[userId] onComplete:^(MXUsersTrustLevelSummary *usersTrustLevelSummary) {
[self.mxSession.crypto trustLevelSummaryForUserIds:@[userId] forceDownload:NO success:^(MXUsersTrustLevelSummary *usersTrustLevelSummary) {
UserEncryptionTrustLevel userEncryptionTrustLevel;
double trustedDevicesPercentage = usersTrustLevelSummary.trustedDevicesProgress.fractionCompleted;
@ -341,7 +341,7 @@
else if (trustedDevicesPercentage == 0.0)
{
// Verify if the user has the user has cross-signing enabled
if ([self.mxSession.crypto crossSigningKeysForUser:userId])
if ([self.mxSession.crypto.crossSigning crossSigningKeysForUser:userId])
{
userEncryptionTrustLevel = UserEncryptionTrustLevelNotVerified;
}
@ -357,6 +357,9 @@
onComplete(userEncryptionTrustLevel);
} failure:^(NSError *error) {
MXLogErrorDetails(@"[MXRoom+Riot] Error fetching trust level summary", error);
onComplete(UserEncryptionTrustLevelUnknown);
}];
}
else

View file

@ -195,7 +195,9 @@ UINavigationControllerDelegate
- (BOOL)presentIncomingKeyVerificationRequest:(id<MXKeyVerificationRequest>)incomingKeyVerificationRequest
inSession:(MXSession*)session;
- (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember session:(MXSession*)mxSession;
- (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember
session:(MXSession*)mxSession
completion:(void (^)(void))completion;
- (BOOL)presentCompleteSecurityForSession:(MXSession*)mxSession;

View file

@ -128,6 +128,11 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
If any the currently displayed key verification dialog
*/
KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter;
/**
Completion block for the requester of key verification
*/
void (^keyVerificationCompletionBlock)(void);
/**
Currently displayed secure backup setup
@ -3700,7 +3705,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
return presented;
}
- (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember session:(MXSession*)mxSession
- (BOOL)presentUserVerificationForRoomMember:(MXRoomMember*)roomMember
session:(MXSession*)mxSession
completion:(void (^)(void))completion;
{
MXLogDebug(@"[AppDelegate][MXKeyVerification] presentUserVerificationForRoomMember: %@", roomMember);
@ -3713,6 +3720,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[keyVerificationCoordinatorBridgePresenter presentFrom:self.presentedViewController roomMember:roomMember animated:YES];
presented = YES;
keyVerificationCompletionBlock = completion;
}
else
{
@ -3744,7 +3753,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
MXCrypto *crypto = coordinatorBridgePresenter.session.crypto;
id<MXCrypto> crypto = coordinatorBridgePresenter.session.crypto;
if (!crypto.backup.hasPrivateKeyInCryptoStore || !crypto.backup.enabled)
{
MXLogDebug(@"[AppDelegate][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys");
@ -3765,6 +3774,11 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}];
keyVerificationCoordinatorBridgePresenter = nil;
if (keyVerificationCompletionBlock) {
keyVerificationCompletionBlock();
}
keyVerificationCompletionBlock = nil;
}
#pragma mark - New request
@ -3984,7 +3998,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)registerUserDidSignInOnNewDeviceNotificationForSession:(MXSession*)session
{
MXCrossSigning *crossSigning = session.crypto.crossSigning;
id<MXCrossSigning> crossSigning = session.crypto.crossSigning;
if (!crossSigning)
{
@ -4075,7 +4089,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)registerDidChangeCrossSigningKeysNotificationForSession:(MXSession*)session
{
MXCrossSigning *crossSigning = session.crypto.crossSigning;
id<MXCrossSigning> crossSigning = session.crypto.crossSigning;
if (!crossSigning)
{

View file

@ -324,12 +324,8 @@ extension KeyVerificationCoordinator: KeyVerificationDataLoadingCoordinatorDeleg
// MARK: - DeviceVerificationStartCoordinatorDelegate
extension KeyVerificationCoordinator: DeviceVerificationStartCoordinatorDelegate {
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didCompleteWithOutgoingTransaction transaction: MXSASTransaction) {
self.showVerifyBySAS(transaction: transaction, animated: true)
}
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didTransactionCancelled transaction: MXSASTransaction) {
self.didCancel()
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, otherDidAcceptRequest request: MXKeyVerificationRequest) {
self.showVerifyByScanning(keyVerificationRequest: request, animated: true)
}
func deviceVerificationStartCoordinatorDidCancel(_ coordinator: DeviceVerificationStartCoordinatorType) {

View file

@ -63,13 +63,9 @@ extension DeviceVerificationStartCoordinator: DeviceVerificationStartViewModelCo
func deviceVerificationStartViewModelDidUseLegacyVerification(_ viewModel: DeviceVerificationStartViewModelType) {
self.delegate?.deviceVerificationStartCoordinatorDidCancel(self)
}
func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didCompleteWithOutgoingTransaction transaction: MXSASTransaction) {
self.delegate?.deviceVerificationStartCoordinator(self, didCompleteWithOutgoingTransaction: transaction)
}
func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didTransactionCancelled transaction: MXSASTransaction) {
self.delegate?.deviceVerificationStartCoordinator(self, didTransactionCancelled: transaction)
func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, otherDidAcceptRequest request: MXKeyVerificationRequest) {
self.delegate?.deviceVerificationStartCoordinator(self, otherDidAcceptRequest: request)
}
func deviceVerificationStartViewModelDidCancel(_ viewModel: DeviceVerificationStartViewModelType) {

View file

@ -19,8 +19,7 @@
import Foundation
protocol DeviceVerificationStartCoordinatorDelegate: AnyObject {
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didCompleteWithOutgoingTransaction transaction: MXSASTransaction)
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didTransactionCancelled transaction: MXSASTransaction)
func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, otherDidAcceptRequest request: MXKeyVerificationRequest)
func deviceVerificationStartCoordinatorDidCancel(_ coordinator: DeviceVerificationStartCoordinatorType)
}

View file

@ -29,7 +29,7 @@ final class DeviceVerificationStartViewModel: DeviceVerificationStartViewModelTy
private let otherUser: MXUser
private let otherDevice: MXDeviceInfo
private var transaction: MXSASTransaction!
private var request: MXKeyVerificationRequest?
// MARK: Public
@ -52,12 +52,12 @@ final class DeviceVerificationStartViewModel: DeviceVerificationStartViewModelTy
case .beginVerifying:
self.beginVerifying()
case .verifyUsingLegacy:
self.cancelTransaction()
self.cancelRequest()
self.update(viewState: .verifyUsingLegacy(self.session, self.otherDevice))
case .verifiedUsingLegacy:
self.coordinatorDelegate?.deviceVerificationStartViewModelDidUseLegacyVerification(self)
case .cancel:
self.cancelTransaction()
self.cancelRequest()
self.coordinatorDelegate?.deviceVerificationStartViewModelDidCancel(self)
}
}
@ -67,30 +67,22 @@ final class DeviceVerificationStartViewModel: DeviceVerificationStartViewModelTy
private func beginVerifying() {
self.update(viewState: .loading)
self.verificationManager.beginKeyVerification(withUserId: self.otherUser.userId, andDeviceId: self.otherDevice.deviceId, method: MXKeyVerificationMethodSAS, success: { [weak self] (transaction) in
guard let sself = self else {
return
}
guard let sasTransaction = transaction as? MXSASTransaction, !sasTransaction.isIncoming else {
self.verificationManager.requestVerificationByToDevice(withUserId: otherUser.userId, deviceIds: [otherDevice.deviceId], methods: [MXKeyVerificationMethodSAS], success: { [weak self] request in
guard let self = self else {
return
}
sself.transaction = sasTransaction
self.request = request
sself.update(viewState: .loaded)
sself.registerTransactionDidStateChangeNotification(transaction: sasTransaction)
self.update(viewState: .loaded)
self.registerKeyVerificationRequestDidChangeNotification(for: request)
}, failure: {[weak self] error in
self?.update(viewState: .error(error))
})
}
private func cancelTransaction() {
guard let transaction = self.transaction else {
return
}
transaction.cancel(with: MXTransactionCancelCode.user())
private func cancelRequest() {
request?.cancel(with: MXTransactionCancelCode.user(), success: nil)
}
private func update(viewState: DeviceVerificationStartViewState) {
@ -98,37 +90,41 @@ final class DeviceVerificationStartViewModel: DeviceVerificationStartViewModelTy
}
// MARK: - MXKeyVerificationTransactionDidChange
// MARK: - MXKeyVerificationRequestDidChange
private func registerTransactionDidStateChangeNotification(transaction: MXSASTransaction) {
NotificationCenter.default.addObserver(self, selector: #selector(transactionDidStateChange(notification:)), name: NSNotification.Name.MXKeyVerificationTransactionDidChange, object: transaction)
private func registerKeyVerificationRequestDidChangeNotification(for request: MXKeyVerificationRequest) {
NotificationCenter.default.addObserver(self, selector: #selector(requestDidStateChange(notification:)), name: .MXKeyVerificationRequestDidChange, object: request)
}
private func unregisterTransactionDidStateChangeNotification() {
NotificationCenter.default.removeObserver(self, name: .MXKeyVerificationTransactionDidChange, object: nil)
private func unregisterKeyVerificationRequestDidChangeNotification() {
NotificationCenter.default.removeObserver(self, name: .MXKeyVerificationRequestDidChange, object: nil)
}
@objc private func transactionDidStateChange(notification: Notification) {
guard let transaction = notification.object as? MXSASTransaction, !transaction.isIncoming else {
@objc private func requestDidStateChange(notification: Notification) {
guard let request = notification.object as? MXKeyVerificationRequest, request.requestId == self.request?.requestId else {
return
}
switch transaction.state {
case MXSASTransactionStateShowSAS:
self.unregisterTransactionDidStateChangeNotification()
self.coordinatorDelegate?.deviceVerificationStartViewModel(self, didCompleteWithOutgoingTransaction: transaction)
case MXSASTransactionStateCancelled:
guard let reason = transaction.reasonCancelCode else {
switch request.state {
case MXKeyVerificationRequestStateAccepted, MXKeyVerificationRequestStateReady:
self.unregisterKeyVerificationRequestDidChangeNotification()
self.coordinatorDelegate?.deviceVerificationStartViewModel(self, otherDidAcceptRequest: request)
case MXKeyVerificationRequestStateCancelled:
guard let reason = request.reasonCancelCode else {
return
}
self.unregisterTransactionDidStateChangeNotification()
self.unregisterKeyVerificationRequestDidChangeNotification()
self.update(viewState: .cancelled(reason))
case MXSASTransactionStateCancelledByMe:
guard let reason = transaction.reasonCancelCode else {
case MXKeyVerificationRequestStateCancelledByMe:
guard let reason = request.reasonCancelCode else {
return
}
self.unregisterTransactionDidStateChangeNotification()
self.unregisterKeyVerificationRequestDidChangeNotification()
self.update(viewState: .cancelledByMe(reason))
case MXKeyVerificationRequestStateExpired:
self.unregisterKeyVerificationRequestDidChangeNotification()
self.update(viewState: .error(UserVerificationStartViewModelError.keyVerificationRequestExpired))
default:
break
}

View file

@ -25,8 +25,7 @@ protocol DeviceVerificationStartViewModelViewDelegate: AnyObject {
protocol DeviceVerificationStartViewModelCoordinatorDelegate: AnyObject {
func deviceVerificationStartViewModelDidUseLegacyVerification(_ viewModel: DeviceVerificationStartViewModelType)
func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didCompleteWithOutgoingTransaction transaction: MXSASTransaction)
func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didTransactionCancelled transaction: MXSASTransaction)
func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, otherDidAcceptRequest request: MXKeyVerificationRequest)
func deviceVerificationStartViewModelDidCancel(_ viewModel: DeviceVerificationStartViewModelType)
}

View file

@ -189,6 +189,7 @@ extension UserVerificationCoordinator: KeyVerificationCoordinatorDelegate {
func keyVerificationCoordinatorDidComplete(_ coordinator: KeyVerificationCoordinatorType, otherUserId: String, otherDeviceId: String) {
dismissPresenter(coordinator: coordinator)
delegate?.userVerificationCoordinatorDidComplete(self)
}
func keyVerificationCoordinatorDidCancel(_ coordinator: KeyVerificationCoordinatorType) {

View file

@ -1743,8 +1743,18 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
return;
}
if (![mxSession.crypto.crossSigning isKindOfClass:[MXLegacyCrossSigning class]]) {
MXLogFailure(@"Device dehydratation is currently only supported by legacy cross signing, add support to all implementations");
if (failure)
{
failure(nil);
}
return;
}
MXLegacyCrossSigning *crossSigning = (MXLegacyCrossSigning *)mxSession.crypto.crossSigning;;
MXLogDebug(@"[MXKAccount] attemptDeviceDehydrationWithRetry: starting device dehydration");
[[MXKAccountManager sharedManager].dehydrationService dehydrateDeviceWithMatrixRestClient:mxRestClient crypto:mxSession.crypto dehydrationKey:keyData success:^(NSString *deviceId) {
[[MXKAccountManager sharedManager].dehydrationService dehydrateDeviceWithMatrixRestClient:mxRestClient crossSigning:crossSigning dehydrationKey:keyData success:^(NSString *deviceId) {
MXLogDebug(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device successfully dehydrated");
if (success)

View file

@ -65,9 +65,12 @@
_event = event;
_displayFix = MXKRoomBubbleComponentDisplayFixNone;
if ([event.content[@"format"] isEqualToString:kMXRoomMessageFormatHTML])
NSString *format = event.content[@"format"];
if ([format isKindOfClass:[NSString class]] && [format isEqualToString:kMXRoomMessageFormatHTML])
{
if ([((NSString*)event.content[@"formatted_body"]) containsString:@"<blockquote"])
NSString *formattedBody = (NSString*)event.content[@"formatted_body"];
if ([formattedBody isKindOfClass:[NSString class]] && [formattedBody containsString:@"<blockquote"])
{
_displayFix |= MXKRoomBubbleComponentDisplayFixHtmlBlockquote;
}

View file

@ -440,7 +440,9 @@
- (void)startUserVerification
{
[[AppDelegate theDelegate] presentUserVerificationForRoomMember:self.mxRoomMember session:self.mainSession];
[[AppDelegate theDelegate] presentUserVerificationForRoomMember:self.mxRoomMember session:self.mainSession completion:^{
[self refreshUserEncryptionTrustLevel];
}];
}
- (void)presentUserVerification
@ -1332,6 +1334,7 @@
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
[self refreshUserEncryptionTrustLevel];
[self dismissKeyVerificationCoordinatorBridgePresenter];
}

View file

@ -806,7 +806,7 @@ static BOOL _disableLongPressGestureOnEvent;
mimetype = bubbleData.attachment.contentInfo[@"mimetype"];
}
if ([mimetype isEqualToString:@"image/gif"])
if ([mimetype isKindOfClass:[NSString class]] && [mimetype isEqualToString:@"image/gif"])
{
if (_isAutoAnimatedGif)
{

View file

@ -88,7 +88,7 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
let subView: UIView = hostingViewController.view
self.addSubview(subView)
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
self.translatesAutoresizingMaskIntoConstraints = false
subView.translatesAutoresizingMaskIntoConstraints = false
heightConstraint = subView.heightAnchor.constraint(equalToConstant: height)
NSLayoutConstraint.activate([
@ -103,7 +103,13 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
.sink(receiveValue: { [weak self] idealHeight in
guard let self = self else { return }
self.updateToolbarHeight(wysiwygHeight: idealHeight)
})
}),
// Required to update the view constraints after minimise/maximise is tapped
wysiwygViewModel.$idealHeight
.removeDuplicates()
.sink { [weak hostingViewController] _ in
hostingViewController?.view.setNeedsLayout()
}
]
update(theme: ThemeService.shared().theme)

View file

@ -324,7 +324,7 @@ TableViewSectionsDelegate>
// Crypto sessions section
if (RiotSettings.shared.settingsSecurityScreenShowSessions)
if (RiotSettings.shared.settingsSecurityScreenShowSessions && !RiotSettings.shared.enableNewSessionManager)
{
Section *sessionsSection = [Section sectionWithTag:SECTION_CRYPTO_SESSIONS];
@ -627,7 +627,7 @@ TableViewSectionsDelegate>
- (void)loadCrossSigning
{
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
id<MXCrossSigning> crossSigning = self.mainSession.crypto.crossSigning;
[crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) {
if (stateUpdated)
@ -643,7 +643,7 @@ TableViewSectionsDelegate>
{
NSInteger numberOfRowsInCrossSigningSection;
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
id<MXCrossSigning> crossSigning = self.mainSession.crypto.crossSigning;
switch (crossSigning.state)
{
case MXCrossSigningStateNotBootstrapped: // Action: Bootstrap
@ -661,7 +661,7 @@ TableViewSectionsDelegate>
- (NSAttributedString*)crossSigningInformation
{
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
id<MXCrossSigning> crossSigning = self.mainSession.crypto.crossSigning;
NSString *crossSigningInformation;
switch (crossSigning.state)
@ -708,7 +708,7 @@ TableViewSectionsDelegate>
buttonCell.mxkButton.accessibilityIdentifier = nil;
// And customise it
MXCrossSigning *crossSigning = self.mainSession.crypto.crossSigning;
id<MXCrossSigning> crossSigning = self.mainSession.crypto.crossSigning;
switch (crossSigning.state)
{
case MXCrossSigningStateNotBootstrapped: // Action: Bootstrap

View file

@ -106,7 +106,11 @@ class QRLoginService: NSObject, QRLoginServiceProtocol {
}
func stopScanning(destroy: Bool) {
zxCapture.delegate = nil
if (zxCapture.delegate != nil) {
// Setting the zxCapture to nil without checking makes it start
// scanning and implicitly requesting camera access
zxCapture.delegate = nil
}
guard zxCapture.running else {
return
@ -292,7 +296,7 @@ class QRLoginService: NSObject, QRLoginServiceProtocol {
MXLog.debug("[QRLoginService] Received cross-signing details \(responsePayload)")
if let masterKeyFromVerifyingDevice = responsePayload.masterKey,
let localMasterKey = session.crypto.crossSigningKeys(forUser: session.myUserId).masterKeys?.keys {
let localMasterKey = session.crypto.crossSigning.crossSigningKeys(forUser: session.myUserId)?.masterKeys?.keys {
guard masterKeyFromVerifyingDevice == localMasterKey else {
MXLog.error("[QRLoginService] Received invalid master key from verifying device")
await teardownRendezvous(state: .failed(error: .rendezvousFailed))
@ -348,6 +352,7 @@ class QRLoginService: NSObject, QRLoginServiceProtocol {
await teardownRendezvous()
}
@MainActor
private func teardownRendezvous(state: QRLoginServiceState? = nil) async {
// Stop listening for changes, try deleting the resource
_ = await rendezvousService?.tearDown()

View file

@ -36,6 +36,7 @@ struct ScreenList: View {
VStack {
TextField("Search", text: $searchQuery)
.textFieldStyle(.roundedBorder)
.autocorrectionDisabled()
.padding(.horizontal)
.accessibilityIdentifier("searchQueryTextField")
.onChange(of: searchQuery, perform: search)

View file

@ -20,16 +20,33 @@ import XCTest
extension XCUIApplication {
func goToScreenWithIdentifier(_ identifier: String) {
// Search for the screen identifier
textFields["searchQueryTextField"].tap()
typeText(identifier)
let textField = textFields["searchQueryTextField"]
let button = buttons[identifier]
let footer = staticTexts["footerText"]
while !button.isHittable, !footer.isHittable {
tables.firstMatch.swipeUp()
// Sometimes the search gets stuck without showing any results. Try to nudge it along
for _ in 0...10 {
textField.clearAndTypeText(identifier)
if button.exists {
break
}
}
button.tap()
}
}
private extension XCUIElement {
func clearAndTypeText(_ text: String) {
guard let stringValue = value as? String else {
XCTFail("Tried to clear and type text into a non string value")
return
}
tap()
let deleteString = String(repeating: XCUIKeyboardKey.delete.rawValue, count: stringValue.count)
typeText(deleteString)
typeText(text)
}
}

View file

@ -30,6 +30,19 @@ final class ComposerUITests: MockScreenTestCase {
wysiwygTextView.typeText("test")
XCTAssertTrue(sendButton.exists)
XCTAssertFalse(app.buttons["editButton"].exists)
let maximiseButton = app.buttons["maximiseButton"]
let minimiseButton = app.buttons["minimiseButton"]
XCTAssertFalse(minimiseButton.exists)
XCTAssertTrue(maximiseButton.exists)
maximiseButton.tap()
XCTAssertTrue(minimiseButton.exists)
XCTAssertFalse(maximiseButton.exists)
minimiseButton.tap()
XCTAssertFalse(minimiseButton.exists)
XCTAssertTrue(maximiseButton.exists)
}
func testReplyMode() throws {
@ -56,6 +69,19 @@ final class ComposerUITests: MockScreenTestCase {
let textViewContent = wysiwygTextView.value as! String
XCTAssertFalse(textViewContent.isEmpty)
XCTAssertFalse(cancelButton.exists)
let maximiseButton = app.buttons["maximiseButton"]
let minimiseButton = app.buttons["minimiseButton"]
XCTAssertFalse(minimiseButton.exists)
XCTAssertTrue(maximiseButton.exists)
maximiseButton.tap()
XCTAssertTrue(minimiseButton.exists)
XCTAssertFalse(maximiseButton.exists)
minimiseButton.tap()
XCTAssertFalse(minimiseButton.exists)
XCTAssertTrue(maximiseButton.exists)
}
func testEditMode() throws {
@ -82,5 +108,18 @@ final class ComposerUITests: MockScreenTestCase {
let textViewContent = wysiwygTextView.value as! String
XCTAssertTrue(textViewContent.isEmpty)
XCTAssertFalse(cancelButton.exists)
let maximiseButton = app.buttons["maximiseButton"]
let minimiseButton = app.buttons["minimiseButton"]
XCTAssertFalse(minimiseButton.exists)
XCTAssertTrue(maximiseButton.exists)
maximiseButton.tap()
XCTAssertTrue(minimiseButton.exists)
XCTAssertFalse(maximiseButton.exists)
minimiseButton.tap()
XCTAssertFalse(minimiseButton.exists)
XCTAssertTrue(maximiseButton.exists)
}
}

View file

@ -51,6 +51,14 @@ struct Composer: View {
viewModel.viewState.sendMode == .edit ? "editButton" : "sendButton"
}
private var toggleButtonAcccessibilityIdentifier: String {
wysiwygViewModel.maximised ? "minimiseButton" : "maximiseButton"
}
private var toggleButtonImageName: String {
wysiwygViewModel.maximised ? Asset.Images.minimiseComposer.name : Asset.Images.maximiseComposer.name
}
private var borderColor: Color {
focused ? theme.colors.quarterlyContent : theme.colors.quinaryContent
}
@ -76,8 +84,6 @@ struct Composer: View {
var body: some View {
VStack(spacing: 8) {
let rect = RoundedRectangle(cornerRadius: cornerRadius)
// TODO: Fix maximise animation bugs before re-enabling
// ZStack(alignment: .topTrailing) {
VStack(spacing: 12) {
if viewModel.viewState.shouldDisplayContext {
HStack {
@ -103,36 +109,39 @@ struct Composer: View {
.padding(.top, 8)
.padding(.horizontal, horizontalPadding)
}
WysiwygComposerView(
focused: $focused,
content: wysiwygViewModel.content,
replaceText: wysiwygViewModel.replaceText,
select: wysiwygViewModel.select,
didUpdateText: wysiwygViewModel.didUpdateText
)
.tintColor(theme.colors.accent)
.placeholder(viewModel.viewState.placeholder, color: theme.colors.tertiaryContent)
.frame(height: wysiwygViewModel.idealHeight)
.padding(.horizontal, horizontalPadding)
.onAppear {
wysiwygViewModel.setup()
HStack(alignment: .top, spacing: 0) {
WysiwygComposerView(
focused: $focused,
content: wysiwygViewModel.content,
replaceText: wysiwygViewModel.replaceText,
select: wysiwygViewModel.select,
didUpdateText: wysiwygViewModel.didUpdateText
)
.tintColor(theme.colors.accent)
.placeholder(viewModel.viewState.placeholder, color: theme.colors.tertiaryContent)
.frame(height: wysiwygViewModel.idealHeight)
.onAppear {
wysiwygViewModel.setup()
}
Button {
wysiwygViewModel.maximised.toggle()
} label: {
Image(toggleButtonImageName)
.resizable()
.foregroundColor(theme.colors.tertiaryContent)
.frame(width: 16, height: 16)
}
.accessibilityIdentifier(toggleButtonAcccessibilityIdentifier)
.padding(.leading, 12)
.padding(.trailing, 4)
}
// Button {
// withAnimation(.easeInOut(duration: 0.25)) {
// viewModel.maximised.toggle()
// }
// } label: {
// Image(viewModel.maximised ? Asset.Images.minimiseComposer.name : Asset.Images.maximiseComposer.name)
// .foregroundColor(theme.colors.tertiaryContent)
// }
// .padding(.top, 4)
// .padding(.trailing, 12)
// }
.padding(.horizontal, horizontalPadding)
.padding(.top, topPadding)
.padding(.bottom, verticalPadding)
}
.clipShape(rect)
.overlay(rect.stroke(borderColor, lineWidth: 1))
.animation(.easeInOut(duration: 0.1), value: wysiwygViewModel.idealHeight)
.padding(.horizontal, horizontalPadding)
.padding(.top, 8)
.onTapGesture {
@ -148,7 +157,6 @@ struct Composer: View {
.resizable()
.foregroundColor(theme.colors.tertiaryContent)
.frame(width: 14, height: 14)
}
.frame(width: 36, height: 36)
.background(Circle().fill(theme.colors.system))

View file

@ -24,36 +24,45 @@ class TimelinePollUITests: MockScreenTestCase {
XCTAssert(app.staticTexts["Question"].exists)
XCTAssert(app.staticTexts["20 votes cast"].exists)
XCTAssert(app.buttons["First, 10 votes"].exists)
XCTAssertEqual(app.buttons["First, 10 votes"].value as! String, "50%")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Count"].label, "10 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption0Progress"].value as? String, "50%")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Count"].label, "5 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption1Progress"].value as? String, "25%")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Count"].label, "15 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption2Progress"].value as? String, "75%")
XCTAssert(app.buttons["Second, 5 votes"].exists)
XCTAssertEqual(app.buttons["Second, 5 votes"].value as! String, "25%")
app.buttons["PollAnswerOption0"].tap()
XCTAssert(app.buttons["Third, 15 votes"].exists)
XCTAssertEqual(app.buttons["Third, 15 votes"].value as! String, "75%")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Count"].label, "11 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption0Progress"].value as? String, "55%")
app.buttons["First, 10 votes"].tap()
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Count"].label, "4 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption1Progress"].value as? String, "20%")
XCTAssert(app.buttons["First, 11 votes"].exists)
XCTAssertEqual(app.buttons["First, 11 votes"].value as! String, "55%")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Count"].label, "15 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption2Progress"].value as? String, "75%")
XCTAssert(app.buttons["Second, 4 votes"].exists)
XCTAssertEqual(app.buttons["Second, 4 votes"].value as! String, "20%")
app.buttons["PollAnswerOption2"].tap()
XCTAssert(app.buttons["Third, 15 votes"].exists)
XCTAssertEqual(app.buttons["Third, 15 votes"].value as! String, "75%")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Count"].label, "10 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption0Progress"].value as? String, "50%")
app.buttons["Third, 15 votes"].tap()
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Count"].label, "4 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption1Progress"].value as? String, "20%")
XCTAssert(app.buttons["First, 10 votes"].exists)
XCTAssertEqual(app.buttons["First, 10 votes"].value as! String, "50%")
XCTAssert(app.buttons["Second, 4 votes"].exists)
XCTAssertEqual(app.buttons["Second, 4 votes"].value as! String, "20%")
XCTAssert(app.buttons["Third, 16 votes"].exists)
XCTAssertEqual(app.buttons["Third, 16 votes"].value as! String, "80%")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Count"].label, "16 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption2Progress"].value as? String, "80%")
}
func testOpenUndisclosedPoll() {
@ -62,29 +71,29 @@ class TimelinePollUITests: MockScreenTestCase {
XCTAssert(app.staticTexts["Question"].exists)
XCTAssert(app.staticTexts["20 votes cast"].exists)
XCTAssert(!app.buttons["First, 10 votes"].exists)
XCTAssert(app.buttons["First"].exists)
XCTAssertTrue((app.buttons["First"].value as! String).isEmpty)
XCTAssert(!app.buttons["Second, 5 votes"].exists)
XCTAssert(app.buttons["Second"].exists)
XCTAssertTrue((app.buttons["Second"].value as! String).isEmpty)
XCTAssert(!app.buttons["Third, 15 votes"].exists)
XCTAssert(app.buttons["Third"].exists)
XCTAssertTrue((app.buttons["Third"].value as! String).isEmpty)
app.buttons["First"].tap()
XCTAssert(app.buttons["First"].exists)
XCTAssert(app.buttons["Second"].exists)
XCTAssert(app.buttons["Third"].exists)
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssert(!app.staticTexts["PollAnswerOption0Count"].exists)
XCTAssert(!app.progressIndicators["PollAnswerOption0Progress"].exists)
app.buttons["Third"].tap()
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssert(!app.staticTexts["PollAnswerOption1Count"].exists)
XCTAssert(!app.progressIndicators["PollAnswerOption1Progress"].exists)
XCTAssert(app.buttons["First"].exists)
XCTAssert(app.buttons["Second"].exists)
XCTAssert(app.buttons["Third"].exists)
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
XCTAssert(!app.staticTexts["PollAnswerOption2Count"].exists)
XCTAssert(!app.progressIndicators["PollAnswerOption2Progress"].exists)
app.buttons["PollAnswerOption0"].tap()
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
app.buttons["PollAnswerOption2"].tap()
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
}
func testClosedDisclosedPoll() {
@ -100,25 +109,31 @@ class TimelinePollUITests: MockScreenTestCase {
private func checkClosedPoll() {
XCTAssert(app.staticTexts["Question"].exists)
XCTAssert(app.staticTexts["Final results based on 20 votes"].exists)
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Count"].label, "10 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption0Progress"].value as? String, "50%")
XCTAssert(app.buttons["First, 10 votes"].exists)
XCTAssertEqual(app.buttons["First, 10 votes"].value as! String, "50%")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Count"].label, "5 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption1Progress"].value as? String, "25%")
XCTAssert(app.buttons["Second, 5 votes"].exists)
XCTAssertEqual(app.buttons["Second, 5 votes"].value as! String, "25%")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Count"].label, "15 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption2Progress"].value as? String, "75%")
XCTAssert(app.buttons["Third, 15 votes"].exists)
XCTAssertEqual(app.buttons["Third, 15 votes"].value as! String, "75%")
app.buttons["PollAnswerOption0"].tap()
app.buttons["First, 10 votes"].tap()
XCTAssertEqual(app.staticTexts["PollAnswerOption0Label"].label, "First")
XCTAssertEqual(app.staticTexts["PollAnswerOption0Count"].label, "10 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption0Progress"].value as? String, "50%")
XCTAssert(app.buttons["First, 10 votes"].exists)
XCTAssertEqual(app.buttons["First, 10 votes"].value as! String, "50%")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Label"].label, "Second")
XCTAssertEqual(app.staticTexts["PollAnswerOption1Count"].label, "5 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption1Progress"].value as? String, "25%")
XCTAssert(app.buttons["Second, 5 votes"].exists)
XCTAssertEqual(app.buttons["Second, 5 votes"].value as! String, "25%")
XCTAssert(app.buttons["Third, 15 votes"].exists)
XCTAssertEqual(app.buttons["Third, 15 votes"].value as! String, "75%")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Label"].label, "Third")
XCTAssertEqual(app.staticTexts["PollAnswerOption2Count"].label, "15 votes")
XCTAssertEqual(app.progressIndicators["PollAnswerOption2Progress"].value as? String, "75%")
}
}

View file

@ -41,6 +41,7 @@ struct TimelinePollAnswerOptionButton: View {
.overlay(rect.stroke(borderAccentColor, lineWidth: 1.0))
.accentColor(progressViewAccentColor)
}
.accessibilityIdentifier("PollAnswerOption\(optionIndex)")
}
var answerOptionLabel: some View {
@ -53,6 +54,7 @@ struct TimelinePollAnswerOptionButton: View {
Text(answerOption.text)
.font(theme.fonts.body)
.foregroundColor(theme.colors.primaryContent)
.accessibilityIdentifier("PollAnswerOption\(optionIndex)Label")
if poll.closed, answerOption.winner {
Spacer()
@ -66,11 +68,13 @@ struct TimelinePollAnswerOptionButton: View {
total: Double(poll.totalAnswerCount))
.progressViewStyle(LinearProgressViewStyle())
.scaleEffect(x: 1.0, y: 1.2, anchor: .center)
.accessibilityIdentifier("PollAnswerOption\(optionIndex)Progress")
if poll.shouldDiscloseResults {
Text(answerOption.count == 1 ? VectorL10n.pollTimelineOneVote : VectorL10n.pollTimelineVotesCount(Int(answerOption.count)))
.font(theme.fonts.footnote)
.foregroundColor(poll.closed && answerOption.winner ? theme.colors.accent : theme.colors.secondaryContent)
.accessibilityIdentifier("PollAnswerOption\(optionIndex)Count")
}
}
}
@ -92,6 +96,10 @@ struct TimelinePollAnswerOptionButton: View {
return answerOption.selected ? theme.colors.accent : theme.colors.quarterlyContent
}
var optionIndex: Int {
poll.answerOptions.firstIndex { $0.id == answerOption.id } ?? Int.max
}
}
struct TimelinePollAnswerOptionButton_Previews: PreviewProvider {

View file

@ -21,10 +21,7 @@ class UserSuggestionUITests: MockScreenTestCase {
func testUserSuggestionScreen() throws {
app.goToScreenWithIdentifier(MockUserSuggestionScreenState.multipleResults.title)
XCTAssert(app.tables.firstMatch.waitForExistence(timeout: 1))
let firstButton = app.tables.firstMatch.buttons.firstMatch
_ = firstButton.waitForExistence(timeout: 10)
XCTAssert(firstButton.identifier == "displayNameText-userIdText")
let firstButton = app.buttons["displayNameText-userIdText"].firstMatch
XCTAssert(firstButton.waitForExistence(timeout: 10))
}
}

View file

@ -18,7 +18,7 @@ import RiotSwiftUI
import XCTest
class UserSessionDetailsUITests: MockScreenTestCase {
func test_longPressDetailsCell_CopiesValueToClipboard() throws {
func disabled_broken_xcode14_test_longPressDetailsCell_CopiesValueToClipboard() throws {
app.goToScreenWithIdentifier(MockUserSessionDetailsScreenState.allSections.title)
UIPasteboard.general.string = ""

View file

@ -111,7 +111,7 @@ private class MockSession: MXSession {
}
/// A mock `MXCrypto` that can override the `canCrossSign` state.
private class MockCrypto: MXCrypto {
private class MockCrypto: MXLegacyCrypto {
let canCrossSign: Bool
override var crossSigning: MXCrossSigning! { MockCrossSigning(canCrossSign: canCrossSign) }
@ -123,7 +123,7 @@ private class MockCrypto: MXCrypto {
}
/// A mock `MXCrossSigning` with an overridden `canCrossSign` property.
private class MockCrossSigning: MXCrossSigning {
private class MockCrossSigning: MXLegacyCrossSigning {
let canCrossSignMock: Bool
override var canCrossSign: Bool { canCrossSignMock }

1
changelog.d/6954.change Normal file
View file

@ -0,0 +1 @@
Added the maximise/minimise toggle button to the Rich Text Composer

View file

@ -0,0 +1 @@
Verification: Deprecate legacy device-to-device verification

View file

@ -0,0 +1 @@
Crypto: Define MXCrypto and MXCrossSigning as protocols

View file

@ -0,0 +1 @@
Add Z-Labs tag for rich text editor and update to the new label naming.

View file

@ -0,0 +1 @@
Hide the old session list when the new device manager is enabled.

View file

@ -21,7 +21,7 @@ platform :ios do
before_all do
# Ensure used Xcode version
xcversion(version: "~> 13.4")
xcversion(version: "~> 14.0.1")
end
#### Public ####
@ -196,7 +196,7 @@ platform :ios do
run_tests(
workspace: "Riot.xcworkspace",
scheme: "RiotSwiftUITests",
device: "iPhone 13",
device: "iPhone 14",
code_coverage: true,
# Test result configuration
result_bundle: true,