From 0bd4e016a9d1bf722201a9722aa75e8448a747cf Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 28 Mar 2025 16:03:45 +0100 Subject: [PATCH 01/61] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index e0c97cb89..b4b2a9e9d 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.27 -CURRENT_PROJECT_VERSION = 1.11.27 +MARKETING_VERSION = 1.11.28 +CURRENT_PROJECT_VERSION = 1.11.28 From f7fc8b807a94d76a6cc5023eb3ecfb4fd53752d5 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 7 May 2025 12:36:23 +0100 Subject: [PATCH 02/61] Support for experimental MSC4286 to not render external payment details Ref: https://github.com/matrix-org/matrix-spec-proposals/pull/4286 --- .../Categories/DTHTMLElement+MatrixKit.swift | 10 ++++++++++ .../MatrixKitTests/MXKEventFormatterTests.m | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Riot/Modules/MatrixKit/Categories/DTHTMLElement+MatrixKit.swift b/Riot/Modules/MatrixKit/Categories/DTHTMLElement+MatrixKit.swift index 012c4eace..6dc0f9cfb 100644 --- a/Riot/Modules/MatrixKit/Categories/DTHTMLElement+MatrixKit.swift +++ b/Riot/Modules/MatrixKit/Categories/DTHTMLElement+MatrixKit.swift @@ -23,6 +23,16 @@ public extension DTHTMLElement { // Remove any attachments to fix rendering. textAttachment = nil + // Handle special case for span with data-mx-external-payment-details + // This could be based on Storefront.current.countryCode to show the link + // content in unrestricted countries. e.g. currently USA + if name == "span", + let attributes = attributes as? [String: String], + attributes["data-msc4286-external-payment-details"] != nil { + parent.removeChildNode(self) + return + } + // If the element has plain text content show that, // otherwise prevent the tag from displaying. if let stringContent = attributedString()?.string, diff --git a/RiotTests/MatrixKitTests/MXKEventFormatterTests.m b/RiotTests/MatrixKitTests/MXKEventFormatterTests.m index f16f786eb..24457b990 100644 --- a/RiotTests/MatrixKitTests/MXKEventFormatterTests.m +++ b/RiotTests/MatrixKitTests/MXKEventFormatterTests.m @@ -239,6 +239,24 @@ Please see LICENSE in the repository root for full details. XCTAssertFalse(hasAttachment, @"iFrame attachments should be removed as they're not included in the allowedHTMLTags array."); } +- (void)testMxExternalPaymentDetailsRemoved +{ + // Given an HTML string containing a with data-mx-external-payment-details. + NSString *html = @"This is visible. But text is hidden and this link too"; + + // When rendering this string as an attributed string. + NSAttributedString *attributedString = [eventFormatter renderHTMLString:html + forEvent:anEvent + withRoomState:nil + andLatestRoomState:nil]; + + // Then the attributed string should have the stripped and not include any attachments. + XCTAssertEqualObjects(attributedString.string, @"This is visible", @"The tag content should be removed."); + + BOOL hasAttachment = [attributedString containsAttachmentsInRange:NSMakeRange(0, attributedString.length)]; + XCTAssertFalse(hasAttachment, @"span attachments should be removed as they're not included in the allowedHTMLTags array."); +} + - (void)testRenderHTMLStringWithMXReply { // Given an HTML string representing a matrix reply. From 866d3e1b5da731d93cd5a650506b38a896d241c5 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 26 May 2025 17:48:10 +0100 Subject: [PATCH 03/61] Changelog --- changelog.d/pr-7927.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-7927.change diff --git a/changelog.d/pr-7927.change b/changelog.d/pr-7927.change new file mode 100644 index 000000000..05f943e8e --- /dev/null +++ b/changelog.d/pr-7927.change @@ -0,0 +1 @@ +Support for experimental MSC4286 during event rendering. \ No newline at end of file From 09a523ff3cd13c993eb830b54947002011ff0c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=84=82=F0=9D=95=A0=F0=9D=95=A0=F0=9D=95=A0=F0=9D=95=9D?= =?UTF-8?q?=20=28=F0=9D=95=98=F0=9D=95=9A=F0=9D=95=A5=F0=9D=95=99?= =?UTF-8?q?=F0=9D=95=A6=F0=9D=95=93=2E=F0=9D=95=94=F0=9D=95=A0=F0=9D=95=9E?= =?UTF-8?q?/=E2=84=82=F0=9D=95=A0=F0=9D=95=A0=F0=9D=95=A0=F0=9D=95=9D=29?= Date: Sun, 25 May 2025 20:35:33 +0000 Subject: [PATCH 04/61] Translated using Weblate (Latvian) Currently translated at 12.5% (1 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/lv/ --- Riot/Assets/lv.lproj/InfoPlist.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/lv.lproj/InfoPlist.strings b/Riot/Assets/lv.lproj/InfoPlist.strings index a1cc84b8d..d84040979 100644 --- a/Riot/Assets/lv.lproj/InfoPlist.strings +++ b/Riot/Assets/lv.lproj/InfoPlist.strings @@ -3,3 +3,4 @@ "NSPhotoLibraryUsageDescription" = "Foto bibliotēka tiek izmantota, lai nosūtītu fotoattēlus un video."; "NSMicrophoneUsageDescription" = "Mikrofons tiek izmantots, lai uzņemtu video un veiktu zvanus."; "NSContactsUsageDescription" = "Kontaktu grāmata tiek izmantota, lai meklētu lietotājus pēc epasta adreses vai telefona numura Riot aplikācijā."; +"NSFaceIDUsageDescription" = "Face ID tiek izmantots, lai piekļūtu lietotnei."; From 966202ad016798431b600f313c994031e36f77bf Mon Sep 17 00:00:00 2001 From: Basheer Radman Date: Sun, 6 Apr 2025 14:36:34 +0000 Subject: [PATCH 05/61] Translated using Weblate (Arabic) Currently translated at 82.5% (2003 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ar/ --- Riot/Assets/ar.lproj/Vector.strings | 145 ++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index d14eab146..2a3f34ccc 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2080,3 +2080,148 @@ "poll_timeline_not_closed_subtitle" = "الرجاء المحاولة مرة أخرى"; "poll_edit_form_post_failure_title" = "فشل في نشر الاستطلاع"; "location_sharing_title" = "موقع"; +"room_details_fail_to_update_history_visibility" = "فشل في تحديث رؤية التاريخ"; +"room_details_copy_room_address" = "عنوان غرفة النسخ"; +"room_details_copy_room_url" = "نسخ عنوان URL للغرفة"; +"widget_integration_missing_room_id" = "room_id مفقود في الطلب."; +"room_access_settings_screen_message" = "قرر من يمكنه العثور على %@ والانضمام إليه."; +"room_access_settings_screen_upgrade_alert_message_no_param" = "سيتمكن أي شخص في مساحة الوالدين من العثور على هذه الغرفة والانضمام إليها - دون الحاجة إلى دعوة الجميع يدويًا. يمكنك تغيير ذلك في إعدادات الغرفة في أي وقت."; +"room_access_settings_screen_upgrade_alert_note" = "يرجى ملاحظة أن الترقية ستؤدي إلى إنشاء نسخة جديدة من الغرفة. ستبقى جميع الرسائل الحالية في هذه الغرفة المؤرشفة."; +"room_access_settings_screen_upgrade_alert_auto_invite_switch" = "دعوة الأعضاء تلقائيًا إلى غرفة جديدة"; +"room_notifs_settings_notify_me_for" = "أعلمني بذلك"; +"e2e_room_key_request_message" = "تطلب جلستك غير الموثقة '%@' مفاتيح التشفير."; +"secure_key_backup_setup_intro_use_security_key_title" = "استخدم مفتاح الأمان"; +"secure_key_backup_setup_existing_backup_error_info" = "قم بإلغاء قفله لإعادة استخدامه في النسخ الاحتياطي الآمن أو احذفه لإنشاء نسخة احتياطية جديدة للرسائل في النسخ الاحتياطي الآمن."; +"room_details_fail_to_add_room_aliases" = "فشل في إضافة عناوين الغرف الجديدة"; +"room_details_fail_to_update_room_direct" = "فشل في تحديث العلم المباشر لهذه الغرفة"; +"room_access_settings_screen_restricted_message" = "اسمح لأي شخص في مساحة بالبحث والانضمام.\nسيُطلب منك تأكيد المساحات."; +"room_suggestion_settings_screen_title" = "إنشاء غرفة مقترحة في مساحة"; +"group_details_title" = "تفاصيل المجتمع"; +"group_invitation_format" = "لقد دعاك %@ للانضمام إلى هذا المجتمع"; +"directory_server_type_homeserver" = "اكتب خادمًا رئيسيًا لإدراج الغرف العامة منه"; +"bug_report_send_logs" = "إرسال تسجيلات الدخول"; +"e2e_room_key_request_start_verification" = "بدء التحقق…"; +"key_backup_setup_intro_manual_export_info" = "(متقدم)"; +"room_access_settings_screen_upgrade_alert_upgrading" = "ترقية الغرفة"; +"room_notifs_settings_done_action" = "منتهي"; +"e2e_room_key_request_share_without_verifying" = "شارك دون التحقق"; +"gdpr_consent_not_given_alert_review_now_action" = "قم بالمراجعة الآن"; +"service_terms_modal_description_integration_manager" = "سيسمح لك هذا باستخدام الروبوتات والجسور والأدوات وحزم الملصقات."; +"key_backup_setup_title" = "النسخ الاحتياطي للمفتاح"; +"group_details_home" = "الصفحة الرئيسية"; +"room_details_set_main_address" = "تعيين كعنوان رئيسي"; +"room_notifs_settings_manage_notifications" = "يمكنك إدارة الإشعارات في %@"; +"room_notifs_settings_encrypted_room_notice" = "يرجى ملاحظة أن الإشارات وإشعارات الكلمات الرئيسية غير متوفرة في الغرف المشفرة على الهاتف المحمول."; +"group_details_rooms" = "الغرف"; +"widget_integration_room_not_visible" = "الغرفة %@ غير مرئية."; +"room_widget_permission_room_id_permission" = "معرف الغرفة"; +"service_terms_modal_information_title_integration_manager" = "مدير التكامل"; +"service_terms_modal_information_description_integration_manager" = "يتيح لك مدير التكامل إضافة ميزات من جهات خارجية."; +"secure_key_backup_setup_intro_use_security_key_info" = "‌إنشاء مفتاح أمان لتخزينه في مكان آمن مثل مدير كلمات المرور أو الخزنة."; +"secure_key_backup_setup_cancel_alert_message" = "إذا ألغيت الاشتراك الآن، فقد تفقد رسائلك وبياناتك المشفرة إذا فقدت الوصول إلى بيانات تسجيل الدخول الخاصة بك.\n\nيمكنك أيضًا إعداد النسخ الاحتياطي الآمن وإدارة مفاتيحك في الإعدادات."; +"key_backup_setup_skip_alert_message" = "قد تفقد الرسائل الآمنة إذا قمت بتسجيل الخروج أو فقدت جهازك."; +"widget_integration_missing_user_id" = "معرف المستخدم مفقود في الطلب."; +"widget_picker_manage_integrations" = "إدارة التكاملات…"; +"room_widget_permission_creator_info_title" = "تمت إضافة هذه الودجت بواسطة:"; +"share_extension_auth_prompt" = "قم بتسجيل الدخول إلى التطبيق الرئيسي لمشاركة المحتوى"; +"e2e_room_key_request_message_new_device" = "لقد قمت بإضافة جلسة جديدة '%@'، والتي تطلب مفاتيح التشفير."; +"room_access_settings_screen_setting_room_access" = "الوصول إلى غرفة الإعداد"; +"group_home_multi_rooms_format" = "%tu غرف"; +"group_participants_add_participant" = "إضافة مشارك"; +"group_participants_leave_prompt_msg" = "هل أنت متأكد أنك تريد مغادرة المجموعة؟"; +"room_widget_permission_widget_id_permission" = "معرف الودجت"; +"share_extension_low_quality_video_title" = "سيتم إرسال الفيديو بجودة منخفضة"; +"share_extension_low_quality_video_message" = "أرسل %@ للحصول على جودة أفضل، أو أرسل بجودة منخفضة أدناه."; +"e2e_room_key_request_title" = "طلب مفتاح التشفير"; +"service_terms_modal_decline_button" = "رفض"; +"service_terms_modal_description_identity_server" = "سيسمح هذا لأي شخص بالعثور عليك إذا كان لديه رقم هاتفك أو بريدك الإلكتروني محفوظًا في جهات اتصال هاتفه."; +"room_access_space_chooser_other_spaces_section_info" = "من المحتمل أن تكون هذه أشياء يشارك فيها مسؤولون آخرون في %@."; +"room_access_settings_screen_nav_title" = "الوصول إلى الغرفة"; +"service_terms_modal_table_header_integration_manager" = "شروط مدير التكامل"; +"room_access_settings_screen_public_message" = "يمكن لأي شخص العثور والانضمام."; +"room_notifs_settings_none" = "لا أحد"; +"room_details_fail_to_enable_encryption" = "فشل في تمكين التشفير في هذه الغرفة"; +"room_details_copy_room_id" = "معرف غرفة النسخ"; +"room_access_settings_screen_upgrade_alert_upgrade_button" = "ترقية"; +"room_suggestion_settings_screen_message" = "يتم الترويج للغرف المقترحة لأعضاء الفضاء باعتبارها غرفًا جيدة للانضمام إليها."; +"room_notifs_settings_account_settings" = "إعدادات الحساب"; +"group_participants_remove_prompt_title" = "تأكيد"; +"service_terms_modal_footer" = "يمكن تعطيل هذه الميزة في أي وقت من خلال الإعدادات."; +"deactivate_account_forget_messages_information_part1" = "يرجى نسيان جميع الرسائل التي أرسلتها عندما تم إلغاء تنشيط حسابي ("; +"secure_key_backup_setup_intro_info" = "قم بحماية نفسك من فقدان الوصول إلى الرسائل والبيانات المشفرة عن طريق عمل نسخة احتياطية لمفاتيح التشفير على الخادم الخاص بك."; +"key_backup_setup_intro_manual_export_action" = "تصدير المفاتيح يدويًا"; +"room_widget_permission_avatar_url_permission" = "عنوان URL للصورة الرمزية الخاصة بك"; +"share_extension_failed_to_encrypt" = "فشل الإرسال. تحقق من إعدادات التشفير لهذه الغرفة في التطبيق الرئيسي"; +"secure_key_backup_setup_intro_use_security_passphrase_info" = "أدخل عبارة سرية تعرفها أنت فقط، ثم قم بإنشاء مفتاح للنسخ الاحتياطي."; +"room_details_fail_to_remove_room_aliases" = "فشل في إزالة عناوين الغرف"; +"room_access_settings_screen_private_message" = "يمكن فقط للأشخاص المدعوين العثور على الصفحة والانضمام إليها."; +"room_access_settings_screen_edit_spaces" = "تحرير المساحات"; +"group_details_people" = "الناس"; +"widget_integration_must_be_in_room" = "أنت لست في هذه الغرفة."; +"widget_integration_no_permission_in_room" = "ليس لديك الإذن للقيام بذلك في هذه الغرفة."; +"deactivate_account_informations_part2_emphasize" = "هذا الإجراء لا رجعة فيه."; +"deactivate_account_validate_action" = "إلغاء تنشيط الحساب"; +"deactivate_account_password_alert_message" = "للمتابعة، الرجاء إدخال كلمة مرور حساب Matrix الخاص بك"; +"secure_key_backup_setup_existing_backup_error_unlock_it" = "افتحه"; +"room_notifs_settings_cancel_action" = "إلغاء"; +"share_extension_send_now" = "أرسل الآن"; +"service_terms_modal_title_message" = "للمتابعة، قم بقبول الشروط والأحكام أدناه"; +"room_details_promote_room_suggest_title" = "اقترح على أعضاء المساحة"; +"room_details_fail_to_update_room_canonical_alias" = "فشل في تحديث العنوان الرئيسي"; +"room_details_unset_main_address" = "غير مُعيَّن كعنوان رئيسي"; +"e2e_room_key_request_ignore_request" = "تجاهل الطلب"; +"deactivate_account_forget_messages_information_part3" = ": سيؤدي هذا إلى جعل المستخدمين في المستقبل يرون عرضًا غير كامل للمحادثات)"; +"rerequest_keys_alert_title" = "تم إرسال الطلب"; +"room_details_fail_to_update_room_communities" = "فشل في تحديث المجتمعات ذات الصلة"; +"group_home_one_room_format" = "غرفة واحدة"; +"widget_creation_failure" = "فشل إنشاء الودجت"; +"service_terms_modal_information_title_identity_server" = "خادم الهوية"; +"deactivate_account_forget_messages_information_part2_emphasize" = "تحذير"; +"key_backup_setup_skip_alert_title" = "هل أنت متأكد؟"; +"key_backup_setup_intro_title" = "لا تفقد الرسائل المشفرة أبدًا"; +"widget_picker_title" = "التكاملات"; +"service_terms_modal_accept_button" = "قبول"; +"key_backup_setup_intro_info" = "الرسائل في الغرف المشفرة مؤمنة بتشفير شامل. أنت والمستلم فقط لديهما مفاتيح قراءة هذه الرسائل.\n\nاحتفظ بنسخة احتياطية آمنة من مفاتيحك لتجنب فقدانها."; +"room_access_settings_screen_upgrade_alert_title" = "ترقية الغرفة"; +"room_notifs_settings_all_messages" = "كل الرسائل"; +"deactivate_account_title" = "إلغاء تنشيط الحساب"; +"deactivate_account_informations_part4_emphasize" = "لا يؤدي افتراضيًا إلى نسيان الرسائل التي أرسلتها. "; +"secure_key_backup_setup_intro_use_security_passphrase_title" = "استخدم عبارة أمنية"; +"key_backup_setup_passphrase_title" = "تأمين النسخة الاحتياطية الخاصة بك باستخدام عبارة أمان"; +"bug_report_progress_zipping" = "جمع تسجيلات الدخول"; +"room_details_save_changes_prompt" = "هل تريد حفظ التغييرات؟"; +"room_access_settings_screen_title" = "من يمكنه الوصول إلى هذه الغرفة؟"; +"room_access_settings_screen_upgrade_required" = "الترقية مطلوبة"; +"room_access_settings_screen_upgrade_alert_message" = "سيتمكن أي شخص في %@ من العثور على هذه الغرفة والانضمام إليها - دون الحاجة إلى دعوة الجميع يدويًا. يمكنك تغيير ذلك في أي وقت من إعدادات الغرفة."; +"room_access_space_chooser_known_spaces_section" = "المساحات التي تعرف أنها تحتوي على %@"; +"room_access_space_chooser_other_spaces_section" = "مساحات أو غرف أخرى"; +"room_suggestion_settings_screen_nav_title" = "اقتراح غرفة"; +"room_notifs_settings_mentions_and_keywords" = "الإشارات والكلمات الرئيسية فقط"; +"group_home_one_member_format" = "عضو واحد"; +"group_home_multi_members_format" = "%tu أعضاء"; +"group_participants_leave_prompt_title" = "مغادرة المجموعة"; +"event_formatter_widget_removed" = "تمت إزالة الودجت %@ بواسطة %@"; +"widget_integration_room_not_recognised" = "لم يتم التعرف على هذه الغرفة."; +"widget_integration_positive_power_level" = "يجب أن يكون مستوى الطاقة عددًا صحيحًا موجبًا."; +"widget_integration_manager_disabled" = "يجب عليك تمكين مدير التكامل في الإعدادات"; +"room_widget_permission_webview_information_title" = "قد يؤدي استخدامه إلى تعيين ملفات تعريف الارتباط ومشاركة البيانات مع %@:\n"; +"room_widget_permission_display_name_permission" = "اسم العرض الخاص بك"; +"room_widget_permission_user_id_permission" = "معرف المستخدم الخاص بك"; +"gdpr_consent_not_given_alert_message" = "لمواصلة استخدام %@ homeserver، يجب عليك مراجعة الشروط والأحكام والموافقة عليها."; +"service_terms_modal_table_header_identity_server" = "شروط خادم الهوية"; +"deactivate_account_informations_part1" = "سيؤدي هذا إلى تعطيل حسابك نهائيًا. لن تتمكن من تسجيل الدخول، ولن يتمكن أي شخص من إعادة تسجيل اسم المستخدم نفسه. سيؤدي هذا إلى مغادرة حسابك جميع الغرف التي يشارك فيها، وإزالة تفاصيل حسابك من خادم الهوية الخاص بك. "; +"deactivate_account_informations_part5" = "إذا كنت ترغب في حذف رسائلك، يُرجى وضع علامة في المربع أدناه.\n\nتشبه ميزة رؤية الرسائل في Matrix ميزة البريد الإلكتروني. تعني ميزة \"حذف رسائلك\" أن الرسائل التي أرسلتها لن تُشارك مع أي مستخدمين جدد أو غير مسجلين، بينما سيظل بإمكان المستخدمين المسجلين الذين لديهم حق الوصول إلى هذه الرسائل الوصول إلى نسخهم."; +"deactivate_account_password_alert_title" = "إلغاء تنشيط الحساب"; +"secure_key_backup_setup_intro_title" = "النسخ الاحتياطي الآمن"; +"secure_key_backup_setup_existing_backup_error_title" = "توجد نسخة احتياطية للرسائل بالفعل"; +"secure_key_backup_setup_existing_backup_error_delete_it" = "احذفه"; +"secure_key_backup_setup_cancel_alert_title" = "هل انت متأكد؟"; +"secure_backup_setup_banner_title" = "النسخ الاحتياطي الآمن"; +"secure_backup_setup_banner_subtitle" = "الحماية من فقدان الوصول إلى الرسائل والبيانات المشفرة"; +"key_backup_setup_skip_alert_skip_action" = "تخطي"; +"key_backup_setup_intro_setup_action_without_existing_backup" = "ابدأ باستخدام النسخ الاحتياطي للمفتاح"; +"key_backup_setup_intro_setup_connect_action_with_existing_backup" = "قم بتوصيل هذا الجهاز بـ Key Backup"; +"room_widget_permission_title" = "ودجت تحميل"; +"room_widget_permission_information_title" = "قد يؤدي استخدامه إلى مشاركة البيانات مع %@:\n"; +"service_terms_modal_information_description_identity_server" = "يساعدك خادم الهوية في العثور على جهات الاتصال الخاصة بك، من خلال البحث عن رقم الهاتف أو عنوان البريد الإلكتروني، لمعرفة ما إذا كان لديهم حساب بالفعل."; +"rerequest_keys_alert_message" = "يرجى تشغيل %@ على جهاز آخر يمكنه فك تشفير الرسالة حتى يتمكن من إرسال المفاتيح إلى هذه الجلسة."; From ae81969d34508c6e4b109ee2f3c628e289ff6c63 Mon Sep 17 00:00:00 2001 From: Basheer Radman Date: Mon, 7 Apr 2025 20:29:12 +0000 Subject: [PATCH 06/61] Translated using Weblate (Arabic) Currently translated at 86.1% (2090 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ar/ --- Riot/Assets/ar.lproj/Vector.strings | 88 +++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index 2a3f34ccc..731053d4f 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2225,3 +2225,91 @@ "room_widget_permission_information_title" = "قد يؤدي استخدامه إلى مشاركة البيانات مع %@:\n"; "service_terms_modal_information_description_identity_server" = "يساعدك خادم الهوية في العثور على جهات الاتصال الخاصة بك، من خلال البحث عن رقم الهاتف أو عنوان البريد الإلكتروني، لمعرفة ما إذا كان لديهم حساب بالفعل."; "rerequest_keys_alert_message" = "يرجى تشغيل %@ على جهاز آخر يمكنه فك تشفير الرسالة حتى يتمكن من إرسال المفاتيح إلى هذه الجلسة."; +"key_backup_setup_passphrase_info" = "سنخزن نسخة مشفرة من مفاتيحك على خادمنا. احمِ نسختك الاحتياطية بعبارة للحفاظ عليها آمنة.\n\nلأقصى درجات الأمان، يجب أن تكون كلمة المرور مختلفة عن كلمة مرور حساب Matrix الخاص بك."; +"device_verification_emoji_trophy" = "غنيمة"; +"key_backup_recover_invalid_passphrase_title" = "عبارة أمنية غير صحيحة"; +"key_backup_recover_invalid_recovery_key_title" = "عدم تطابق مفتاح الأمان"; +"key_backup_setup_passphrase_setup_recovery_key_info" = "أو قم بتأمين النسخة الاحتياطية الخاصة بك باستخدام مفتاح أمان، وحفظها في مكان آمن."; +"key_backup_recover_title" = "رسائل آمنة"; +"key_backup_recover_from_private_key_info" = "جاري استعادة النسخة الاحتياطية…"; +"device_verification_emoji_cloud" = "سحاب"; +"device_verification_emoji_clock" = "ساعة"; +"device_verification_emoji_pencil" = "قلم رصاص"; +"key_backup_setup_passphrase_passphrase_invalid" = "حاول إضافة كلمة"; +"key_backup_setup_passphrase_confirm_passphrase_invalid" = "العبارة لا تتطابق"; +"key_backup_setup_success_from_recovery_key_info" = "يتم الآن نسخ مفاتيحك احتياطيًا.\n\nانسخ مفتاح الأمان هذا واحتفظ به في مكان آمن."; +"device_verification_emoji_panda" = "باندا"; +"device_verification_emoji_telephone" = "الهاتف"; +"device_verification_emoji_pig" = "خنزير"; +"device_verification_emoji_paperclip" = "مشبك"; +"device_verification_emoji_ball" = "كرة"; +"device_verification_emoji_guitar" = "غيتار"; +"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "تأكيد العبارة"; +"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = "."; +"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "أدخل مفتاح الأمان"; +"device_verification_emoji_glasses" = "نظارات"; +"device_verification_emoji_unicorn" = "وحيد القرن"; +"device_verification_emoji_flower" = "ورد"; +"device_verification_emoji_tree" = "شجرة"; +"device_verification_emoji_cactus" = "صبار"; +"device_verification_emoji_smiley" = "ابتسامة"; +"device_verification_emoji_scissors" = "مقص"; +"device_verification_emoji_hammer" = "مطرقة"; +"device_verification_emoji_banana" = "موز"; +"device_verification_emoji_turtle" = "سلحفاة"; +"key_backup_setup_passphrase_passphrase_valid" = "عظيم!"; +"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "حفظ مفتاح الأمان"; +"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "لا تعرف عبارة الأمان الخاصة بك؟ يمكنك "; +"device_verification_emoji_octopus" = "الأخطبوط"; +"device_verification_emoji_strawberry" = "الفراولة"; +"device_verification_emoji_heart" = "قلب"; +"device_verification_emoji_hourglass" = "الساعة الرملية"; +"device_verification_emoji_key" = "مفتاح"; +"device_verification_emoji_flag" = "علَم"; +"device_verification_emoji_bicycle" = "دراجة"; +"device_verification_emoji_rocket" = "صاروخ"; +"device_verification_emoji_aeroplane" = "طائرة"; +"device_verification_emoji_horse" = "حصان"; +"device_verification_emoji_elephant" = "فيل"; +"device_verification_emoji_rabbit" = "أرنب"; +"key_backup_setup_success_from_recovery_key_recovery_key_title" = "مفتاح الأمان"; +"device_verification_emoji_rooster" = "ديك"; +"device_verification_emoji_light bulb" = "مصباح كهربائي"; +"key_backup_setup_passphrase_confirm_passphrase_valid" = "عظيم!"; +"key_backup_setup_success_title" = "نجاح!"; +"key_backup_recover_from_passphrase_info" = "استخدم عبارة الأمان الخاصة بك لفتح سجل رسائلك الآمنة"; +"device_verification_emoji_penguin" = "البطريق"; +"device_verification_emoji_apple" = "تفاحة"; +"device_verification_emoji_book" = "كتاب"; +"key_backup_setup_success_from_recovery_key_make_copy_action" = "اصنع نسخة"; +"key_backup_setup_passphrase_setup_recovery_key_action" = "(متقدم) الإعداد باستخدام مفتاح الأمان"; +"key_backup_recover_from_private_key_progress" = "٪@٪٪ مكتمل"; +"device_verification_emoji_fish" = "سمكة"; +"device_verification_emoji_corn" = "حبوب ذرة"; +"device_verification_emoji_robot" = "روبوت"; +"key_backup_setup_passphrase_passphrase_title" = "دخول"; +"device_verification_emoji_umbrella" = "مظلة"; +"device_verification_emoji_cake" = "كعكة"; +"device_verification_emoji_lock" = "قفل"; +"security_settings_crosssigning_bootstrap" = "إعداد"; +"event_formatter_call_decline" = "رفض"; +"key_backup_setup_passphrase_passphrase_placeholder" = "أدخل العبارة"; +"key_backup_setup_passphrase_confirm_passphrase_title" = "تأكيد"; +"key_backup_setup_success_from_passphrase_info" = "يتم نسخ مفاتيحك احتياطيًا.\n\nمفتاح الأمان الخاص بك هو بمثابة شبكة أمان، يمكنك استخدامه لاستعادة الوصول إلى رسائلك المشفرة في حال نسيت كلمة المرور.\n\nاحتفظ بمفتاح الأمان الخاص بك في مكان آمن للغاية، مثل مدير كلمات المرور (أو خزنة)."; +"key_backup_setup_success_from_passphrase_done_action" = "منتهي"; +"key_backup_setup_success_from_recovery_key_made_copy_action" = "لقد قمت بعمل نسخة"; +"key_backup_setup_success_from_secure_backup_info" = "يتم إجراء نسخة احتياطية لمفاتيحك."; +"key_backup_recover_invalid_passphrase" = "لم يتم فك تشفير النسخ الاحتياطي باستخدام هذه العبارة: يرجى التأكد من إدخال عبارة الأمان الصحيحة."; +"key_backup_recover_invalid_recovery_key" = "لم يتمكن من فك تشفير النسخة الاحتياطية باستخدام هذا المفتاح: يرجى التأكد من إدخال مفتاح الأمان الصحيح."; +"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "استخدم مفتاح الأمان الخاص بك"; +"key_backup_recover_from_recovery_key_info" = "استخدم مفتاح الأمان الخاص بك لفتح سجل رسائلك الآمنة"; +"device_verification_emoji_lion" = "الأسد"; +"device_verification_emoji_butterfly" = "فراشة"; +"device_verification_emoji_globe" = "الكرة الأرضية"; +"device_verification_emoji_fire" = "نار"; +"device_verification_emoji_pizza" = "بيتزا"; +"device_verification_emoji_spanner" = "مفتاح البراغي"; +"device_verification_emoji_gift" = "هدية"; +"key_backup_recover_from_passphrase_recover_action" = "فتح التاريخ"; +"device_verification_emoji_mushroom" = "فطر"; +"device_verification_emoji_moon" = "القمر"; From 65e247a0beb19d614475a46be6f1fec9bf41a995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=BAlio=20Sim=C3=B5es=20Martins=20Padilha?= Date: Wed, 9 Apr 2025 14:51:36 +0000 Subject: [PATCH 07/61] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2427 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ --- Riot/Assets/pt_BR.lproj/Vector.strings | 78 +++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings index edd2cf70e..52d254d8b 100644 --- a/Riot/Assets/pt_BR.lproj/Vector.strings +++ b/Riot/Assets/pt_BR.lproj/Vector.strings @@ -2556,8 +2556,8 @@ "authentication_qr_login_start_subtitle" = "Use a câmera neste dispositivo para scannar o QR code mostrado em seu outro dispositivo:"; "authentication_qr_login_start_title" = "Scannar QR code"; "authentication_login_with_qr" = "Fazer signin com QR code"; -"wysiwyg_composer_format_action_underline" = "Aplicar formato sublinhar"; -"wysiwyg_composer_format_action_strikethrough" = "Aplicar formato tachar"; +"wysiwyg_composer_format_action_underline" = "Aplicar formato de sublinhado"; +"wysiwyg_composer_format_action_strikethrough" = "Aplicar formato tachado"; "wysiwyg_composer_format_action_italic" = "Aplicar formato itálico"; // Formatting Actions @@ -2671,3 +2671,77 @@ "room_command_join_room_description" = "Entra na sala com o endereço fornecido"; "room_command_invite_user_description" = "Convida o usuário com o ID fornecido para a sala atual"; "authentication_qr_login_failure_device_not_supported" = "Vincular com este dispositivo não é suportado."; +"key_verification_scan_qr_code_information_other_device" = "Aponte sua câmera para o código QR exibido em seu outro dispositivo para verificar esta sessão"; +"wysiwyg_composer_action_minimise_action" = "Compositor psiquiatra"; +"pill_message" = "Mensagem"; +"sunset_delegated_oidc_registration_not_supported_title" = "Você não pode mais criar uma conta com %1$@ usando este aplicativo"; +"sunset_delegated_oidc_registration_not_supported_message" = "Baixe %1$@ para usar %2$@ na sua conta ou escolha um servidor doméstico diferente."; +"sunset_delegated_oidc_registration_not_supported_generic_error" = "Você não pode mais criar uma conta com o servidor doméstico inserido usando este aplicativo"; +"sunset_download_banner_title" = "Baixar %1$@"; +"sunset_download_banner_message" = "Mais rápido, mais seguro e repleto de poderosas ferramentas de colaboração."; +"sunset_download_banner_learn_more" = "Saber mais"; +"call_unsupported_matrix_rtc_call" = "Chamada não suportada. O novo aplicativo Element X é necessário para participar desta chamada."; +"voice_broadcast_voip_cannot_start_description" = "Você não pode iniciar uma chamada porque está gravando uma transmissão ao vivo. Encerre a transmissão ao vivo para iniciar a chamada."; +"poll_timeline_decryption_error" = "Devido a erros de descriptografia, alguns votos podem não ser contados"; +"wysiwyg_composer_action_maximise_action" = "Expandir compositor"; +"room_command_change_room_topic_description" = "Define o tema da sala"; +"room_action_report" = "Sala de relatórios"; +"room_action_report_prompt_reason" = "Motivo da denúncia desta sala"; +"room_command_discard_session_description" = "Força o descarte da sessão de grupo de saída atual em uma sala criptografada"; +"room_command_error_unknown_command" = "Comando inválido ou não tratado"; +"pill_room_fallback_display_name" = "Espaço/Sala"; +"device_verification_self_verify_wait_recover_secrets_additional_help" = "Não consegue acessar uma sessão %@ existente?"; +"room_waiting_other_participants_title" = "Aguardando a adesão dos usuários %@"; +"voice_broadcast_playback_lock_screen_placeholder" = "Transmissão de voz"; +"device_verification_self_verify_open_on_other_device_title" = "Abra %@ no seu outro dispositivo"; +"key_verification_scan_qr_code_information_other_session" = "Aponte sua câmera para o código QR exibido em seu outro dispositivo para verificar sua sessão"; +"voice_message_broadcast_in_progress_title" = "Não é possível iniciar a mensagem de voz"; +"voice_message_broadcast_in_progress_message" = "Você não pode iniciar uma mensagem de voz, pois está gravando uma transmissão ao vivo. Encerre a transmissão ao vivo para iniciar a gravação da mensagem de voz."; +"notice_display_name_changed_to" = "%@ mudou seu nome de exibição para %@"; +"pill_message_from" = "Mensagem de %@"; +"poll_timeline_loading" = "Carregando..."; +"wysiwyg_composer_format_action_un_indent" = "Diminuir recuo"; +"wysiwyg_composer_format_action_indent" = "Aumentar o recuo"; +"room_details_polls" = "Histórico de pesquisas"; +"poll_history_no_active_poll_text" = "Não há enquetes ativas nesta sala"; +"poll_history_fetching_error" = "Erro ao buscar enquetes."; +"wysiwyg_composer_format_action_code_block" = "Alternar bloco de código"; +"poll_history_detail_view_in_timeline" = "Ver enquete na linha do tempo"; +"settings_acceptable_use" = "Política de Uso Aceitável"; +"launch_loading_generic" = "Sincronizando suas conversas"; +"launch_loading_delay_warning" = "Isso pode demorar um pouco mais.\nObrigado pela sua paciência."; +"poll_history_no_past_poll_text" = "Não há pesquisas anteriores nesta sala"; +"poll_timeline_ended_text" = "Terminou a enquete"; +"home_context_menu_mark_as_unread" = "Marcar como não lido"; +"poll_history_title" = "Histórico de pesquisas"; +"poll_history_active_segment_title" = "Pesquisas ativas"; +"wysiwyg_composer_format_action_unordered_list" = "Alternar lista com marcadores"; +"voice_broadcast_recorder_connection_error" = "Erro de conexão - Gravação pausada"; +"wysiwyg_composer_format_action_quote" = "Alternar citação"; +"manage_session_redirect" = "Você será redirecionado ao provedor de autenticação do seu servidor para concluir o logout."; +"manage_session_redirect_error" = "Funcionalidade indisponível no momento. Entre em contato com o administrador do seu servidor doméstico."; +"room_command_reset_user_power_level_description" = "Usuário Deops com ID fornecido"; +"settings_push_rules_error" = "Ocorreu um erro ao atualizar suas preferências de notificação. Tente alternar sua opção novamente."; +"key_verification_scan_qr_code_title" = "Escaneie o código QR"; +"key_verification_scan_qr_code_information_other_user" = "Aponte sua câmera para o código QR exibido no dispositivo para verificar a sessão"; +"key_verification_scan_qr_code_information_new_session" = "Aponte sua câmera para o código QR exibido em seu outro dispositivo para verificar sua nova sessão"; +"voice_broadcast_connection_error_title" = "Erro de conexão"; +"voice_broadcast_connection_error_message" = "Infelizmente, não podemos iniciar a gravação no momento. Tente novamente mais tarde."; +"voice_broadcast_playback_unable_to_decrypt" = "Não é possível decifrar esta transmissão de voz."; +"poll_history_past_segment_title" = "Pesquisas anteriores"; +"poll_history_load_more" = "Carregar mais enquetes"; +"poll_timeline_reply_ended_poll" = "Enquete encerrada"; +"wysiwyg_composer_format_action_ordered_list" = "Alternar lista numerada"; +"key_backup_recover_from_private_key_progress" = "%@%% Concluído"; +"pill_message_in" = "Mensagem em %@"; +"poll_history_loading_text" = "Exibindo enquetes"; +"poll_history_no_active_poll_period_text" = "Não há enquetes ativas nos últimos %@ dias. Carregue mais enquetes para ver as enquetes dos meses anteriores."; +"poll_history_no_past_poll_period_text" = "Não há enquetes anteriores nos últimos %@ dias. Carregue mais enquetes para ver as enquetes dos meses anteriores."; +"settings_manage_account_title" = "Conta"; +"settings_manage_account_action" = "Gerenciar conta"; +"settings_manage_account_description" = "Gerencie sua conta em %@"; +"key_verification_self_verify_security_upgrade_alert_title" = "Aplicativo atualizado"; +"key_verification_self_verify_security_upgrade_alert_message" = "A segurança das mensagens foi aprimorada com a atualização mais recente. Verifique novamente o seu dispositivo."; +"device_verification_self_verify_open_on_other_device_information" = "Você precisa verificar esta sessão para ler seu histórico de mensagens seguras.\n\nAbra o Element em um dos seus outros dispositivos e siga as instruções."; +"voice_broadcast_voip_cannot_start_title" = "Não é possível iniciar uma chamada"; +"room_waiting_other_participants_message" = "Depois que os usuários convidados se juntarem a %@, você poderá bater papo e a sala será criptografada de ponta a ponta"; From 5319490d64130e6e8eda7849c0017eb77bc41b30 Mon Sep 17 00:00:00 2001 From: Basheer Radman Date: Wed, 9 Apr 2025 16:19:02 +0000 Subject: [PATCH 08/61] Translated using Weblate (Arabic) Currently translated at 86.1% (2092 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ar/ --- Riot/Assets/ar.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index 731053d4f..ada0f9115 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2313,3 +2313,5 @@ "key_backup_recover_from_passphrase_recover_action" = "فتح التاريخ"; "device_verification_emoji_mushroom" = "فطر"; "device_verification_emoji_moon" = "القمر"; +"key_backup_recover_from_passphrase_passphrase_placeholder" = "أدخل العبارة"; +"deactivate_account_informations_part3" = "\n\nإلغاء تنشيط حسابك "; From 8a29828e74e5adf544aa0e02651d6983dea03bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=BAlio=20Sim=C3=B5es=20Martins=20Padilha?= Date: Wed, 9 Apr 2025 14:53:04 +0000 Subject: [PATCH 09/61] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (51 of 51 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/pt_BR/ --- Riot/Assets/pt_BR.lproj/Localizable.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/pt_BR.lproj/Localizable.strings b/Riot/Assets/pt_BR.lproj/Localizable.strings index 49f919d5d..62f30dc0d 100644 --- a/Riot/Assets/pt_BR.lproj/Localizable.strings +++ b/Riot/Assets/pt_BR.lproj/Localizable.strings @@ -118,3 +118,5 @@ /* New file message from a specific person, not referencing a room. */ "LOCATION_FROM_USER" = "%@ compartilhou a localização dela(e)"; +"VOICE_BROADCAST_FROM_USER" = "%@ iniciou uma transmissão de voz"; +"UNSUPPORTED_CALL" = "Chamada não suportada"; From 299f549c90c910a0e1e85a31636bb3ab5c927edc Mon Sep 17 00:00:00 2001 From: Basheer Radman Date: Fri, 11 Apr 2025 18:47:57 +0000 Subject: [PATCH 10/61] Translated using Weblate (Arabic) Currently translated at 91.5% (2223 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ar/ --- Riot/Assets/ar.lproj/Vector.strings | 132 ++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index ada0f9115..1bf1bc016 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2315,3 +2315,135 @@ "device_verification_emoji_moon" = "القمر"; "key_backup_recover_from_passphrase_passphrase_placeholder" = "أدخل العبارة"; "deactivate_account_informations_part3" = "\n\nإلغاء تنشيط حسابك "; +"user_verification_sessions_list_user_trust_level_unknown_title" = "غير معروف"; +"room_invite_to_space_option_title" = "ل ٪@"; +"spaces_coming_soon_detail" = "لم تُطبّق هذه الميزة هنا، ولكنها في طريقها. حاليًا، يمكنك القيام بذلك باستخدام %@ على جهاز الكمبيوتر."; +"space_feature_unavailable_subtitle" = "لم يتم إطلاق Spaces على نظام التشغيل iOS بعد، ولكن يمكنك استخدامها الآن على الويب وسطح المكتب"; +"space_feature_unavailable_information" = "المساحات وسيلة جديدة لتجميع الغرف والأشخاص.\n\nستتوفر قريبًا. حاليًا، إذا انضممت إلى واحدة عبر منصة أخرى، ستتمكن من الوصول إلى أي غرف تنضم إليها هنا."; +"space_tag" = "مساحة"; +"spaces_empty_space_detail" = "قد تكون بعض الغرف مخفية لأنها خاصة وتحتاج إلى دعوة."; +"spaces_no_member_found_detail" = "هل تبحث عن شخص ليس في %@؟ حاليًا، يمكنك دعوته عبر الويب أو سطح المكتب."; +"spaces_no_room_found_detail" = "قد تكون بعض النتائج مخفية لأنها خاصة وتحتاج إلى دعوة للانضمام إليها."; +"space_settings_update_failed_message" = "فشل تحديث إعدادات المساحة. هل تريد إعادة المحاولة؟"; +"space_private_join_rule" = "مساحة خاصة"; +"major_update_learn_more_action" = "معرفة المزيد"; +"emoji_picker_title" = "ردود الفعل"; +"emoji_picker_symbols_category" = "الرموز"; +"user_verification_start_information_part1" = "لمزيد من الأمان، قم بالتحقق "; +"user_verification_sessions_list_user_trust_level_trusted_title" = "موثوق به"; +"user_verification_session_details_information_trusted_current_user" = "تمت الوثوق بهذه الجلسة للمراسلة الآمنة لأنك قمت بالتحقق منها:"; +"user_verification_session_details_information_trusted_other_user_part1" = "هذه الجلسة موثوقة للمراسلة الآمنة لأنها "; +"user_verification_session_details_information_trusted_other_user_part2" = " تم التحقق من ذلك:"; +"home_context_menu_mute" = "كتم"; +"room_intro_cell_information_dm_sentence1_part1" = "هذه هي بداية رسالتك المباشرة مع "; +"room_intro_cell_information_dm_sentence2" = "أنتما الاثنان فقط في هذه المحادثة، ولا يمكن لأي شخص آخر الانضمام."; +"room_invite_not_enough_permission" = "ليس لديك إذن لدعوة الأشخاص إلى هذه الغرفة"; +"leave_space_message" = "هل أنت متأكد أنك تريد مغادرة %@؟ هل تريد أيضًا مغادرة جميع الغرف والمساحات في هذه المساحة؟"; +"spaces_suggested_room" = "مقترح"; +"spaces_empty_space_title" = "لا يوجد غرف في هذه المساحة (حتى الآن)"; +"spaces_add_rooms_coming_soon_title" = "سيتم إضافة الغرف قريبًا"; +"space_participants_action_remove" = "إزالة من هذه المساحة"; +"space_participants_action_ban" = "حظر من هذه المساحة"; +"space_home_show_all_rooms" = "عرض جميع الغرف"; +"space_private_join_rule_detail" = "للدعوة فقط، الأفضل لك أو لفريقك"; +"spaces_invite_people" = "دعوة الناس"; +"spaces_add_space" = "إضافة مساحة"; +"spaces_feature_not_available" = "هذه الميزة غير متوفرة هنا. حاليًا، يمكنك القيام بذلك باستخدام %@ على جهاز الكمبيوتر الخاص بك."; +"spaces_creation_footer" = "يمكنك تغيير هذا لاحقًا"; +"device_verification_emoji_headphones" = "سماعات الرأس"; +"user_verification_session_details_information_untrusted_other_user" = " تم تسجيل الدخول باستخدام جلسة جديدة:"; +"user_verification_session_details_additional_information_untrusted_other_user" = "حتى يثق هذا المستخدم بهذه الجلسة، تُعلَّم الرسائل المرسلة إليها ومنها بتحذيرات. يمكنك أيضًا التحقق منها يدويًا."; +"secrets_recovery_with_passphrase_passphrase_placeholder" = "أدخل عبارة الأمان"; +"create_room_section_footer_type_restricted" = "يمكن لأي شخص في اسم المساحة البحث والانضمام."; +"space_beta_announce_information" = "المساحات هي طريقة جديدة لتجميع الغرف والأشخاص. لم تتوفر بعد على نظام iOS، ولكن يمكنك استخدامها الآن على الويب وسطح المكتب."; +"leave_space_title" = "يترك ٪@"; +"leave_space_message_admin_warning" = "أنت مسؤول عن هذه المساحة، تأكد من أنك قمت بنقل حقوق المسؤول إلى عضو آخر قبل المغادرة."; +"spaces_creation_settings_message" = "أضف بعض التفاصيل لإبرازها. يمكنك تغييرها في أي وقت."; +"device_verification_emoji_anchor" = "مِرسَاة"; +"error_not_supported_on_mobile" = "لا يمكنك القيام بذلك من %@الجوال."; +"user_verification_sessions_list_user_trust_level_warning_title" = "تحذير"; +"user_verification_session_details_verify_action_current_user" = "التحقق بشكل تفاعلي"; +"create_room_placeholder_topic" = "ما هي هذه الغرفة؟"; +"room_intro_cell_information_room_without_topic_sentence2_part1" = "أضف موضوعًا"; +"space_invite_not_enough_permission" = "ليس لديك إذن لدعوة الأشخاص إلى هذه المساحة"; +"space_public_join_rule_detail" = "مفتوح للجميع، الأفضل للمجتمعات"; +"spaces_creation_visibility_message" = "للانضمام إلى مساحة موجودة، تحتاج إلى دعوة."; +"space_topic" = "وصف"; +"reaction_history_title" = "ردود الفعل"; +"home_context_menu_leave" = "يغادر"; +"spaces_add_space_title" = "إنشاء مساحة"; +"spaces_explore_rooms" = "استكشاف الغرف"; +"device_verification_emoji_bell" = "جرس"; +"device_verification_emoji_pin" = "دبوس"; +"pin_protection_settings_section_header_with_biometrics" = "دبوس & ٪@"; +"space_feature_unavailable_title" = "المساحات ليست هنا بعد"; +"spaces_explore_rooms_format" = "يستكشف ٪@"; +"key_verification_bootstrap_not_setup_message" = "يجب عليك أولاً تمهيد التوقيع المتبادل."; +"user_verification_session_details_verify_action_other_user" = "التحقق يدويًا"; +"secrets_recovery_with_passphrase_information_verify_device" = "استخدم عبارة الأمان الخاصة بك للتحقق من هذا الجهاز."; +"key_verification_alert_title" = "لديك جلسات غير موثقة"; +"device_verification_emoji_folder" = "مجلد"; +"file_upload_error_unsupported_file_type_message" = "نوع الملف غير مدعوم."; +"emoji_picker_places_category" = "السفر والأماكن"; +"error_invite_3pid_with_no_identity_server" = "أضف خادم هوية في إعداداتك لدعوتك عبر البريد الإلكتروني."; +"user_verification_start_waiting_partner" = "في انتظار %@…"; +"user_verification_session_details_trusted_title" = "موثوق به"; +"user_verification_session_details_untrusted_title" = "غير موثوق به"; +"secrets_recovery_reset_action_part_2" = "إعادة تعيين كل شيء"; +"secrets_recovery_with_passphrase_title" = "عبارة أمنية"; +"room_invite_to_space_option_detail" = "بإمكانهم استكشاف %@، ولكنهم لن يكونوا أعضاءً في %@."; +"spaces_home_space_title" = "الصفحة الرئيسية"; +"spaces_left_panel_title" = "المساحات"; +"leave_space_and_all_rooms_action" = "اترك جميع الغرف والمساحات"; +"spaces_no_result_found_title" = "لم يتم العثور على نتائج"; +"spaces_invites_coming_soon_title" = "الدعوات قادمة قريبا"; +"spaces_add_room" = "إضافة غرفة"; +"spaces_subspace_creation_visibility_message" = "سيتم إضافة المساحة التي تم إنشاؤها إلى %@."; +"space_public_join_rule" = "مساحة عامة"; +"secrets_recovery_with_passphrase_information_default" = "قم بالوصول إلى سجل رسائلك الآمنة وهوية التوقيع المتبادل الخاصة بك للتحقق من الجلسات الأخرى عن طريق إدخال عبارة الأمان الخاصة بك."; +"emoji_picker_foods_category" = "الطعام والشراب"; +"emoji_picker_activity_category" = "أنشطة"; +"user_verification_sessions_list_table_title" = "الجلسات"; +"create_room_type_restricted" = "أعضاء المساحة"; +"room_invite_to_room_option_detail" = "لن يكونوا جزءًا من %@."; +"spaces_add_subspace_title" = "إنشاء مساحة داخل %@"; +"space_settings_current_address_message" = "مساحتك متاحة للعرض على\n%@"; +"leave_space_only_action" = "لا تغادر أي غرف"; +"spaces_explore_rooms_room_number" = "%@ غرف"; +"user_verification_sessions_list_session_trusted" = "موثوق به"; +"create_room_show_in_directory_footer" = "سيساعد هذا الأشخاص في العثور على أعضاء جدد والانضمام إليهم."; +"room_intro_cell_information_room_without_topic_sentence2_part2" = " لإعلام الناس بما تحتويه هذه الغرفة."; +"spaces_create_space_title" = "إنشاء مساحة"; +"spaces_create_subspace_title" = "إنشاء مساحة فرعية"; +"file_upload_error_title" = "تحميل الملف"; +"emoji_picker_people_category" = "الوجوه الضاحكة والأشخاص"; +"emoji_picker_nature_category" = "الحيوانات والطبيعة"; +"emoji_picker_objects_category" = "أشياء"; +"emoji_picker_flags_category" = "الأعلام"; +"key_verification_bootstrap_not_setup_title" = "خطأ"; +"key_verification_tile_request_incoming_title" = "طلب التحقق"; +"key_verification_tile_request_outgoing_title" = "تم إرسال التحقق"; +"user_verification_start_verify_action" = "بدء التحقق"; +"user_verification_start_information_part2" = " عن طريق التحقق من رمز لمرة واحدة على كلا الجهازين."; +"user_verification_start_additional_information" = "لضمان الأمان، قم بذلك شخصيًا أو استخدم طريقة أخرى للتواصل."; +"user_verification_sessions_list_information" = "الرسائل التي يتبادلها هذا المستخدم في هذه الغرفة تكون مشفرة من البداية إلى النهاية ولا يمكن لأطراف ثالثة قراءتها."; +"user_verification_session_details_information_untrusted_current_user" = "قم بالتحقق من هذه الجلسة لوضع علامة عليها كموثوقة ومنحها حق الوصول إلى الرسائل المشفرة:"; +"user_verification_session_details_additional_information_untrusted_current_user" = "إذا لم تقم بتسجيل الدخول إلى هذه الجلسة، فقد يكون حسابك معرضًا للخطر."; +"user_verification_session_details_verify_action_current_user_manually" = "التحقق يدويًا عن طريق النص"; +"secrets_recovery_reset_action_part_1" = "هل نسيت أو فقدت كافة خيارات الاسترداد؟ "; +"secrets_recovery_with_passphrase_passphrase_title" = "دخول"; +"room_intro_cell_information_dm_sentence1_part3" = ". "; +"room_intro_cell_information_multiple_dm_sentence2" = "أنت وحدك من يشارك في هذه المحادثة، ما لم يقم أي منكم بدعوة شخص ما للانضمام."; +"room_invite_to_room_option_title" = "إلى هذه الغرفة فقط"; +"spaces_explore_rooms_one_room" = "غرفة واحدة"; +"space_settings_access_section" = "من يمكنه الوصول إلى هذه المساحة؟"; +"spaces_creation_hint" = "المساحات هي طريقة جديدة لتجميع الغرف والأشخاص."; +"spaces_creation_visibility_title" = "ما نوع المساحة التي تريد إنشاءها؟"; +"spaces_subspace_creation_visibility_title" = "ما نوع المساحة الفرعية التي تريد إنشاءها؟"; +"spaces_creation_address" = "عنوان"; +"space_beta_announce_title" = "المساحات قادمة قريبا"; +"user_verification_sessions_list_session_untrusted" = "غير موثوق به"; +"secrets_recovery_with_passphrase_recover_action" = "استخدم العبارة"; +"biometrics_cant_unlocked_alert_title" = "لا يمكن فتح التطبيق"; +"create_room_section_footer_type_public" = "يمكن فقط للأشخاص المدعوين العثور على المساحة والانضمام إليها، وليس فقط الأشخاص الموجودين في اسم المساحة."; +"space_beta_announce_subtitle" = "النسخة الجديدة من المجتمعات"; From e9603ee3da81b9a833c931f42fa5b6fc575e2727 Mon Sep 17 00:00:00 2001 From: Basheer Radman Date: Sun, 13 Apr 2025 18:03:06 +0000 Subject: [PATCH 11/61] Translated using Weblate (Arabic) Currently translated at 100.0% (51 of 51 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/ar/ --- Riot/Assets/ar.lproj/Localizable.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/ar.lproj/Localizable.strings b/Riot/Assets/ar.lproj/Localizable.strings index c5e8f6fef..978cd9f3b 100644 --- a/Riot/Assets/ar.lproj/Localizable.strings +++ b/Riot/Assets/ar.lproj/Localizable.strings @@ -167,3 +167,5 @@ /** General **/ "Notification" = "إشعار"; +"VOICE_BROADCAST_FROM_USER" = "%@ بدأ بثًا صوتيًا"; +"UNSUPPORTED_CALL" = "مكالمة غير مدعومة"; From 937e7bf77f40bc92acb18017ddd372cecf47a21c Mon Sep 17 00:00:00 2001 From: Basheer Radman Date: Sat, 12 Apr 2025 19:42:01 +0000 Subject: [PATCH 12/61] Translated using Weblate (Arabic) Currently translated at 99.9% (2425 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ar/ --- Riot/Assets/ar.lproj/Vector.strings | 197 ++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index 1bf1bc016..5cee2c098 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2447,3 +2447,200 @@ "biometrics_cant_unlocked_alert_title" = "لا يمكن فتح التطبيق"; "create_room_section_footer_type_public" = "يمكن فقط للأشخاص المدعوين العثور على المساحة والانضمام إليها، وليس فقط الأشخاص الموجودين في اسم المساحة."; "space_beta_announce_subtitle" = "النسخة الجديدة من المجتمعات"; +"user_session_verification_unknown" = "حالة التحقق غير معروفة"; +"user_session_overview_session_title" = "جلسة"; +"wysiwyg_composer_start_action_location" = "موقع"; +"user_session_details_last_activity" = "آخر نشاط"; +"spaces_creation_sharing_type_me_and_teammates_detail" = "مساحة خاصة لك ولزملائك في الفريق"; +"user_session_details_device_os" = "نظام التشغيل"; +"spaces_creation_private_space_title" = "مساحتك الخاصة"; +"wysiwyg_composer_start_action_polls" = "استطلاعات الرأي"; +"wysiwyg_composer_format_action_unordered_list" = "تبديل القائمة النقطية"; +"wysiwyg_composer_format_action_indent" = "زيادة المسافة البادئة"; +"wysiwyg_composer_format_action_un_indent" = "تقليل المسافة البادئة"; +"spaces_creation_address_default_message" = "ستكون مساحتك متاحة للعرض في\n%@"; +"spaces_creation_new_rooms_general" = "عام"; +"notice_display_name_changed_to" = "%@ غيّر اسم العرض الخاص به إلى %@"; +"network_offline_prompt" = "يبدو أنه غير متصل بالانترنت."; +"side_menu_action_invite_friends" = "دعوة الأصدقاء"; +"spaces_creation_post_process_creating_space" = "إنشاء مساحة"; +"user_session_unverified_additional_info" = "قم بالتحقق من جلستك الحالية للحصول على مراسلة آمنة معززة."; +"user_session_unverified_session_description" = "الجلسات غير المُتحققة هي الجلسات التي تم تسجيل الدخول إليها باستخدام بيانات اعتمادك ولكن لم يتم التحقق منها.\n\nيجب عليك التأكد بشكل خاص من التعرف على هذه الجلسات، فقد تُمثل استخدامًا غير مُصرّح به لحسابك."; +"user_other_session_menu_select_sessions" = "اختيار الجلسات"; +"poll_timeline_total_votes_not_voted" = "تم الإدلاء بـ %lu من الأصوات. صوّت لرؤية النتائج"; +"user_session_permanently_unverified_session_description" = "هذه الجلسة لا تدعم التشفير، لذا لا يمكن التحقق منها.\n\nلن تتمكن من المشاركة في الغرف التي يُفعّل فيها التشفير عند استخدام هذه الجلسة.\n\nلأعلى مستوى من الأمان والخصوصية، يُنصح باستخدام عملاء Matrix الذين يدعمون التشفير."; +"user_session_verified_session_description" = "الجلسات المُتحققة موجودة في أي مكان تستخدم فيه Element بعد إدخال كلمة المرور أو تأكيد هويتك بجلسة مُتحققة أخرى.\n\nهذا يعني أن لديك جميع المفاتيح اللازمة لفتح رسائلك المُشفرة وتأكيد ثقتك بهذه الجلسة للمستخدمين الآخرين."; +"device_name_desktop" = "%@ سطح المكتب"; +"user_sessions_overview_current_session_section_title" = "الجلسة الحالية"; +"user_sessions_view_all_action" = "عرض الكل (%d)"; +"user_session_verify_action" = "التحقق من الجلسة"; +"user_session_view_details" = "عرض التفاصيل"; +"user_session_details_title" = "تفاصيل الجلسة"; +"user_session_inactive_session_title" = "الجلسات غير النشطة"; +"device_type_name_web" = "الويب"; +"wysiwyg_composer_start_action_camera" = "كاميرا"; +"wysiwyg_composer_start_action_voice_broadcast" = "البث الصوتي"; +"wysiwyg_composer_format_action_code_block" = "مكون كود التبديل"; +"user_other_session_no_verified_sessions" = "لم يتم العثور على جلسات تم التحقق منها."; +"user_inactive_session_item" = "غير نشط لمدة 90 يومًا أو أكثر"; +"wysiwyg_composer_format_action_quote" = "اقتباس التبديل"; +"wysiwyg_composer_link_action_edit_title" = "تعديل الرابط"; +"key_backup_setup_passphrase_set_passphrase_action" = "تعيين عبارة"; +"user_session_unverified_session_title" = "جلسة غير مُتحققة"; +"device_name_web" = "%@ ويب"; +"user_session_verification_unknown_short" = "غير معروف"; +"message_reply_to_sender_sent_their_live_location" = "الموقع المباشر"; +"spaces_creation_add_rooms_message" = "بما أن هذه المساحة مخصصة لك فقط، فلن يتم إعلام أحد. يمكنك إضافة المزيد لاحقًا."; +"spaces_creation_post_process_creating_space_task" = "إنشاء %@"; +"spaces_creation_post_process_uploading_avatar" = "تحميل الصورة الرمزية"; +"spaces_creation_in_spacename_plus_many" = "في مساحات %@ + %@"; +"voice_message_stop_locked_mode_recording" = "اضغط على التسجيل الخاص بك لإيقافه أو الاستماع إليه"; +"poll_edit_form_option_number" = "الخيار %lu"; +"poll_timeline_total_votes" = "%lu الأصوات المدلى بها"; +"location_sharing_live_timer_incoming" = "مباشر حتى %@"; +"user_sessions_overview_link_device" = "ربط جهاز"; +"user_other_session_permanently_unverified_additional_info" = "هذه الجلسة لا تدعم التشفير وبالتالي لا يمكن التحقق منها."; +"user_other_session_verified_additional_info" = "هذه الجلسة جاهزة للمراسلة الآمنة."; +"user_session_push_notifications_message" = "عند تشغيلها، ستتلقى هذه الجلسة إشعارات فورية."; +"user_session_details_device_browser" = "المتصفح"; +"user_session_details_application_url" = "عنوان URL"; +"wysiwyg_composer_action_maximise_action" = "توسيع الملحن"; +"wysiwyg_composer_format_action_bold" = "تطبيق تنسيق غامق"; +"wysiwyg_composer_format_action_italic" = "تطبيق التنسيق المائل"; +"wysiwyg_composer_format_action_link" = "تطبيق تنسيق الرابط"; +"wysiwyg_composer_link_action_link" = "وصلة"; +"device_type_name_unknown" = "غير معروف"; +"user_other_session_verified_sessions_header_subtitle" = "للحصول على أفضل مستوى من الأمان، قم بتسجيل الخروج من أي جلسة لا تعرفها أو لا تستخدمها بعد الآن."; +"device_name_mobile" = "٪@ جوال"; +"device_type_name_desktop" = "سطح المكتب"; +"wysiwyg_composer_link_action_create_title" = "إنشاء رابط"; +"deselect_all" = "إلغاء تحديد الكل"; +"ignore_user" = "تجاهل المستخدم"; +"device_verification_emoji_train" = "يدرب"; +"spaces_creation_address_invalid_characters" = "%@\nيحتوي على أحرف غير صالحة"; +"spaces_creation_new_rooms_message" = "سننشئ غرفة لكل واحد منهم."; +"spaces_creation_new_rooms_random" = "عشوائي"; +"spaces_add_room_missing_permission_message" = "ليس لديك الأذونات اللازمة لإضافة غرف إلى هذه المساحة."; +"side_menu_reveal_action_accessibility_label" = "اللوحة اليسرى"; +"voice_message_release_to_send" = "اضغط باستمرار للتسجيل، ثم حرر للإرسال"; +"leave_space_and_more_rooms" = "اترك مساحة و %@غرف"; +"user_session_learn_more" = "معرفة المزيد"; +"wysiwyg_composer_action_minimise_action" = "ملحن الانكماش"; +"user_session_rename_session_description" = "يستطيع المستخدمون الآخرون في الرسائل المباشرة والغرف التي تنضم إليها عرض قائمة كاملة بجلساتك.\n\nهذا يمنحهم الثقة بأنهم يتحدثون إليك حقًا، ويعني أيضًا أنهم يستطيعون رؤية اسم الجلسة التي تُدخلها هنا."; +"user_other_session_filter_menu_verified" = "تم التحقق"; +"user_other_session_no_inactive_sessions" = "لم يتم العثور على جلسات غير نشطة."; +"device_verification_emoji_hat" = "قبعة"; +"room_intro_cell_information_room_with_topic_sentence2" = "موضوع: ٪@"; +"space_beta_announce_badge" = "بيتا (تجريبي)"; +"spaces_creation_new_rooms_title" = "ما هي بعض المناقشات التي ستجريها؟"; +"spaces_creation_invite_by_username_title" = "ادعُ فريقك"; +"spaces_creation_post_process_inviting_users" = "دعوة %@ المستخدمين"; +"leave_space_action" = "غادر المساحة"; +"leave_space_selection_all_rooms" = "حدد جميع الغرف"; +"space_avatar_view_accessibility_hint" = "تغيير الصورة الرمزية للمساحة"; +"leave_space_selection_title" = "تحديد الغرف"; +"side_menu_action_settings" = "إعدادات"; +"side_menu_coach_message" = "مرر لليمين أو انقر لرؤية جميع الغرف"; +"voice_message_broadcast_in_progress_title" = "لا يمكن بدء الرسالة الصوتية"; +"voice_message_broadcast_in_progress_message" = "لا يمكنك بدء رسالة صوتية لأنك تُسجِّل بثًا مباشرًا. يُرجى إنهاء البث المباشر لبدء تسجيل رسالة صوتية"; +"voice_broadcast_unauthorized_title" = "لا يمكن بدء بث صوتي جديد"; +"user_session_inactive_session_description" = "الجلسات غير النشطة هي جلسات لم تستخدمها منذ فترة، ولكنها تستمر في تلقي مفاتيح التشفير.\n\nيؤدي حذف الجلسات غير النشطة إلى تحسين الأمان والأداء، ويسهّل عليك تحديد ما إذا كانت الجلسة الجديدة مشبوهة."; +"user_other_session_unverified_sessions_header_subtitle" = "قم بالتحقق من جلساتك للحصول على رسائل آمنة معززة أو قم بتسجيل الخروج من الجلسات التي لا تعرفها أو لا تستخدمها بعد الآن."; +"user_session_name" = "%@: %@"; +"user_other_session_filter_menu_unverified" = "غير مُتحقق"; +"user_session_details_session_section_footer" = "انسخ أي بيانات عن طريق النقر عليها مع الاستمرار في الضغط عليها."; +"user_session_details_device_ip_location" = "موقع IP"; +"user_inactive_session_item_with_date" = "غير نشط لمدة 90 يومًا أو أكثر (%@)"; +"user_session_overview_session_details_button_title" = "تفاصيل الجلسة"; +"wysiwyg_composer_start_action_media_picker" = "مكتبة الصور"; +"user_session_unverified_short" = "غير مُتحقق"; +"wysiwyg_composer_format_action_underline" = "تطبيق تنسيق التسطير"; +"spaces_creation_empty_room_name_error" = "الاسم مطلوب"; +"room_event_encryption_info_key_authenticity_not_guaranteed" = "لا يمكن ضمان صحة هذه الرسالة المشفرة على هذا الجهاز."; +"spaces_creation_sharing_type_me_and_teammates_title" = "أنا وزملائي في الفريق"; +"spaces_creation_invite_by_username" = "دعوة عن طريق اسم المستخدم"; +"spaces_creation_in_spacename" = "في ٪@"; +"spaces_creation_in_spacename_plus_one" = "في %@ + 1 مساحة"; +"room_event_action_reaction_more" = "٪@ أكثر"; +"side_menu_action_help" = "مساعدة"; +"user_session_push_notifications" = "إشعارات الدفع"; +"user_other_session_filter_menu_all" = "جميع الجلسات"; +"user_other_session_filter_menu_inactive" = "غير نشط"; +"user_session_details_application_section_header" = "تطبيق"; +"user_session_details_session_id" = "معرف الجلسة"; +"wysiwyg_composer_start_action_attachments" = "المرفقات"; +"wysiwyg_composer_format_action_ordered_list" = "تبديل القائمة المرقمة"; +"device_verification_emoji_trumpet" = "بوق"; +"key_verification_tile_request_incoming_approval_decline" = "رفض"; +"spaces_creation_address_already_exists" = "%@\nموجود بالفعل"; +"spaces_creation_email_invites_email_title" = "بريد إلكتروني"; +"spaces_creation_sharing_type_just_me_title" = "أنا فقط"; +"spaces_creation_sharing_type_just_me_detail" = "مساحة خاصة لتنظيم غرفك"; +"spaces_creation_in_many_spaces" = "في %@ مساحات"; +"key_backup_recover_from_recovery_key_recovery_key_title" = "دخول"; +"device_verification_emoji_thumbs up" = "ممتاز"; +"spaces_creation_cancel_title" = "توقف عن إنشاء مساحة؟"; +"spaces_creation_cancel_message" = "سيتم فقدان تقدمك."; +"spaces_creation_new_rooms_support" = "دعم"; +"spaces_creation_email_invites_title" = "ادعُ فريقك"; +"leave_space_selection_no_rooms" = "عدم تحديد الغرف"; +"space_avatar_view_accessibility_label" = "الصورة الرمزية"; +"user_session_verified" = "جلسة تم التحقق منها"; +"wysiwyg_composer_start_action_text_formatting" = "تنسيق النص"; +"wysiwyg_composer_format_action_inline_code" = "تطبيق تنسيق الكود المضمن"; +"wysiwyg_composer_link_action_text" = "نص"; +"service_terms_modal_policy_checkbox_accessibility_hint" = "حدد لقبول %@"; +"user_avatar_view_accessibility_label" = "الصورة الرمزية"; +"spaces_creation_public_space_title" = "مساحتك العامة"; +"spaces_creation_email_invites_message" = "ويمكنك دعوتهم لاحقًا أيضًا."; +"poll_timeline_reply_ended_poll" = "انتهى الاستطلاع"; +"user_session_verified_additional_info" = "جلستك الحالية جاهزة للمراسلة الآمنة."; +"user_session_verification_unknown_additional_info" = "قم بالتحقق من جلستك الحالية للكشف عن حالة التحقق الخاصة بهذه الجلسة."; +"user_session_rename_session_title" = "إعادة تسمية الجلسات"; +"user_session_item_details" = "%1$@ · %2$@"; +"user_session_details_session_name" = "اسم الجلسة"; +"user_session_details_application_name" = "اسم"; +"user_other_session_selected_count" = "%@ تم اختياره"; +"wysiwyg_composer_format_action_strikethrough" = "تطبيق تنسيق الشطب"; +"spaces_creation_invite_by_username_message" = "ويمكنك دعوتهم لاحقًا أيضًا."; +"voice_message_remaining_recording_time" = "%@s متبقية"; +"spaces_creation_sharing_type_title" = "مع من تعمل؟"; +"side_menu_action_feedback" = "تعليق"; +"location_sharing_loading_map_error_title" = "تعذر تحميل الخريطة. يُرجى المحاولة لاحقًا."; +"user_session_unverified" = "جلسة غير مُتحققة"; +"user_other_session_security_recommendation_title" = "جلسات أخرى"; +"user_session_details_application_version" = "إصدار"; +"key_backup_recover_from_passphrase_passphrase_title" = "دخول"; +"device_verification_emoji_santa" = "سانتا"; +"major_update_title" = "الشغب الآن %@"; +"home_context_menu_unmute" = "إزالة الكتم"; +"spaces_creation_new_rooms_room_name_title" = "اسم الغرفة"; +"spaces_creation_sharing_type_message" = "تأكد من أن الأشخاص المناسبين لديهم حق الوصول %@. يمكنك تغيير هذا لاحقًا."; +"spaces_creation_add_rooms_title" = "ماذا تريد أن تضيف؟"; +"spaces_creation_post_process_creating_room" = "إنشاء %@"; +"spaces_creation_post_process_adding_rooms" = "إضافة %@ غرف"; +"spaces_creation_in_one_space" = "في مساحة واحدة"; +"side_menu_app_version" = "إصدار ٪@"; +"voice_message_lock_screen_placeholder" = "رسالة صوتية"; +"user_session_verified_short" = "تم التحقق"; +"user_other_session_unverified_additional_info" = "قم بالتحقق من هذه الجلسة أو تسجيل الخروج منها للحصول على أفضل مستوى من الأمان والموثوقية."; +"user_other_session_current_session_details" = "جلستك الحالية"; +"user_other_session_filter" = "عامل التصفية"; +"user_other_session_no_unverified_sessions" = "لم يتم العثور على جلسات غير موثقة."; +"user_other_session_clear_filter" = "مسح عامل التصفية"; +"user_other_session_menu_sign_out_sessions" = "تسجيل الخروج من جلسات %@"; +"user_session_item_details_last_activity" = "آخر نشاط %@"; +"user_session_details_device_section_header" = "جهاز"; +"user_session_details_device_ip_address" = "عنوان IP"; +"spaces_coming_soon_title" = "قادم قريباً"; +"leave_space_and_one_room" = "اترك مساحة وغرفة واحدة"; +"room_widget_permission_theme_permission" = "موضوعك"; +"user_avatar_view_accessibility_hint" = "تغيير صورة المستخدم الرمزية"; +"user_session_details_session_section_header" = "جلسة"; +"user_session_overview_current_session_title" = "الجلسة الحالية"; +"wysiwyg_composer_start_action_stickers" = "ملصقات"; +"user_session_got_it" = "فهمتها"; +"user_session_verified_session_title" = "الجلسات التي تم التحقق منها"; +"user_session_details_device_model" = "نموذج"; +"device_name_unknown" = "عميل غير معروف"; +"device_type_name_mobile" = "جوال"; From 489a15dbdf6bf394fd6fb18b174fe8d837f3d511 Mon Sep 17 00:00:00 2001 From: EntilS Date: Thu, 24 Apr 2025 17:15:26 +0000 Subject: [PATCH 13/61] Translated using Weblate (Italian) Currently translated at 100.0% (51 of 51 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/it/ --- Riot/Assets/it.lproj/Localizable.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/it.lproj/Localizable.strings b/Riot/Assets/it.lproj/Localizable.strings index 3232ff2a4..94ba80bd4 100644 --- a/Riot/Assets/it.lproj/Localizable.strings +++ b/Riot/Assets/it.lproj/Localizable.strings @@ -121,3 +121,4 @@ /* New voice broadcast from a specific person, not referencing a room. */ "VOICE_BROADCAST_FROM_USER" = "%@ ha iniziato una trasmissione vocale"; +"UNSUPPORTED_CALL" = "Chiamata non supportata"; From d1826dfe5dd66833da586f71b76a3472b1ee604f Mon Sep 17 00:00:00 2001 From: EntilS Date: Thu, 24 Apr 2025 17:14:58 +0000 Subject: [PATCH 14/61] Translated using Weblate (Italian) Currently translated at 100.0% (2427 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ --- Riot/Assets/it.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/it.lproj/Vector.strings b/Riot/Assets/it.lproj/Vector.strings index 55551cc09..24c1f159c 100644 --- a/Riot/Assets/it.lproj/Vector.strings +++ b/Riot/Assets/it.lproj/Vector.strings @@ -2754,3 +2754,10 @@ "wysiwyg_composer_action_maximise_action" = "Espandi il compositore"; "room_action_report" = "Segnala stanza"; "room_action_report_prompt_reason" = "Motivo della segnalazione della stanza"; +"call_unsupported_matrix_rtc_call" = "Chiamata non supportata. Per unirsi a questa chiamata è necessaria la nuova app Element X."; +"sunset_delegated_oidc_registration_not_supported_title" = "Non puoi più creare un account con %1$@ usando quest'app"; +"sunset_delegated_oidc_registration_not_supported_message" = "Scarica %1$@ per utilizzare %2$@ per il tuo account o scegli un homeserver differente."; +"sunset_download_banner_title" = "Scarica %1$@"; +"sunset_download_banner_message" = "Più veloce, più sicura, e piena di potenti strumenti di collaborazione."; +"sunset_download_banner_learn_more" = "Per saperne di più"; +"sunset_delegated_oidc_registration_not_supported_generic_error" = "Non puoi più creare un account con l'homeserver indicato usando quest'app"; From 5167ed8fb6a0cbb64e8e8da5be6cc2e452c1f22b Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 11:39:51 +0200 Subject: [PATCH 15/61] update to support 16.3 --- Gemfile.lock | 31 ++++++++++++++------------- Podfile | 2 +- Podfile.lock | 12 +++++------ RiotTests/PushRulesUpdaterTests.swift | 2 +- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 82538d2eb..c858250c3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -32,17 +32,18 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.2) - aws-partitions (1.1063.0) - aws-sdk-core (3.220.1) + aws-partitions (1.1107.0) + aws-sdk-core (3.224.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) base64 jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.99.0) + logger + aws-sdk-kms (1.101.0) aws-sdk-core (~> 3, >= 3.216.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.182.0) + aws-sdk-s3 (1.186.1) aws-sdk-core (~> 3, >= 3.216.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -96,13 +97,13 @@ GEM commander (4.6.0) highline (~> 2.0.0) concurrent-ruby (1.3.5) - connection_pool (2.5.0) + connection_pool (2.5.3) declarative (0.0.20) digest-crc (0.7.0) rake (>= 12.0.0, < 14.0.0) domain_name (0.6.20240107) dotenv (2.8.1) - drb (2.2.1) + drb (2.2.3) emoji_regex (3.2.3) escape (0.0.4) ethon (0.16.0) @@ -137,7 +138,7 @@ GEM faraday_middleware (1.2.1) faraday (~> 1.0) fastimage (2.4.0) - fastlane (2.226.0) + fastlane (2.227.2) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -177,17 +178,17 @@ GEM tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.4.0) + xcpretty (~> 0.4.1) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) fastlane-plugin-brew (0.1.1) - fastlane-plugin-sentry (1.28.0) + fastlane-plugin-sentry (1.29.0) os (~> 1.1, >= 1.1.4) fastlane-plugin-versioning (0.7.1) fastlane-plugin-xcodegen (1.1.0) fastlane-plugin-brew (~> 0.1.1) fastlane-sirp (1.0.0) sysrandom (~> 1.0) - ffi (1.17.1) + ffi (1.17.2) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -235,14 +236,14 @@ GEM i18n (1.14.7) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.10.1) + json (2.12.2) jwt (2.10.1) base64 - logger (1.6.6) + logger (1.7.0) mini_magick (4.13.2) mini_mime (1.1.5) - mini_portile2 (2.8.8) - minitest (5.25.4) + mini_portile2 (2.8.9) + minitest (5.25.5) molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.4.1) @@ -313,7 +314,7 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) - xcpretty (0.4.0) + xcpretty (0.4.1) rouge (~> 3.28.0) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) diff --git a/Podfile b/Podfile index 5a9048ac9..df74ba48c 100644 --- a/Podfile +++ b/Podfile @@ -34,7 +34,7 @@ abstract_target 'RiotPods' do pod 'KeychainAccess', '~> 4.2.2' pod 'WeakDictionary', '~> 2.0' - pod 'Sentry', '~> 8.35.0' + pod 'Sentry', '~> 8.46.0' pod 'zxcvbn-ios' diff --git a/Podfile.lock b/Podfile.lock index 0d2dfd08b..5fa3debb8 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -60,9 +60,9 @@ PODS: - Reusable/View (= 4.1.2) - Reusable/Storyboard (4.1.2) - Reusable/View (4.1.2) - - Sentry (8.35.1): - - Sentry/Core (= 8.35.1) - - Sentry/Core (8.35.1) + - Sentry (8.46.0): + - Sentry/Core (= 8.46.0) + - Sentry/Core (8.46.0) - SideMenu (6.5.0) - SwiftBase32 (0.9.0) - SwiftFormat/CLI (0.54.5) @@ -97,7 +97,7 @@ DEPENDENCIES: - MatrixSDK/JingleCallStack (from `matrix-ios-sdk/MatrixSDK.podspec`) - ReadMoreTextView (~> 3.0.1) - Reusable (~> 4.1) - - Sentry (~> 8.35.0) + - Sentry (~> 8.46.0) - SideMenu (~> 6.5) - SwiftBase32 (~> 0.9.0) - SwiftFormat/CLI @@ -181,7 +181,7 @@ SPEC CHECKSUMS: ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 - Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1 + Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854 SideMenu: f583187d21c5b1dd04c72002be544b555a2627a2 SwiftBase32: 9399c25a80666dc66b51e10076bf591e3bbb8f17 SwiftFormat: 543a7b1ab4a6ce2d88bd5616a17903446ca3dc5c @@ -195,6 +195,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: 24c4218f1b6fef3b8605b4af17ed3b914f373774 +PODFILE CHECKSUM: 60f4fe3695f2304b9bba734acf38d59c79678ac1 COCOAPODS: 1.16.2 diff --git a/RiotTests/PushRulesUpdaterTests.swift b/RiotTests/PushRulesUpdaterTests.swift index 7602b5982..24abcec09 100644 --- a/RiotTests/PushRulesUpdaterTests.swift +++ b/RiotTests/PushRulesUpdaterTests.swift @@ -54,7 +54,7 @@ final class PushRulesUpdaterTests: XCTestCase { } } - func testAffectedOneToOneRulesAreUpdated() async throws { + func disabled_testAffectedOneToOneRulesAreUpdated() async throws { let targetActions: NotificationActions = .init(notify: true, sound: "abc") try mockRule(ruleId: .oneToOneRoom, enabled: true, actions: targetActions) let affectedRules: [NotificationPushRuleId] = [.oneToOneRoom, .oneToOnePollStart, .msc3930oneToOnePollStart, .oneToOnePollEnd, .msc3930oneToOnePollEnd] From de546c54aade3fe88bd8e71140c999d5baa5002a Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 11:44:45 +0200 Subject: [PATCH 16/61] test again --- RiotTests/PushRulesUpdaterTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RiotTests/PushRulesUpdaterTests.swift b/RiotTests/PushRulesUpdaterTests.swift index 24abcec09..7602b5982 100644 --- a/RiotTests/PushRulesUpdaterTests.swift +++ b/RiotTests/PushRulesUpdaterTests.swift @@ -54,7 +54,7 @@ final class PushRulesUpdaterTests: XCTestCase { } } - func disabled_testAffectedOneToOneRulesAreUpdated() async throws { + func testAffectedOneToOneRulesAreUpdated() async throws { let targetActions: NotificationActions = .init(notify: true, sound: "abc") try mockRule(ruleId: .oneToOneRoom, enabled: true, actions: targetActions) let affectedRules: [NotificationPushRuleId] = [.oneToOneRoom, .oneToOnePollStart, .msc3930oneToOnePollStart, .oneToOnePollEnd, .msc3930oneToOnePollEnd] From cc3ce5692624f922fa3326bd90081edfde6e22cc Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 12:02:44 +0200 Subject: [PATCH 17/61] version++ --- CHANGES.md | 7 +++++++ changelog.d/pr-7927.change | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) delete mode 100644 changelog.d/pr-7927.change diff --git a/CHANGES.md b/CHANGES.md index 6967d43cc..eebfcebc7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,10 @@ +## Changes in 1.11.28 (2025-05-28) + +🙌 Improvements + +- Support for experimental MSC4286 during event rendering. ([#7927](https://github.com/element-hq/element-ios/pull/7927)) + + ## Changes in 1.11.27 (2025-03-28) No significant changes. diff --git a/changelog.d/pr-7927.change b/changelog.d/pr-7927.change deleted file mode 100644 index 05f943e8e..000000000 --- a/changelog.d/pr-7927.change +++ /dev/null @@ -1 +0,0 @@ -Support for experimental MSC4286 during event rendering. \ No newline at end of file From ab6d00e47ee4829576458acfc83928bc0aab14b6 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 13:06:14 +0200 Subject: [PATCH 18/61] removed strings that don't work --- Riot/Assets/ar.lproj/Vector.strings | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index 5cee2c098..7faac7573 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2283,7 +2283,6 @@ "device_verification_emoji_book" = "كتاب"; "key_backup_setup_success_from_recovery_key_make_copy_action" = "اصنع نسخة"; "key_backup_setup_passphrase_setup_recovery_key_action" = "(متقدم) الإعداد باستخدام مفتاح الأمان"; -"key_backup_recover_from_private_key_progress" = "٪@٪٪ مكتمل"; "device_verification_emoji_fish" = "سمكة"; "device_verification_emoji_corn" = "حبوب ذرة"; "device_verification_emoji_robot" = "روبوت"; @@ -2375,7 +2374,6 @@ "spaces_explore_rooms" = "استكشاف الغرف"; "device_verification_emoji_bell" = "جرس"; "device_verification_emoji_pin" = "دبوس"; -"pin_protection_settings_section_header_with_biometrics" = "دبوس & ٪@"; "space_feature_unavailable_title" = "المساحات ليست هنا بعد"; "spaces_explore_rooms_format" = "يستكشف ٪@"; "key_verification_bootstrap_not_setup_message" = "يجب عليك أولاً تمهيد التوقيع المتبادل."; @@ -2530,7 +2528,6 @@ "user_other_session_filter_menu_verified" = "تم التحقق"; "user_other_session_no_inactive_sessions" = "لم يتم العثور على جلسات غير نشطة."; "device_verification_emoji_hat" = "قبعة"; -"room_intro_cell_information_room_with_topic_sentence2" = "موضوع: ٪@"; "space_beta_announce_badge" = "بيتا (تجريبي)"; "spaces_creation_new_rooms_title" = "ما هي بعض المناقشات التي ستجريها؟"; "spaces_creation_invite_by_username_title" = "ادعُ فريقك"; @@ -2606,7 +2603,6 @@ "voice_message_remaining_recording_time" = "%@s متبقية"; "spaces_creation_sharing_type_title" = "مع من تعمل؟"; "side_menu_action_feedback" = "تعليق"; -"location_sharing_loading_map_error_title" = "تعذر تحميل الخريطة. يُرجى المحاولة لاحقًا."; "user_session_unverified" = "جلسة غير مُتحققة"; "user_other_session_security_recommendation_title" = "جلسات أخرى"; "user_session_details_application_version" = "إصدار"; From e3fc7f1baad4e75a17fa40ff1e083ba1c87e1ef1 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 13:30:23 +0200 Subject: [PATCH 19/61] removed broken localization strings --- Riot/Assets/ar.lproj/Vector.strings | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index 7faac7573..076873b5b 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2355,7 +2355,6 @@ "secrets_recovery_with_passphrase_passphrase_placeholder" = "أدخل عبارة الأمان"; "create_room_section_footer_type_restricted" = "يمكن لأي شخص في اسم المساحة البحث والانضمام."; "space_beta_announce_information" = "المساحات هي طريقة جديدة لتجميع الغرف والأشخاص. لم تتوفر بعد على نظام iOS، ولكن يمكنك استخدامها الآن على الويب وسطح المكتب."; -"leave_space_title" = "يترك ٪@"; "leave_space_message_admin_warning" = "أنت مسؤول عن هذه المساحة، تأكد من أنك قمت بنقل حقوق المسؤول إلى عضو آخر قبل المغادرة."; "spaces_creation_settings_message" = "أضف بعض التفاصيل لإبرازها. يمكنك تغييرها في أي وقت."; "device_verification_emoji_anchor" = "مِرسَاة"; @@ -2375,7 +2374,6 @@ "device_verification_emoji_bell" = "جرس"; "device_verification_emoji_pin" = "دبوس"; "space_feature_unavailable_title" = "المساحات ليست هنا بعد"; -"spaces_explore_rooms_format" = "يستكشف ٪@"; "key_verification_bootstrap_not_setup_message" = "يجب عليك أولاً تمهيد التوقيع المتبادل."; "user_verification_session_details_verify_action_other_user" = "التحقق يدويًا"; "secrets_recovery_with_passphrase_information_verify_device" = "استخدم عبارة الأمان الخاصة بك للتحقق من هذا الجهاز."; @@ -2509,7 +2507,6 @@ "wysiwyg_composer_link_action_link" = "وصلة"; "device_type_name_unknown" = "غير معروف"; "user_other_session_verified_sessions_header_subtitle" = "للحصول على أفضل مستوى من الأمان، قم بتسجيل الخروج من أي جلسة لا تعرفها أو لا تستخدمها بعد الآن."; -"device_name_mobile" = "٪@ جوال"; "device_type_name_desktop" = "سطح المكتب"; "wysiwyg_composer_link_action_create_title" = "إنشاء رابط"; "deselect_all" = "إلغاء تحديد الكل"; @@ -2556,9 +2553,7 @@ "room_event_encryption_info_key_authenticity_not_guaranteed" = "لا يمكن ضمان صحة هذه الرسالة المشفرة على هذا الجهاز."; "spaces_creation_sharing_type_me_and_teammates_title" = "أنا وزملائي في الفريق"; "spaces_creation_invite_by_username" = "دعوة عن طريق اسم المستخدم"; -"spaces_creation_in_spacename" = "في ٪@"; "spaces_creation_in_spacename_plus_one" = "في %@ + 1 مساحة"; -"room_event_action_reaction_more" = "٪@ أكثر"; "side_menu_action_help" = "مساعدة"; "user_session_push_notifications" = "إشعارات الدفع"; "user_other_session_filter_menu_all" = "جميع الجلسات"; @@ -2616,7 +2611,6 @@ "spaces_creation_post_process_creating_room" = "إنشاء %@"; "spaces_creation_post_process_adding_rooms" = "إضافة %@ غرف"; "spaces_creation_in_one_space" = "في مساحة واحدة"; -"side_menu_app_version" = "إصدار ٪@"; "voice_message_lock_screen_placeholder" = "رسالة صوتية"; "user_session_verified_short" = "تم التحقق"; "user_other_session_unverified_additional_info" = "قم بالتحقق من هذه الجلسة أو تسجيل الخروج منها للحصول على أفضل مستوى من الأمان والموثوقية."; From 58920f3c48fe015e5eb1c8a92b34963cb6414573 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 13:45:44 +0200 Subject: [PATCH 20/61] another malformatted string removed --- Riot/Assets/ar.lproj/Vector.strings | 1 - 1 file changed, 1 deletion(-) diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index 076873b5b..838be3117 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -2315,7 +2315,6 @@ "key_backup_recover_from_passphrase_passphrase_placeholder" = "أدخل العبارة"; "deactivate_account_informations_part3" = "\n\nإلغاء تنشيط حسابك "; "user_verification_sessions_list_user_trust_level_unknown_title" = "غير معروف"; -"room_invite_to_space_option_title" = "ل ٪@"; "spaces_coming_soon_detail" = "لم تُطبّق هذه الميزة هنا، ولكنها في طريقها. حاليًا، يمكنك القيام بذلك باستخدام %@ على جهاز الكمبيوتر."; "space_feature_unavailable_subtitle" = "لم يتم إطلاق Spaces على نظام التشغيل iOS بعد، ولكن يمكنك استخدامها الآن على الويب وسطح المكتب"; "space_feature_unavailable_information" = "المساحات وسيلة جديدة لتجميع الغرف والأشخاص.\n\nستتوفر قريبًا. حاليًا، إذا انضممت إلى واحدة عبر منصة أخرى، ستتمكن من الوصول إلى أي غرف تنضم إليها هنا."; From 24be42decd01578a17e148e5081f368d014f8185 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 15:00:22 +0200 Subject: [PATCH 21/61] finish version++ From d2712aa8af18c6177571ab39e84fe19cba98d473 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 28 May 2025 15:00:28 +0200 Subject: [PATCH 22/61] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index b4b2a9e9d..9904a98f5 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.28 -CURRENT_PROJECT_VERSION = 1.11.28 +MARKETING_VERSION = 1.11.29 +CURRENT_PROJECT_VERSION = 1.11.29 From 982b50c3f0f90dfaeec20db82b10be654c917382 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 29 May 2025 14:52:33 +0200 Subject: [PATCH 23/61] updated matrix crypto sdk --- Podfile.lock | 10 +++++----- matrix-ios-sdk | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 5fa3debb8..e7dd60ab3 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -44,13 +44,13 @@ PODS: - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - - MatrixSDKCrypto (= 0.4.3) + - MatrixSDKCrypto (= 0.11.0) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - MatrixSDK/JingleCallStack (0.27.17): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - - MatrixSDKCrypto (0.4.3) + - MatrixSDKCrypto (0.11.0) - ReadMoreTextView (3.0.1) - Realm (10.27.0): - Realm/Headers (= 10.27.0) @@ -112,6 +112,7 @@ DEPENDENCIES: SPEC REPOS: https://github.com/CocoaPods/Specs.git: + - MatrixSDKCrypto - Sentry trunk: - AFNetworking @@ -134,7 +135,6 @@ SPEC REPOS: - libPhoneNumber-iOS - LoggerAPI - Logging - - MatrixSDKCrypto - ReadMoreTextView - Realm - Reusable @@ -176,8 +176,8 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 33d348122df228efa234d7b353c33620fc420a59 - MatrixSDKCrypto: 27bee960e0e8b3a3039f3f3e93dd2ec88299c77e + MatrixSDK: b5ab31261eb15cb5e365fbed4ce7de155a21bf8a + MatrixSDKCrypto: 44fd5cac8d3db72a7dd5ded927c2a2f705df7e87 ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 6a49ee70a..36c9232c3 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 6a49ee70a54aa2d4cade316b536f2ca35ce93e73 +Subproject commit 36c9232c3167558a7d936f10e8bfa8d4a38deb7a From 3e1a9eb3da123d1c395508bff22ab777d0a2228b Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 29 May 2025 16:17:08 +0200 Subject: [PATCH 24/61] fixing a test --- RiotTests/Modules/Encryption/EncryptionTrustLevelTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RiotTests/Modules/Encryption/EncryptionTrustLevelTests.swift b/RiotTests/Modules/Encryption/EncryptionTrustLevelTests.swift index 1632da47f..ec87c1c29 100644 --- a/RiotTests/Modules/Encryption/EncryptionTrustLevelTests.swift +++ b/RiotTests/Modules/Encryption/EncryptionTrustLevelTests.swift @@ -25,7 +25,8 @@ class EncryptionTrustLevelTests: XCTestCase { identity: .other( userId: "Bob", masterKey: "MSK", - selfSigningKey: "SSK" + selfSigningKey: "SSK", + hasVerificationViolation: false ), isVerified: isVerified ) From b7ab797172517b1968846c5df0fa50071d2f646e Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 29 May 2025 17:02:12 +0200 Subject: [PATCH 25/61] version++ --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index eebfcebc7..67da50a70 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +## Changes in 1.11.29 (2025-05-29) + +No significant changes. + + ## Changes in 1.11.28 (2025-05-28) 🙌 Improvements From bf1680919cac91f9defa1e84a9a9efff68b9ce79 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 29 May 2025 17:02:53 +0200 Subject: [PATCH 26/61] finish version++ From 07368ea14c2f3100716ed23c4a31f20c539a4c88 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 29 May 2025 17:03:00 +0200 Subject: [PATCH 27/61] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 9904a98f5..d6aebd1d1 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.29 -CURRENT_PROJECT_VERSION = 1.11.29 +MARKETING_VERSION = 1.11.30 +CURRENT_PROJECT_VERSION = 1.11.30 From 102e8f6f42454d07b25f68eea9b5343d29122162 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 10 Jun 2025 14:48:40 +0200 Subject: [PATCH 28/61] update crypto sdk --- Podfile.lock | 8 ++++---- matrix-ios-sdk | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index e7dd60ab3..f9e91e62f 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -44,13 +44,13 @@ PODS: - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - - MatrixSDKCrypto (= 0.11.0) + - MatrixSDKCrypto (= 0.11.1) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - MatrixSDK/JingleCallStack (0.27.17): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - - MatrixSDKCrypto (0.11.0) + - MatrixSDKCrypto (0.11.1) - ReadMoreTextView (3.0.1) - Realm (10.27.0): - Realm/Headers (= 10.27.0) @@ -176,8 +176,8 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: b5ab31261eb15cb5e365fbed4ce7de155a21bf8a - MatrixSDKCrypto: 44fd5cac8d3db72a7dd5ded927c2a2f705df7e87 + MatrixSDK: 45f9f97e7424e5d8731bf6b207c728a71caa8eb1 + MatrixSDKCrypto: e44608012cae9befc52f13cd8e56c6f51ac83702 ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 36c9232c3..8e6c4f42a 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 36c9232c3167558a7d936f10e8bfa8d4a38deb7a +Subproject commit 8e6c4f42a20e090f01c7402be46d4dbd09acc6d1 From 31690d0d81a103bf7ce2d5f75fcb940f64c0daf5 Mon Sep 17 00:00:00 2001 From: Baxrom Date: Sun, 1 Jun 2025 10:37:21 +0000 Subject: [PATCH 29/61] Added translation using Weblate (Uzbek) --- Riot/Assets/uz.lproj/Localizable.strings | 1 + 1 file changed, 1 insertion(+) create mode 100644 Riot/Assets/uz.lproj/Localizable.strings diff --git a/Riot/Assets/uz.lproj/Localizable.strings b/Riot/Assets/uz.lproj/Localizable.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Riot/Assets/uz.lproj/Localizable.strings @@ -0,0 +1 @@ + From ebbe0ed0a9a0a4aba8bb60137b971de6949d825f Mon Sep 17 00:00:00 2001 From: Someone Date: Sun, 8 Jun 2025 13:41:48 +0000 Subject: [PATCH 30/61] Translated using Weblate (Vietnamese) Currently translated at 100.0% (51 of 51 strings) Translation: Element iOS/Element iOS (Push) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-push/vi/ --- Riot/Assets/vi.lproj/Localizable.strings | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Riot/Assets/vi.lproj/Localizable.strings b/Riot/Assets/vi.lproj/Localizable.strings index bbad48963..01b38d1bb 100644 --- a/Riot/Assets/vi.lproj/Localizable.strings +++ b/Riot/Assets/vi.lproj/Localizable.strings @@ -38,17 +38,17 @@ /* Incoming one-to-one video call */ "VIDEO_CALL_FROM_USER" = "Gọi video từ %@"; /* Incoming unnamed voice conference invite from a specific person */ -"VOICE_CONF_FROM_USER" = "Gọi nhóm từ %@"; +"VOICE_CONF_FROM_USER" = "Cuộc gọi nhóm từ %@"; /* Incoming unnamed video conference invite from a specific person */ -"VIDEO_CONF_FROM_USER" = "Gọi video nhóm từ %@"; +"VIDEO_CONF_FROM_USER" = "Cuộc gọi truyền hình nhóm từ %@"; /* Incoming named voice conference invite from a specific person */ -"VOICE_CONF_NAMED_FROM_USER" = "Gọi nhóm từ %@: '%@'"; +"VOICE_CONF_NAMED_FROM_USER" = "Cuộc gọi nhóm từ %@: '%@'"; /* Incoming named video conference invite from a specific person */ -"VIDEO_CONF_NAMED_FROM_USER" = "Gọi video nhóm từ %@: '%@'"; +"VIDEO_CONF_NAMED_FROM_USER" = "Cuộc gọi video nhóm từ %@: '%@'"; /** Key verification **/ -"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ muốn xác minh"; +"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ muốn xác thực"; /* Group call from user, CallKit caller name */ "GROUP_CALL_FROM_USER" = "%@ (cuộc gọi nhóm)"; @@ -60,7 +60,7 @@ "USER_MEMBERSHIP_UPDATED" = "%@ đã cập nhật hồ sơ"; /* A user has change their avatar */ -"USER_UPDATED_AVATAR" = "%@ đã đổi avatar"; +"USER_UPDATED_AVATAR" = "%@ đã đổi ảnh đại diện"; /* A user has change their name to a new name which we don't know */ "GENERIC_USER_UPDATED_DISPLAYNAME" = "%@ đã đổi tên"; @@ -71,7 +71,7 @@ "USER_UPDATED_DISPLAYNAME" = "%@ đã đổi tên sang %@"; /* A user has reacted to a message, but the reaction content is unknown */ -"GENERIC_REACTION_FROM_USER" = "%@ đã gửi một tương tác"; +"GENERIC_REACTION_FROM_USER" = "%@ đã bày tỏ cảm xúc"; /** Reactions **/ @@ -96,10 +96,10 @@ "STICKER_FROM_USER" = "%@ đã gửi một sticker"; /* A single unread message */ -"SINGLE_UNREAD" = "Bạn đã nhận một tin nhắn"; +"SINGLE_UNREAD" = "Bạn nhận được một tin nhắn"; /* A single unread message in a room */ -"SINGLE_UNREAD_IN_ROOM" = "Bạn đã nhận một tin nhắn trong %@"; +"SINGLE_UNREAD_IN_ROOM" = "Bạn nhận được một tin nhắn trong %@"; /* New file message from a specific person, not referencing a room. */ "FILE_FROM_USER" = "%@ đã gửi một tệp %@"; @@ -131,3 +131,6 @@ /** General **/ "Notification" = "Thông báo"; +"VOICE_BROADCAST_FROM_USER" = "%@ bắt đầu phát thanh"; +"UNSUPPORTED_CALL" = "Cuộc gọi không được hỗ trợ"; +"LOCATION_FROM_USER" = "%@ đã chia sẻ vị trí của họ"; From 2ceb13a95c201a36179c9d4a9bf03cb96d8dd92b Mon Sep 17 00:00:00 2001 From: Baxrom Date: Sun, 1 Jun 2025 10:36:35 +0000 Subject: [PATCH 31/61] Added translation using Weblate (Uzbek) --- Riot/Assets/uz.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) create mode 100644 Riot/Assets/uz.lproj/Vector.strings diff --git a/Riot/Assets/uz.lproj/Vector.strings b/Riot/Assets/uz.lproj/Vector.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Riot/Assets/uz.lproj/Vector.strings @@ -0,0 +1 @@ + From 142c6a2c9efe51d99b9a320ac4b1b603cb31b688 Mon Sep 17 00:00:00 2001 From: Baxrom Date: Sun, 1 Jun 2025 10:38:02 +0000 Subject: [PATCH 32/61] Translated using Weblate (Uzbek) Currently translated at 0.1% (1 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uz/ --- Riot/Assets/uz.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/uz.lproj/Vector.strings b/Riot/Assets/uz.lproj/Vector.strings index 8b1378917..bf8bb59b9 100644 --- a/Riot/Assets/uz.lproj/Vector.strings +++ b/Riot/Assets/uz.lproj/Vector.strings @@ -1 +1 @@ - +"store_short_description" = "Xavfsiz markazlashmagan chat/VoIP"; From 2a11bd7d50dadb5306d61eaeb17a61a5cf0719c3 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 10 Jun 2025 18:05:32 +0200 Subject: [PATCH 33/61] version++ --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 67da50a70..22b2255b0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +## Changes in 1.11.30 (2025-06-10) + +No significant changes. + + ## Changes in 1.11.29 (2025-05-29) No significant changes. From 2b451b709a8dd7faf5a7daee072b4911cc2e4abf Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 10 Jun 2025 18:43:15 +0200 Subject: [PATCH 34/61] finish version++ From 8d537f3d469b125aa8db8baac3a6bdcc9a0e6c11 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 10 Jun 2025 18:43:21 +0200 Subject: [PATCH 35/61] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index d6aebd1d1..5daadeaed 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.30 -CURRENT_PROJECT_VERSION = 1.11.30 +MARKETING_VERSION = 1.11.31 +CURRENT_PROJECT_VERSION = 1.11.31 From 1db7169d4e7adc8c5e8b9333e16f2e4341a908d3 Mon Sep 17 00:00:00 2001 From: mxandreas Date: Mon, 14 Jul 2025 09:13:39 +0100 Subject: [PATCH 36/61] Updated the status of the app to make clear it is not receiving further updates. (#7946) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 512bba5c0..c64e9eb8d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ![GitHub](https://img.shields.io/github/license/element-hq/element-ios) [![Twitter URL](https://img.shields.io/twitter/url?label=Element&url=https%3A%2F%2Ftwitter.com%2Felement_hq)](https://twitter.com/element_hq) -Element iOS is an iOS [Matrix](https://matrix.org/) client provided by [Element](https://element.io/). It is based on [MatrixSDK](https://github.com/matrix-org/matrix-ios-sdk). +Element Classic iOS is a previous-generation [Matrix](https://matrix.org/) client provided by [Element](https://element.io/). It is based on [MatrixSDK](https://github.com/matrix-org/matrix-ios-sdk). This client is still supported and receives security updates but no new features or usability enhancements are made. It is recommended to use [Element X](https://github.com/element-hq/element-x-ios) that is the next-generation mobile app.

From 1a23b848829bd5b9ad5d5bbcab9700118279bfbd Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 22 Jul 2025 16:17:48 +0200 Subject: [PATCH 37/61] replaced deprecated function with the new one to check for power levels --- Riot/Managers/Widgets/WidgetManager.m | 2 +- .../AllChatsEditActionProvider.swift | 6 ++++-- .../AllChatsSpaceActionProvider.swift | 6 ++++-- .../IntegrationManagerViewController.m | 2 +- .../Integrations/Widgets/WidgetViewController.m | 2 +- .../MXKRoomMemberDetailsViewController.m | 11 ++++++----- .../MXKRoomMemberListViewController.m | 2 +- .../Models/Room/MXKRoomBubbleCellData.m | 2 +- .../MatrixKit/Views/MXKEventDetailsView.m | 2 +- .../MatrixKit/Views/RoomTitle/MXKRoomTitleView.m | 2 +- .../Views/RoomTitle/MXKRoomTitleViewWithTopic.m | 4 ++-- .../Detail/RoomMemberDetailsViewController.m | 6 +++--- .../Members/RoomParticipantsViewController.m | 6 +++--- ...tsInviteModalCoordinatorBridgePresenter.swift | 5 +++-- Riot/Modules/Room/RoomViewController.m | 4 ++-- .../Room/Settings/RoomSettingsViewController.m | 8 ++++---- Riot/Modules/SideMenu/SideMenuCoordinator.swift | 5 +++-- .../SpaceMembers/SpaceMembersCoordinator.swift | 5 +++-- .../ExploreRoom/SpaceExploreRoomViewModel.swift | 2 +- .../Coordinator/LocationSharingCoordinator.swift | 5 +++-- .../CompletionSuggestionCoordinator.swift | 12 ++++++++---- .../Service/MatrixSDK/SpaceSettingsService.swift | 16 ++++++++-------- 22 files changed, 64 insertions(+), 51 deletions(-) diff --git a/Riot/Managers/Widgets/WidgetManager.m b/Riot/Managers/Widgets/WidgetManager.m index 2513ca40e..4924c32e7 100644 --- a/Riot/Managers/Widgets/WidgetManager.m +++ b/Riot/Managers/Widgets/WidgetManager.m @@ -345,7 +345,7 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain"; // Check user's power in the room MXRoomPowerLevels *powerLevels = roomState.powerLevels; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:room.mxSession.myUser.userId]; + NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:room.mxSession.myUser.userId]; // The user must be able to send state events to manage widgets if (oneSelfPowerLevel < powerLevels.stateDefault) diff --git a/Riot/Modules/ContextMenu/ActionProviders/AllChatsEditActionProvider.swift b/Riot/Modules/ContextMenu/ActionProviders/AllChatsEditActionProvider.swift index a17563d45..cc3457702 100644 --- a/Riot/Modules/ContextMenu/ActionProviders/AllChatsEditActionProvider.swift +++ b/Riot/Modules/ContextMenu/ActionProviders/AllChatsEditActionProvider.swift @@ -105,10 +105,12 @@ class AllChatsEditActionProvider { spaceRoom.state { [weak self] roomState in guard let self = self else { return } - guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else { + guard let roomState, + let powerLevels = roomState.powerLevels, + let userId = session.myUserId else { return } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId) + let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId) self.isInviteAvailable = userPowerLevel >= powerLevels.invite self.isAddRoomAvailable = userPowerLevel >= parentSpace.minimumPowerLevelForAddingRoom(with: powerLevels) diff --git a/Riot/Modules/ContextMenu/ActionProviders/AllChatsSpaceActionProvider.swift b/Riot/Modules/ContextMenu/ActionProviders/AllChatsSpaceActionProvider.swift index 501f730a9..5f90a33ea 100644 --- a/Riot/Modules/ContextMenu/ActionProviders/AllChatsSpaceActionProvider.swift +++ b/Riot/Modules/ContextMenu/ActionProviders/AllChatsSpaceActionProvider.swift @@ -77,10 +77,12 @@ class AllChatsSpaceActionProvider { spaceRoom.state { [weak self] roomState in guard let self = self else { return } - guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else { + guard let roomState, + let powerLevels = roomState.powerLevels, + let userId = session.myUserId else { return } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId) + let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId) self.isInviteAvailable = userPowerLevel >= powerLevels.invite diff --git a/Riot/Modules/Integrations/IntegrationManagerViewController.m b/Riot/Modules/Integrations/IntegrationManagerViewController.m index d97a0d43b..2b815479e 100644 --- a/Riot/Modules/Integrations/IntegrationManagerViewController.m +++ b/Riot/Modules/Integrations/IntegrationManagerViewController.m @@ -489,7 +489,7 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ"; MXJSONModelSetBoolean(isState, requestData[@"is_state"]); MXRoomPowerLevels *powerLevels = roomState.powerLevels; - NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self->mxSession.myUser.userId]; + NSInteger userPowerLevel = [roomState powerLevelOfUserWithUserID:self->mxSession.myUser.userId]; BOOL canSend = NO; diff --git a/Riot/Modules/Integrations/Widgets/WidgetViewController.m b/Riot/Modules/Integrations/Widgets/WidgetViewController.m index dd5d3055e..2f849b650 100644 --- a/Riot/Modules/Integrations/Widgets/WidgetViewController.m +++ b/Riot/Modules/Integrations/Widgets/WidgetViewController.m @@ -94,7 +94,7 @@ NSString *const kJavascriptSendResponseToPostMessageAPI = @"riotIOS.sendResponse { // Check user's power in the room MXRoomPowerLevels *powerLevels = roomState.powerLevels; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:session.myUser.userId]; + NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:session.myUser.userId]; // The user must be able to send state events to manage widgets if (oneSelfPowerLevel >= powerLevels.stateDefault) diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m index 6e154a5ad..39bb1854c 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m @@ -639,9 +639,10 @@ Please see LICENSE in the repository root for full details. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Check user's power level before allowing an action (kick, ban, ...) + MXRoomState *roomState = self.mxRoomLiveTimeline.state; MXRoomPowerLevels *powerLevels = [self.mxRoomLiveTimeline.state powerLevels]; - NSInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:_mxRoomMember.userId]; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger memberPowerLevel = [roomState powerLevelOfUserWithUserID:_mxRoomMember.userId]; + NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; [actionsArray removeAllObjects]; @@ -894,14 +895,14 @@ Please see LICENSE in the repository root for full details. - (void)setPowerLevel:(NSInteger)value promptUser:(BOOL)promptUser { - NSInteger currentPowerLevel = [self.mxRoomLiveTimeline.state.powerLevels powerLevelOfUserWithUserID:_mxRoomMember.userId]; + NSInteger currentPowerLevel = [self.mxRoomLiveTimeline.state powerLevelOfUserWithUserID:_mxRoomMember.userId]; // check if the power level has not yet been set to 0 if (value != currentPowerLevel) { __weak typeof(self) weakSelf = self; - if (promptUser && value == [self.mxRoomLiveTimeline.state.powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]) + if (promptUser && value == [self.mxRoomLiveTimeline.state powerLevelOfUserWithUserID:self.mainSession.myUser.userId]) { // If the user is setting the same power level as his to another user, ask him for a confirmation if (currentAlert) @@ -999,7 +1000,7 @@ Please see LICENSE in the repository root for full details. typeof(self) self = weakSelf; textField.secureTextEntry = NO; - textField.text = [NSString stringWithFormat:@"%ld", (long)[self.mxRoomLiveTimeline.state.powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId]]; + textField.text = [NSString stringWithFormat:@"%ld", (long)[self.mxRoomLiveTimeline.state powerLevelOfUserWithUserID:self.mxRoomMember.userId]]; textField.placeholder = nil; textField.keyboardType = UIKeyboardTypeDecimalPad; }]; diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m index 9ab243448..e1ca0233b 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m @@ -307,7 +307,7 @@ Please see LICENSE in the repository root for full details. if (showInvitationOption && self->dataSource) { // Check conditions to be able to invite someone - NSInteger oneSelfPowerLevel = [roomState.powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger oneSelfPowerLevel = [roomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; if (oneSelfPowerLevel < [roomState.powerLevels invite]) { showInvitationOption = NO; diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m index 6698aee39..73d31c891 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m @@ -691,7 +691,7 @@ Please see LICENSE in the repository root for full details. - (BOOL)canInvitePeople { NSInteger requiredLevel = roomDataSource.roomState.powerLevels.invite; - NSInteger myLevel = [roomDataSource.roomState.powerLevels powerLevelOfUserWithUserID:roomDataSource.mxSession.myUserId]; + NSInteger myLevel = [roomDataSource.roomState powerLevelOfUserWithUserID:roomDataSource.mxSession.myUserId]; return myLevel >= requiredLevel; } diff --git a/Riot/Modules/MatrixKit/Views/MXKEventDetailsView.m b/Riot/Modules/MatrixKit/Views/MXKEventDetailsView.m index e8473e0c3..fd549a9f3 100644 --- a/Riot/Modules/MatrixKit/Views/MXKEventDetailsView.m +++ b/Riot/Modules/MatrixKit/Views/MXKEventDetailsView.m @@ -123,7 +123,7 @@ Please see LICENSE in the repository root for full details. MXStrongifyAndReturnIfNil(self); MXRoomPowerLevels *powerLevels = [roomState powerLevels]; - NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self->mxSession.myUser.userId]; + NSInteger userPowerLevel = [roomState powerLevelOfUserWithUserID:self->mxSession.myUser.userId]; if (powerLevels.redact) { if (userPowerLevel >= powerLevels.redact) diff --git a/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m b/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m index 8365f8c7a..107342d22 100644 --- a/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m +++ b/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleView.m @@ -176,7 +176,7 @@ Please see LICENSE in the repository root for full details. // Check whether the user has enough power to rename the room MXRoomPowerLevels *powerLevels = _mxRoom.dangerousSyncState.powerLevels; - NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:_mxRoom.mxSession.myUser.userId]; + NSInteger userPowerLevel = [_mxRoom.dangerousSyncState powerLevelOfUserWithUserID:_mxRoom.mxSession.myUser.userId]; if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName]) { // Only the room name is edited here, update the text field with the room name diff --git a/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.m b/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.m index c5d1c2050..c5cb82688 100644 --- a/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.m +++ b/Riot/Modules/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.m @@ -354,7 +354,7 @@ Please see LICENSE in the repository root for full details. { // Check whether the user has enough power to rename the room MXRoomPowerLevels *powerLevels = self.mxRoom.dangerousSyncState.powerLevels; - NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId]; + NSInteger userPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId]; if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName]) { // Only the room name is edited here, update the text field with the room name @@ -384,7 +384,7 @@ Please see LICENSE in the repository root for full details. { // Check whether the user has enough power to edit room topic MXRoomPowerLevels *powerLevels = self.mxRoom.dangerousSyncState.powerLevels; - NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId]; + NSInteger userPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mxRoom.mxSession.myUser.userId]; if (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomTopic]) { textField.backgroundColor = [UIColor whiteColor]; diff --git a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m index 860feeccd..2e3e5b155 100644 --- a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m +++ b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m @@ -351,7 +351,7 @@ Please see LICENSE in the repository root for full details. MXStrongifyAndReturnIfNil(self); MXRoomPowerLevels *powerLevels = [roomState powerLevels]; - NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId]; + NSInteger powerLevel = [roomState powerLevelOfUserWithUserID:self.mxRoomMember.userId]; RoomPowerLevel roomPowerLevel = [RoomPowerLevelHelper roomPowerLevelFrom:powerLevel]; @@ -500,8 +500,8 @@ Please see LICENSE in the repository root for full details. // Check user's power level before allowing an action (kick, ban, ...) MXRoomPowerLevels *powerLevels = [self.mxRoom.dangerousSyncState powerLevels]; - NSInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId]; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger memberPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mxRoomMember.userId]; + NSInteger oneSelfPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; [adminActionsArray removeAllObjects]; [otherActionsArray removeAllObjects]; diff --git a/Riot/Modules/Room/Members/RoomParticipantsViewController.m b/Riot/Modules/Room/Members/RoomParticipantsViewController.m index 26f98e2e9..bd7f07aed 100644 --- a/Riot/Modules/Room/Members/RoomParticipantsViewController.m +++ b/Riot/Modules/Room/Members/RoomParticipantsViewController.m @@ -716,8 +716,8 @@ Please see LICENSE in the repository root for full details. { // Order first by power levels (admins then moderators then others) MXRoomPowerLevels *powerLevels = [roomState powerLevels]; - NSInteger powerLevelA = [powerLevels powerLevelOfUserWithUserID:contactA.mxMember.userId]; - NSInteger powerLevelB = [powerLevels powerLevelOfUserWithUserID:contactB.mxMember.userId]; + NSInteger powerLevelA = [roomState powerLevelOfUserWithUserID:contactA.mxMember.userId]; + NSInteger powerLevelB = [roomState powerLevelOfUserWithUserID:contactB.mxMember.userId]; if (powerLevelA == powerLevelB) { @@ -981,7 +981,7 @@ Please see LICENSE in the repository root for full details. // Update member power level MXRoomPowerLevels *powerLevels = [roomState powerLevels]; - NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:contact.mxMember.userId]; + NSInteger powerLevel = [roomState powerLevelOfUserWithUserID:contact.mxMember.userId]; RoomPowerLevel roomPowerLevel = [RoomPowerLevelHelper roomPowerLevelFrom:powerLevel]; diff --git a/Riot/Modules/Room/ParticipantsInviteModal/RoomParticipantsInviteModalCoordinatorBridgePresenter.swift b/Riot/Modules/Room/ParticipantsInviteModal/RoomParticipantsInviteModalCoordinatorBridgePresenter.swift index 444a0a090..fb56c8ad5 100644 --- a/Riot/Modules/Room/ParticipantsInviteModal/RoomParticipantsInviteModalCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/ParticipantsInviteModal/RoomParticipantsInviteModalCoordinatorBridgePresenter.swift @@ -163,12 +163,13 @@ final class RoomParticipantsInviteCoordinatorBridgePresenter: NSObject { } room.state { roomState in - guard let powerLevels = roomState?.powerLevels else { + guard let roomState, + let powerLevels = roomState.powerLevels else { MXLog.error("[RoomParticipantsInviteCoordinatorBridgePresenter] canInvite: room powerLevels not found") completion(false) return } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId) + let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId) completion(userPowerLevel >= powerLevels.invite) } diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 656a41399..5ba46c9c2 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -1200,7 +1200,7 @@ static CGSize kThreadListBarButtonItemImageSize; if (self.roomDataSource.roomState) { MXRoomPowerLevels *powerLevels = self.roomDataSource.roomState.powerLevels; - NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger userPowerLevel = [self.roomDataSource.roomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; BOOL canSend = (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsMessage:kMXEventTypeStringRoomMessage]); BOOL isRoomObsolete = self.roomDataSource.roomState.isObsolete; @@ -1856,7 +1856,7 @@ static CGSize kThreadListBarButtonItemImageSize; { MXRoomPowerLevels *powerLevels = [self.roomDataSource.roomState powerLevels]; NSInteger requiredPower = [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventTypeString]; - NSInteger myPower = [powerLevels powerLevelOfUserWithUserID:self.roomDataSource.mxSession.myUserId]; + NSInteger myPower = [self.roomDataSource.roomState powerLevelOfUserWithUserID:self.roomDataSource.mxSession.myUserId]; return myPower >= requiredPower; } diff --git a/Riot/Modules/Room/Settings/RoomSettingsViewController.m b/Riot/Modules/Room/Settings/RoomSettingsViewController.m index f8142a7e7..fc642590d 100644 --- a/Riot/Modules/Room/Settings/RoomSettingsViewController.m +++ b/Riot/Modules/Room/Settings/RoomSettingsViewController.m @@ -609,7 +609,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { // Check user's power level to know whether the user is allowed to turn on the encryption mode MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels]; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption]) { @@ -652,7 +652,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti return; MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels]; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; if (oneSelfPowerLevel < [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventTypeForSelectedField]) return; @@ -2082,7 +2082,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti // Check user's power level to know which settings are editable. MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels]; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; // general settings if (section == SECTION_TAG_MAIN) @@ -3092,7 +3092,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { // Check user's power level to know whether the user is allowed to set the main address MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels]; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + NSInteger oneSelfPowerLevel = [mxRoomState powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAliases]) { diff --git a/Riot/Modules/SideMenu/SideMenuCoordinator.swift b/Riot/Modules/SideMenu/SideMenuCoordinator.swift index 86e902f3d..8f3a77f19 100644 --- a/Riot/Modules/SideMenu/SideMenuCoordinator.swift +++ b/Riot/Modules/SideMenu/SideMenuCoordinator.swift @@ -329,11 +329,12 @@ final class SideMenuCoordinator: NSObject, SideMenuCoordinatorType { spaceRoom.state { [weak self] roomState in guard let self = self else { return } - guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else { + guard let roomState, + let powerLevels = roomState.powerLevels, let userId = session.myUserId else { MXLog.error("[SpaceMembersCoordinator] spaceMemberListCoordinatorShowInvite: failed to find powerLevels for room") return } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId) + let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId) guard userPowerLevel >= powerLevels.invite else { let alert = UIAlertController(title: VectorL10n.spacesInvitePeople, message: VectorL10n.spaceInviteNotEnoughPermission, preferredStyle: .alert) diff --git a/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift b/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift index e5d8252f0..4d29ad958 100644 --- a/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift +++ b/Riot/Modules/Spaces/SpaceMembers/SpaceMembersCoordinator.swift @@ -165,11 +165,12 @@ extension SpaceMembersCoordinator: SpaceMemberListCoordinatorDelegate { spaceRoom.state { [weak self] roomState in guard let self = self else { return } - guard let powerLevels = roomState?.powerLevels, let userId = self.parameters.session.myUserId else { + guard let roomState, + let powerLevels = roomState.powerLevels, let userId = self.parameters.session.myUserId else { MXLog.error("[SpaceMembersCoordinator] spaceMemberListCoordinatorShowInvite: failed to find powerLevels for room") return } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId) + let userPowerLevel = roomState.powerLevelOfUser(withUserID: userId) guard userPowerLevel >= powerLevels.invite else { let alert = UIAlertController(title: VectorL10n.spacesInvitePeople, message: VectorL10n.spaceInviteNotEnoughPermission, preferredStyle: .alert) diff --git a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift index 57fd88f15..35c8c2ee0 100644 --- a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift +++ b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoom/SpaceExploreRoomViewModel.swift @@ -166,7 +166,7 @@ final class SpaceExploreRoomViewModel: SpaceExploreRoomViewModelType { if let spaceRoom = self.spaceRoom { spaceRoom.state { roomState in self.powerLevels = roomState?.powerLevels - self.powerLevelOfCurrentUser = self.powerLevels?.powerLevelOfUser(withUserID: self.session.myUserId) + self.powerLevelOfCurrentUser = roomState?.powerLevelOfUser(withUserID: self.session.myUserId) } } diff --git a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift index 7ba51888c..ed887cfa3 100644 --- a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift +++ b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/Coordinator/LocationSharingCoordinator.swift @@ -158,8 +158,9 @@ final class LocationSharingCoordinator: Coordinator, Presentable { // Check if user can send beacon info state event private func canShareLiveLocation() -> Bool { guard let myUserId = parameters.roomDataSource.mxSession.myUserId, - let roomPowerLevels = parameters.roomDataSource.roomState.powerLevels, - let userPowerLevel = RoomPowerLevel(rawValue: roomPowerLevels.powerLevelOfUser(withUserID: myUserId)) else { + let roomState = parameters.roomDataSource.roomState, + let roomPowerLevels = roomState.powerLevels, + let userPowerLevel = RoomPowerLevel(rawValue: roomState.powerLevelOfUser(withUserID: myUserId)) else { return false } diff --git a/RiotSwiftUI/Modules/Room/CompletionSuggestion/Coordinator/CompletionSuggestionCoordinator.swift b/RiotSwiftUI/Modules/Room/CompletionSuggestion/Coordinator/CompletionSuggestionCoordinator.swift index 00663c0b3..c8383d8e2 100644 --- a/RiotSwiftUI/Modules/Room/CompletionSuggestion/Coordinator/CompletionSuggestionCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/CompletionSuggestion/Coordinator/CompletionSuggestionCoordinator.swift @@ -162,8 +162,10 @@ private class CompletionSuggestionCoordinatorRoomMemberProvider: RoomMembersProv /// Gets the power levels for the room to update suggestions accordingly. func updateWithPowerLevels() { room.state { [weak self] state in - guard let self, let powerLevels = state?.powerLevels else { return } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: self.userID) + guard let self, + let state, + let powerLevels = state.powerLevels else { return } + let userPowerLevel = state.powerLevelOfUser(withUserID: self.userID) let mentionRoomPowerLevel = powerLevels.minimumPowerLevel(forNotifications: kMXRoomPowerLevelNotificationsRoomKey, defaultPower: kMXRoomPowerLevelNotificationsRoomDefault) self.canMentionRoom = userPowerLevel >= mentionRoomPowerLevel @@ -208,9 +210,11 @@ private class CompletionSuggestionCoordinatorCommandProvider: CommandsProviderPr func updateWithPowerLevels() { room.state { [weak self] state in - guard let self, let powerLevels = state?.powerLevels else { return } + guard let self, + let state, + let powerLevels = state.powerLevels else { return } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: self.userID) + let userPowerLevel = state.powerLevelOfUser(withUserID: self.userID) self.isRoomAdmin = RoomPowerLevel(rawValue: userPowerLevel) == .admin } } diff --git a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift index 0b09739f8..e496efac5 100644 --- a/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift +++ b/RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift @@ -150,12 +150,12 @@ class SpaceSettingsService: SpaceSettingsServiceProtocol { return allowedParentIds } - private func isField(ofType notification: String, editableWith powerLevels: MXRoomPowerLevels?) -> Bool { - guard let powerLevels = powerLevels else { + private func isField(ofType notification: String, editableWith roomState: MXRoomState) -> Bool { + guard let powerLevels = roomState.powerLevels else { return false } - let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: session.myUserId) + let userPowerLevel = roomState.powerLevelOfUser(withUserID: session.myUserId) return userPowerLevel >= powerLevels.minimumPowerLevel(forNotifications: notification, defaultPower: powerLevels.stateDefault) } @@ -226,11 +226,11 @@ class SpaceSettingsService: SpaceSettingsServiceProtocol { avatarUrl: roomState.avatar, visibility: visibility(with: roomState), allowedParentIds: allowedParentIds(with: roomState), - isAvatarEditable: isField(ofType: kMXEventTypeStringRoomAvatar, editableWith: roomState.powerLevels), - isNameEditable: isField(ofType: kMXEventTypeStringRoomName, editableWith: roomState.powerLevels), - isTopicEditable: isField(ofType: kMXEventTypeStringRoomTopic, editableWith: roomState.powerLevels), - isAddressEditable: isField(ofType: kMXEventTypeStringRoomAliases, editableWith: roomState.powerLevels), - isAccessEditable: isField(ofType: kMXEventTypeStringRoomJoinRules, editableWith: roomState.powerLevels) + isAvatarEditable: isField(ofType: kMXEventTypeStringRoomAvatar, editableWith: roomState), + isNameEditable: isField(ofType: kMXEventTypeStringRoomName, editableWith: roomState), + isTopicEditable: isField(ofType: kMXEventTypeStringRoomTopic, editableWith: roomState), + isAddressEditable: isField(ofType: kMXEventTypeStringRoomAliases, editableWith: roomState), + isAccessEditable: isField(ofType: kMXEventTypeStringRoomJoinRules, editableWith: roomState) ) } From 584d3790de94acfe74a60e9874bd659edc419b72 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 23 Jul 2025 11:32:48 +0200 Subject: [PATCH 38/61] update SDK --- matrix-ios-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 8e6c4f42a..96940f6d6 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 8e6c4f42a20e090f01c7402be46d4dbd09acc6d1 +Subproject commit 96940f6d6a0686387095c3c99466209d96fe75bd From 68879af97ea173a84cc34fa34894df3bab1edbf3 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 23 Jul 2025 17:05:46 +0200 Subject: [PATCH 39/61] room continuity fix for room version 12 --- changelog.d/pr-7950.feature | 1 + matrix-ios-sdk | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/pr-7950.feature diff --git a/changelog.d/pr-7950.feature b/changelog.d/pr-7950.feature new file mode 100644 index 000000000..2a41b5c61 --- /dev/null +++ b/changelog.d/pr-7950.feature @@ -0,0 +1 @@ +Support for MSC 4289 \ No newline at end of file diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 96940f6d6..d1fe456f9 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 96940f6d6a0686387095c3c99466209d96fe75bd +Subproject commit d1fe456f97b3f3f390d928b7e66fe4ff914039fe From c6c4bd631fbfb7cf2e983f844978585718449c18 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 23 Jul 2025 17:07:39 +0200 Subject: [PATCH 40/61] changelog --- changelog.d/pr-7950.feature | 2 +- changelog.d/pr-7953.bugfix | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/pr-7953.bugfix diff --git a/changelog.d/pr-7950.feature b/changelog.d/pr-7950.feature index 2a41b5c61..b8f2018e8 100644 --- a/changelog.d/pr-7950.feature +++ b/changelog.d/pr-7950.feature @@ -1 +1 @@ -Support for MSC 4289 \ No newline at end of file +Support for MSC 4289. diff --git a/changelog.d/pr-7953.bugfix b/changelog.d/pr-7953.bugfix new file mode 100644 index 000000000..177893afa --- /dev/null +++ b/changelog.d/pr-7953.bugfix @@ -0,0 +1 @@ +Room continuity fix for room version 12. \ No newline at end of file From 4d2ef7788a70741e2f94d1540f9d83b88f8f8edd Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 23 Jul 2025 18:43:03 +0200 Subject: [PATCH 41/61] PL150 users are displayed as Owner in the list --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++++ Riot/Model/Room/RoomPowerLevel.swift | 5 ++++- Riot/Modules/Room/Members/RoomParticipantsViewController.m | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 6adee1f2a..e10a8dbb5 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -523,6 +523,7 @@ Tap the + to start adding people."; "room_member_power_level_moderator_in" = "Moderator in %@"; "room_member_power_level_custom_in" = "Custom (%@) in %@"; +"room_member_power_level_short_owner" = "Owner"; "room_member_power_level_short_admin" = "Admin"; "room_member_power_level_short_moderator" = "Mod"; "room_member_power_level_short_custom" = "Custom"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index d4dc0d142..1ee48dcf0 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -6171,6 +6171,10 @@ public class VectorL10n: NSObject { public static var roomMemberPowerLevelShortModerator: String { return VectorL10n.tr("Vector", "room_member_power_level_short_moderator") } + /// Owner + public static var roomMemberPowerLevelShortOwner: String { + return VectorL10n.tr("Vector", "room_member_power_level_short_owner") + } /// Editing public static var roomMessageEditing: String { return VectorL10n.tr("Vector", "room_message_editing") diff --git a/Riot/Model/Room/RoomPowerLevel.swift b/Riot/Model/Room/RoomPowerLevel.swift index b008801b2..9463f5586 100644 --- a/Riot/Model/Room/RoomPowerLevel.swift +++ b/Riot/Model/Room/RoomPowerLevel.swift @@ -10,13 +10,16 @@ import Foundation /// Riot Standard Room Member Power Level @objc public enum RoomPowerLevel: Int { + case owner = 150 case admin = 100 case moderator = 50 case user = 0 public init?(rawValue: Int) { switch rawValue { - case 100...: + case 150...: + self = .owner + case 100...149: self = .admin case 50...99: self = .moderator diff --git a/Riot/Modules/Room/Members/RoomParticipantsViewController.m b/Riot/Modules/Room/Members/RoomParticipantsViewController.m index bd7f07aed..6ec3b8e7c 100644 --- a/Riot/Modules/Room/Members/RoomParticipantsViewController.m +++ b/Riot/Modules/Room/Members/RoomParticipantsViewController.m @@ -988,6 +988,9 @@ Please see LICENSE in the repository root for full details. NSString *powerLevelText; switch (roomPowerLevel) { + case RoomPowerLevelOwner: + powerLevelText = [VectorL10n roomMemberPowerLevelShortOwner]; + break; case RoomPowerLevelAdmin: powerLevelText = [VectorL10n roomMemberPowerLevelShortAdmin]; break; From eb0deaa54d0773339598581f22496578d2aa793a Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 23 Jul 2025 18:50:10 +0200 Subject: [PATCH 42/61] added also the owner in x string --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++++ .../Room/Members/Detail/RoomMemberDetailsViewController.m | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index e10a8dbb5..c5a94ded1 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -519,6 +519,7 @@ Tap the + to start adding people."; "room_participants_security_information_room_encrypted" = "Messages in this room are end-to-end encrypted.\n\nYour messages are secured with locks and only you and the recipient have the unique keys to unlock them."; "room_participants_security_information_room_encrypted_for_dm" = "Messages here are end-to-end encrypted.\n\nYour messages are secured with locks and only you and the recipient have the unique keys to unlock them."; +"room_member_power_level_owner_in" = "Owner in %@"; "room_member_power_level_admin_in" = "Admin in %@"; "room_member_power_level_moderator_in" = "Moderator in %@"; "room_member_power_level_custom_in" = "Custom (%@) in %@"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 1ee48dcf0..790cbb1af 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -6155,6 +6155,10 @@ public class VectorL10n: NSObject { public static func roomMemberPowerLevelModeratorIn(_ p1: String) -> String { return VectorL10n.tr("Vector", "room_member_power_level_moderator_in", p1) } + /// Owner in %@ + public static func roomMemberPowerLevelOwnerIn(_ p1: String) -> String { + return VectorL10n.tr("Vector", "room_member_power_level_owner_in", p1) + } /// You will not be able to undo this change as you are promoting the user to have the same power level as yourself.\nAre you sure? public static var roomMemberPowerLevelPrompt: String { return VectorL10n.tr("Vector", "room_member_power_level_prompt") diff --git a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m index 2e3e5b155..07b3f3dd3 100644 --- a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m +++ b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m @@ -356,6 +356,10 @@ Please see LICENSE in the repository root for full details. RoomPowerLevel roomPowerLevel = [RoomPowerLevelHelper roomPowerLevelFrom:powerLevel]; switch (roomPowerLevel) { + case RoomPowerLevelOwner: + self.roomMemberPowerLevelLabel.text = [VectorL10n roomMemberPowerLevelOwnerIn:self.mxRoom.summary.displayName]; + self.roomMemberPowerLevelContainerView.hidden = NO; + break; case RoomPowerLevelAdmin: self.roomMemberPowerLevelLabel.text = [VectorL10n roomMemberPowerLevelAdminIn:self.mxRoom.summary.displayName]; self.roomMemberPowerLevelContainerView.hidden = NO; From 492bc8c2cd450aa4149d3b2d6c8a89e33124ec77 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 24 Jul 2025 17:07:29 +0200 Subject: [PATCH 43/61] implemented in `RoomInfoListViewController` --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Categories/MXRoom.swift | 33 +++++++++++++++++++ Riot/Generated/Strings.swift | 4 +++ .../RoomInfoListViewController.swift | 17 +++++++++- .../RoomInfoList/RoomInfoListViewData.swift | 1 + .../RoomInfoList/RoomInfoListViewModel.swift | 7 +++- 6 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 Riot/Categories/MXRoom.swift diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index c5a94ded1..d79c30175 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -479,6 +479,7 @@ Tap the + to start adding people."; "room_participants_invite_malformed_id" = "Malformed ID. Should be an email address or a Matrix ID like '@localpart:domain'"; "room_participants_invited_section" = "INVITED"; "room_participants_start_new_chat_error_using_user_email_without_identity_server" = "No identity server is configured so you cannot start a chat with a contact using an email."; +"room_participants_leave_not_allowed_for_last_owner_msg" = "You can't leave the room since you're the only owner of it."; "room_participants_online" = "Online"; "room_participants_offline" = "Offline"; diff --git a/Riot/Categories/MXRoom.swift b/Riot/Categories/MXRoom.swift new file mode 100644 index 000000000..02919c0a0 --- /dev/null +++ b/Riot/Categories/MXRoom.swift @@ -0,0 +1,33 @@ +// +// Copyright 2025 New Vector Ltd +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +@objc +extension MXRoom { + /// Returns true if the user is the last owner of the room, but not the last member. + func isLastOwner() async throws -> Bool { + let userID = mxSession.myUserId + let state = try await state() + + guard RoomPowerLevelHelper.roomPowerLevel(from: state.powerLevelOfUser(withUserID: userID)) == .owner else { + return false + } + + guard let joinedMembers = try await members()?.members(with: .join) else { + return false + } + + var isLastMember = true + for member in joinedMembers where member.userId != userID { + isLastMember = false + // If there are other owners they can leave + if RoomPowerLevelHelper.roomPowerLevel(from: state.powerLevelOfUser(withUserID: member.userId)) == .owner { + return false + } + } + return !isLastMember + } +} diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 790cbb1af..9c4bc1ee0 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -6447,6 +6447,10 @@ public class VectorL10n: NSObject { public static var roomParticipantsInvitedSection: String { return VectorL10n.tr("Vector", "room_participants_invited_section") } + /// You can't leave the room since you're the only owner of it + public static var roomParticipantsLeaveNotAllowedForLastOwnerMsg: String { + return VectorL10n.tr("Vector", "room_participants_leave_not_allowed_for_last_owner_msg") + } /// Leaving public static var roomParticipantsLeaveProcessing: String { return VectorL10n.tr("Vector", "room_participants_leave_processing") diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift index 383beac30..22f50ba99 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift @@ -75,6 +75,17 @@ final class RoomInfoListViewController: UIViewController { return controller }() + private lazy var isLastOwnerAlertController: UIAlertController = { + let title = VectorL10n.error + let message = VectorL10n.roomParticipantsLeaveNotAllowedForLastOwnerMsg + let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) + + controller.addAction(UIAlertAction(title: VectorL10n.ok, style: .default, handler: nil)) + controller.mxk_setAccessibilityIdentifier("RoomSettingsVCLastOwnerAlert") + + return controller + }() + private enum RowType { case `default` case destructive @@ -216,7 +227,11 @@ final class RoomInfoListViewController: UIViewController { VectorL10n.roomParticipantsLeavePromptTitleForDm : VectorL10n.roomParticipantsLeavePromptTitle let rowLeave = Row(type: .destructive, icon: Asset.Images.roomActionLeave.image, text: leaveTitle, accessoryType: .none) { - self.present(self.leaveAlertController, animated: true, completion: nil) + if viewData.isLastOwner { + self.present(self.isLastOwnerAlertController, animated: true, completion: nil) + } else { + self.present(self.leaveAlertController, animated: true, completion: nil) + } } let sectionLeave = Section(header: nil, rows: [rowLeave], diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewData.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewData.swift index c217514b8..b8be0b49e 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewData.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewData.swift @@ -24,4 +24,5 @@ struct RoomInfoListViewData { let isEncrypted: Bool let isDirect: Bool let basicInfoViewData: RoomInfoBasicViewData + let isLastOwner: Bool } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift index bf2c82e9b..c208647a4 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift @@ -26,6 +26,7 @@ final class RoomInfoListViewModel: NSObject, RoomInfoListViewModelType { private let session: MXSession private let room: MXRoom + private var isLastOwner = false // MARK: Public @@ -51,7 +52,8 @@ final class RoomInfoListViewModel: NSObject, RoomInfoListViewModelType { return RoomInfoListViewData(numberOfMembers: Int(room.summary.membersCount.joined), isEncrypted: room.summary.isEncrypted, isDirect: room.isDirect, - basicInfoViewData: basicInfoViewData) + basicInfoViewData: basicInfoViewData, + isLastOwner: isLastOwner) } // MARK: - Setup @@ -97,6 +99,9 @@ final class RoomInfoListViewModel: NSObject, RoomInfoListViewModelType { @objc private func roomSummaryUpdated(_ notification: Notification) { // force update view self.update(viewState: .loaded(viewData: viewData)) + Task { + isLastOwner = (try? await room.isLastOwner()) == true + } } private func loadData() { From a6022e1481a3115b95751719fa2c564329907edb Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 24 Jul 2025 18:52:36 +0200 Subject: [PATCH 44/61] added alert in the action context service and in the RecentsViewController --- Riot/Generated/Strings.swift | 2 +- .../Common/Recents/RecentsViewController.m | 274 ++++++++++-------- .../Services/RoomContextActionService.swift | 31 +- 3 files changed, 176 insertions(+), 131 deletions(-) diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 9c4bc1ee0..e3b56a714 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -6447,7 +6447,7 @@ public class VectorL10n: NSObject { public static var roomParticipantsInvitedSection: String { return VectorL10n.tr("Vector", "room_participants_invited_section") } - /// You can't leave the room since you're the only owner of it + /// You can't leave the room since you're the only owner of it. public static var roomParticipantsLeaveNotAllowedForLastOwnerMsg: String { return VectorL10n.tr("Vector", "room_participants_leave_not_allowed_for_last_owner_msg") } diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 21abf0791..98fe7dd63 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -1,10 +1,10 @@ /* -Copyright 2018-2024 New Vector Ltd. -Copyright 2017 Vector Creations Ltd -Copyright 2015 OpenMarket Ltd - -SPDX-License-Identifier: AGPL-3.0-only -Please see LICENSE in the repository root for full details. + Copyright 2018-2024 New Vector Ltd. + Copyright 2017 Vector Creations Ltd + Copyright 2015 OpenMarket Ltd + + SPDX-License-Identifier: AGPL-3.0-only + Please see LICENSE in the repository root for full details. */ #import "RecentsViewController.h" @@ -124,7 +124,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro [tableSearchBar setImage:AssetImages.filterOff.image forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal]; - + tableSearchBar.delegate = self; displayedSectionHeaders = [NSMutableArray array]; @@ -132,7 +132,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro _contextMenuProvider = [RecentCellContextMenuProvider new]; self.contextMenuProvider.serviceDelegate = self; self.contextMenuProvider.menuProviderDelegate = self; - + // Set itself as delegate by default. self.delegate = self; } @@ -150,10 +150,10 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro // Register key backup banner cells [self.recentsTableView registerNib:SecureBackupBannerCell.nib forCellReuseIdentifier:SecureBackupBannerCell.defaultReuseIdentifier]; - + // Register key verification banner cells [self.recentsTableView registerNib:CrossSigningSetupBannerCell.nib forCellReuseIdentifier:CrossSigningSetupBannerCell.defaultReuseIdentifier]; - + [self.recentsTableView registerClass:SectionHeaderView.class forHeaderFooterViewReuseIdentifier:SectionHeaderView.defaultReuseIdentifier]; @@ -180,7 +180,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro [self.recentsSearchBar setImage:AssetImages.filterOff.image forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal]; - + // Observe user interface theme change. kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { @@ -195,7 +195,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)userInterfaceThemeDidChange { [ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar]; - + self.activityIndicator.backgroundColor = ThemeService.shared.theme.overlayBackgroundColor; // Use the primary bg color for the recents table view in plain style. @@ -203,15 +203,15 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro self.recentsTableView.separatorColor = ThemeService.shared.theme.lineBreakColor; topview.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; self.view.backgroundColor = ThemeService.shared.theme.backgroundColor; - + [ThemeService.shared.theme applyStyleOnSearchBar:tableSearchBar]; [ThemeService.shared.theme applyStyleOnSearchBar:self.recentsSearchBar]; - + // Force table refresh [self.recentsTableView reloadData]; [self.emptyView updateWithTheme:ThemeService.shared.theme]; - + [self setNeedsStatusBarAppearanceUpdate]; } @@ -270,7 +270,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro isViewVisible = YES; [self.screenTracker trackScreen]; - + // Reset back user interactions self.userInteractionEnabled = YES; @@ -341,7 +341,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro // the selected room (if any) is highlighted. [self refreshCurrentSelectedCell:YES]; } - + if (self.recentsDataSource) { [self refreshRecentsTable]; @@ -906,10 +906,10 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro { Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerInvite; } - + // Avoid multiple openings of rooms self.userInteractionEnabled = NO; - + // Do not stack views when showing room ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO]; @@ -928,7 +928,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro - (void)showRoomPreviewWithData:(RoomPreviewData*)roomPreviewData { Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerRoomDirectory; - + // Do not stack views when showing room ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO sender:nil sourceView:nil]; @@ -1001,7 +1001,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro { // Retrieve the invited room MXRoom *invitedRoom = userInfo[kInviteRecentTableViewCellRoomKey]; - + if (invitedRoom.summary.roomType == MXRoomTypeSpace) { // Indicates that spaces are not supported @@ -1016,7 +1016,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro { // Retrieve the invited room MXRoom *invitedRoom = userInfo[kInviteRecentTableViewCellRoomKey]; - + if (invitedRoom.summary.roomType == MXRoomTypeSpace) { // Indicates that spaces are not supported @@ -1055,7 +1055,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro [super dataSource:dataSource didCellChange:changes]; return; } - + if ([changes isKindOfClass:NSIndexPath.class]) { NSIndexPath *indexPath = (NSIndexPath *)changes; @@ -1066,7 +1066,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro TableViewCellWithCollectionView *collectionViewCell = (TableViewCellWithCollectionView *)cell; [collectionViewCell.collectionView reloadData]; - + CGRect headerFrame = [self.recentsTableView rectForHeaderInSection:indexPath.section]; UIView *headerView = [self.recentsTableView headerViewForSection:indexPath.section]; UIView *updatedHeaderView = [self.dataSource viewForHeaderInSection:indexPath.section withFrame:headerFrame inTableView:self.recentsTableView]; @@ -1104,7 +1104,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro } [self showEmptyViewIfNeeded]; - + if (dataSource.state == MXKDataSourceStateReady) { [[NSNotificationCenter defaultCenter] postNotificationName:RecentsViewControllerDataReadyNotification @@ -1113,109 +1113,141 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro } #pragma mark - Swipe actions - - (void)leaveEditedRoom { if (editedRoomId) { NSString *currentRoomId = editedRoomId; - __weak typeof(self) weakSelf = self; - NSString *title, *message; - if ([self.mainSession roomWithRoomId:currentRoomId].isDirect) - { - title = [VectorL10n roomParticipantsLeavePromptTitleForDm]; - message = [VectorL10n roomParticipantsLeavePromptMsgForDm]; - } - else - { - title = [VectorL10n roomParticipantsLeavePromptTitle]; - message = [VectorL10n roomParticipantsLeavePromptMsg]; - } - - // confirm leave - UIAlertController *leavePrompt = [UIAlertController alertControllerWithTitle:title - message:message - preferredStyle:UIAlertControllerStyleAlert]; - - [leavePrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] - style:UIAlertActionStyleCancel - handler:^(UIAlertAction * action) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - } - - }]]; - - [leavePrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n leave] - style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - - // Check whether the user didn't leave the room yet - // TODO: Handle multi-account - MXRoom *room = [self.mainSession roomWithRoomId:currentRoomId]; - if (room) - { - [self startActivityIndicatorWithLabel:[VectorL10n roomParticipantsLeaveProcessing]]; - // cancel pending uploads/downloads - // they are useless by now - [MXMediaManager cancelDownloadsInCacheFolder:room.roomId]; - - // TODO GFO cancel pending uploads related to this room - - MXLogDebug(@"[RecentsViewController] Leave room (%@)", room.roomId); - - [room leave:^{ - - if (weakSelf) - { - typeof(self) self = weakSelf; - [self stopActivityIndicator]; - [self.userIndicatorStore presentSuccessWithLabel:[VectorL10n roomParticipantsLeaveSuccess]]; - // Force table refresh - [self cancelEditionMode:YES]; - } - - } failure:^(NSError *error) { - - MXLogDebug(@"[RecentsViewController] Failed to leave room"); - if (weakSelf) - { - typeof(self) self = weakSelf; - // Notify the end user - NSString *userId = room.mxSession.myUser.userId; - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification - object:error - userInfo:userId ? @{kMXKErrorUserIdKey: userId} : nil]; - - [self stopActivityIndicator]; - - // Leave editing mode - [self cancelEditionMode:self->isRefreshPending]; - } - - }]; - } - else - { - // Leave editing mode - [self cancelEditionMode:self->isRefreshPending]; - } - } - - }]]; - - [leavePrompt mxk_setAccessibilityIdentifier:@"LeaveEditedRoomAlert"]; - [self presentViewController:leavePrompt animated:YES completion:nil]; - currentAlert = leavePrompt; + MXRoom *room = [self.mainSession roomWithRoomId:currentRoomId]; + __weak typeof(room) weakRoom = room; + [room isLastOwnerWithCompletionHandler:^(BOOL isLastOwner, NSError* error){ + if (isLastOwner) + { + UIAlertController *isLastOwnerPrompt = [UIAlertController alertControllerWithTitle:[VectorL10n error] + message:[VectorL10n roomParticipantsLeaveNotAllowedForLastOwnerMsg] + preferredStyle:UIAlertControllerStyleAlert]; + + [isLastOwnerPrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + + if (weakSelf) + { + typeof(self) self = weakSelf; + self->currentAlert = nil; + } + + }]]; + + if (weakSelf) + { + typeof(self) self = weakSelf; + [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; + self->currentAlert = isLastOwnerPrompt; + } + } + else + { + NSString *title, *message; + if ([weakSelf.mainSession roomWithRoomId:currentRoomId].isDirect) + { + title = [VectorL10n roomParticipantsLeavePromptTitleForDm]; + message = [VectorL10n roomParticipantsLeavePromptMsgForDm]; + } + else + { + title = [VectorL10n roomParticipantsLeavePromptTitle]; + message = [VectorL10n roomParticipantsLeavePromptMsg]; + } + + // confirm leave + UIAlertController *leavePrompt = [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + [leavePrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + + if (weakSelf) + { + typeof(self) self = weakSelf; + self->currentAlert = nil; + } + + }]]; + + [leavePrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n leave] + style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + if (weakSelf) + { + typeof(self) self = weakSelf; + self->currentAlert = nil; + + // Check whether the user didn't leave the room yet + // TODO: Handle multi-account + if (weakRoom) + { + [self startActivityIndicatorWithLabel:[VectorL10n roomParticipantsLeaveProcessing]]; + // cancel pending uploads/downloads + // they are useless by now + [MXMediaManager cancelDownloadsInCacheFolder:weakRoom.roomId]; + + // TODO GFO cancel pending uploads related to this room + + MXLogDebug(@"[RecentsViewController] Leave room (%@)", weakRoom.roomId); + + [weakRoom leave:^{ + + if (weakSelf) + { + typeof(self) self = weakSelf; + [self stopActivityIndicator]; + [self.userIndicatorStore presentSuccessWithLabel:[VectorL10n roomParticipantsLeaveSuccess]]; + // Force table refresh + [self cancelEditionMode:YES]; + } + + } failure:^(NSError *error) { + + MXLogDebug(@"[RecentsViewController] Failed to leave room"); + if (weakSelf) + { + typeof(self) self = weakSelf; + // Notify the end user + NSString *userId = room.mxSession.myUser.userId; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification + object:error + userInfo:userId ? @{kMXKErrorUserIdKey: userId} : nil]; + + [self stopActivityIndicator]; + + // Leave editing mode + [self cancelEditionMode:self->isRefreshPending]; + } + + }]; + } + else + { + // Leave editing mode + [self cancelEditionMode:self->isRefreshPending]; + } + } + + }]]; + [leavePrompt mxk_setAccessibilityIdentifier:@"LeaveEditedRoomAlert"]; + if (weakSelf) + { + typeof(self) self = weakSelf; + [self presentViewController:leavePrompt animated:YES completion:nil]; + self->currentAlert = leavePrompt; + } + } + }]; } } diff --git a/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift b/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift index dfb8de6ae..b40cabfa8 100644 --- a/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift +++ b/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift @@ -132,19 +132,32 @@ class RoomContextActionService: NSObject, RoomContextActionServiceProtocol { func leaveRoom(promptUser: Bool) { guard promptUser else { + // Only used for declining an invite self.leaveRoom() return } - let title = room.isDirect ? VectorL10n.roomParticipantsLeavePromptTitleForDm : VectorL10n.roomParticipantsLeavePromptTitle - let message = room.isDirect ? VectorL10n.roomParticipantsLeavePromptMsgForDm : VectorL10n.roomParticipantsLeavePromptMsg - - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: nil)) - alertController.addAction(UIAlertAction(title: VectorL10n.leave, style: .default, handler: { action in - self.leaveRoom() - })) - self.delegate?.roomContextActionService(self, presentAlert: alertController) + Task { + if try await room.isLastOwner() { + let alertController = await UIAlertController(title: VectorL10n.error, message: VectorL10n.roomParticipantsLeaveNotAllowedForLastOwnerMsg, preferredStyle: .alert) + await alertController.addAction(UIAlertAction(title: VectorL10n.ok, style: .cancel, handler: nil)) + await MainActor.run { + self.delegate?.roomContextActionService(self, presentAlert: alertController) + } + } else { + let title = room.isDirect ? VectorL10n.roomParticipantsLeavePromptTitleForDm : VectorL10n.roomParticipantsLeavePromptTitle + let message = room.isDirect ? VectorL10n.roomParticipantsLeavePromptMsgForDm : VectorL10n.roomParticipantsLeavePromptMsg + + let alertController = await UIAlertController(title: title, message: message, preferredStyle: .alert) + await alertController.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: nil)) + await alertController.addAction(UIAlertAction(title: VectorL10n.leave, style: .default, handler: { action in + self.leaveRoom() + })) + await MainActor.run { + self.delegate?.roomContextActionService(self, presentAlert: alertController) + } + } + } } func joinRoom() { From 17ad5c1cbbc9e7158f4aec52557276d888d1db7f Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 24 Jul 2025 19:23:09 +0200 Subject: [PATCH 45/61] added the alert in objc --- .../Common/Recents/RecentsViewController.m | 12 +- .../MXKRoomMemberDetailsViewController.m | 63 ++++++-- .../Members/RoomParticipantsViewController.m | 140 +++++++++++------- 3 files changed, 141 insertions(+), 74 deletions(-) diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 98fe7dd63..fca8a1300 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -1144,8 +1144,10 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro if (weakSelf) { typeof(self) self = weakSelf; - [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; - self->currentAlert = isLastOwnerPrompt; + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; + self->currentAlert = isLastOwnerPrompt; + }); } } else @@ -1243,8 +1245,10 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro if (weakSelf) { typeof(self) self = weakSelf; - [self presentViewController:leavePrompt animated:YES completion:nil]; - self->currentAlert = leavePrompt; + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:leavePrompt animated:YES completion:nil]; + self->currentAlert = leavePrompt; + }); } } }]; diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m index 39bb1854c..908a3e72c 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m @@ -220,20 +220,55 @@ Please see LICENSE in the repository root for full details. } case MXKRoomMemberDetailsActionLeave: { - [self addPendingActionMask]; - [self.mxRoom leave:^{ - - [self removePendingActionMask]; - [self withdrawViewControllerAnimated:YES completion:nil]; - - } failure:^(NSError *error) { - - [self removePendingActionMask]; - MXLogDebug(@"[MXKRoomMemberDetailsVC] Leave room %@ failed", self->mxRoom.roomId); - // Notify MatrixKit user - NSString *myUserId = self.mainSession.myUser.userId; - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil]; - + __weak typeof(self) weakSelf = self; + [self.mxRoom isLastOwnerWithCompletionHandler:^(BOOL isLastOwner, NSError* error){ + if (isLastOwner) + { + UIAlertController *isLastOwnerPrompt = [UIAlertController alertControllerWithTitle:[VectorL10n error] + message:[VectorL10n roomParticipantsLeaveNotAllowedForLastOwnerMsg] + preferredStyle:UIAlertControllerStyleAlert]; + + [isLastOwnerPrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + if (weakSelf) + { + typeof(self) self = weakSelf; + self->currentAlert = nil; + } + }]]; + + if (weakSelf) + { + typeof(self) self = weakSelf; + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; + self->currentAlert = isLastOwnerPrompt; + }); + } + } + else + { + if (weakSelf) + { + typeof(self) self = weakSelf; + [self addPendingActionMask]; + [self.mxRoom leave:^{ + + [self removePendingActionMask]; + [self withdrawViewControllerAnimated:YES completion:nil]; + + } failure:^(NSError *error) { + + [self removePendingActionMask]; + MXLogDebug(@"[MXKRoomMemberDetailsVC] Leave room %@ failed", self->mxRoom.roomId); + // Notify MatrixKit user + NSString *myUserId = self.mainSession.myUser.userId; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil]; + + }]; + } + } }]; break; } diff --git a/Riot/Modules/Room/Members/RoomParticipantsViewController.m b/Riot/Modules/Room/Members/RoomParticipantsViewController.m index 6ec3b8e7c..392211da1 100644 --- a/Riot/Modules/Room/Members/RoomParticipantsViewController.m +++ b/Riot/Modules/Room/Members/RoomParticipantsViewController.m @@ -1231,62 +1231,7 @@ Please see LICENSE in the repository root for full details. if (section == participantsSection && userParticipant && (0 == row) && !currentSearchText.length) { - // Leave ? - MXWeakify(self); - - NSString *title, *message; - if (self.mxRoom.isDirect) - { - title = [VectorL10n roomParticipantsLeavePromptTitleForDm]; - message = [VectorL10n roomParticipantsLeavePromptMsgForDm]; - } - else - { - title = [VectorL10n roomParticipantsLeavePromptTitle]; - message = [VectorL10n roomParticipantsLeavePromptMsg]; - } - - currentAlert = [UIAlertController alertControllerWithTitle:title - message:message - preferredStyle:UIAlertControllerStyleAlert]; - - [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] - style:UIAlertActionStyleCancel - handler:^(UIAlertAction * action) { - - MXStrongifyAndReturnIfNil(self); - self->currentAlert = nil; - - }]]; - - [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n leave] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - - MXStrongifyAndReturnIfNil(self); - self->currentAlert = nil; - - [self addPendingActionMask]; - MXWeakify(self); - [self.mxRoom leave:^{ - - MXStrongifyAndReturnIfNil(self); - [self withdrawViewControllerAnimated:YES completion:nil]; - - } failure:^(NSError *error) { - - MXStrongifyAndReturnIfNil(self); - [self removePendingActionMask]; - MXLogDebug(@"[RoomParticipantsVC] Leave room %@ failed", self.mxRoom.roomId); - // Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; - - }]; - - }]]; - - [currentAlert mxk_setAccessibilityIdentifier:@"RoomParticipantsVCLeaveAlert"]; - [self presentViewController:currentAlert animated:YES completion:nil]; + [self leaveRoom]; } else { @@ -1433,6 +1378,89 @@ Please see LICENSE in the repository root for full details. } } +- (void)leaveRoom { + MXWeakify(self); + + [self.mxRoom isLastOwnerWithCompletionHandler:^(BOOL isLastOnwer, NSError* error) { + if (isLastOnwer) + { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n error] + message:[VectorL10n roomParticipantsLeaveNotAllowedForLastOwnerMsg] + preferredStyle:UIAlertControllerStyleAlert]; + + [self->currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + }]]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:self->currentAlert animated:YES completion:nil]; + }); + } + else + { + // Leave ? + MXStrongifyAndReturnIfNil(self); + NSString *title, *message; + if (self.mxRoom.isDirect) + { + title = [VectorL10n roomParticipantsLeavePromptTitleForDm]; + message = [VectorL10n roomParticipantsLeavePromptMsgForDm]; + } + else + { + title = [VectorL10n roomParticipantsLeavePromptTitle]; + message = [VectorL10n roomParticipantsLeavePromptMsg]; + } + + self->currentAlert = [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + [self->currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + + }]]; + + [self->currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n leave] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + + [self addPendingActionMask]; + MXWeakify(self); + [self.mxRoom leave:^{ + + MXStrongifyAndReturnIfNil(self); + [self withdrawViewControllerAnimated:YES completion:nil]; + + } failure:^(NSError *error) { + + MXStrongifyAndReturnIfNil(self); + [self removePendingActionMask]; + MXLogDebug(@"[RoomParticipantsVC] Leave room %@ failed", self.mxRoom.roomId); + // Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + + }]; + + }]]; + + [self->currentAlert mxk_setAccessibilityIdentifier:@"RoomParticipantsVCLeaveAlert"]; + [self presentViewController:self->currentAlert animated:YES completion:nil]; + } + }]; +} + - (void)onCancel:(id)sender { [self withdrawViewControllerAnimated:YES completion:nil]; From d664d7f68e1ef60548a4299995492018c8b1d082 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 24 Jul 2025 19:25:18 +0200 Subject: [PATCH 46/61] removed unused leave room function --- Riot/Modules/Room/RoomViewController.m | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 5ba46c9c2..fbe71630c 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -2624,23 +2624,6 @@ static CGSize kThreadListBarButtonItemImageSize; } } -- (void)leaveRoom -{ - [self startActivityIndicator]; - - [self.roomDataSource.room leave:^{ - - [self stopActivityIndicator]; - [self notifyDelegateOnLeaveRoomIfNecessary]; - - } failure:^(NSError *error) { - - [self stopActivityIndicator]; - MXLogDebug(@"[RoomVC] Failed to reject an invited room (%@) failed", self.roomDataSource.room.roomId); - - }]; -} - - (void)notifyDelegateOnLeaveRoomIfNecessary { if (isRoomLeft) { return; From dbe5cc61f881b0aac8f621c4b917c9ae5ab1a73d Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 24 Jul 2025 19:32:28 +0200 Subject: [PATCH 47/61] changelog --- changelog.d/7951.change | 1 + changelog.d/7952.change | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog.d/7951.change create mode 100644 changelog.d/7952.change diff --git a/changelog.d/7951.change b/changelog.d/7951.change new file mode 100644 index 000000000..d1c32d168 --- /dev/null +++ b/changelog.d/7951.change @@ -0,0 +1 @@ +PL 150 users will be displayed as Owners. \ No newline at end of file diff --git a/changelog.d/7952.change b/changelog.d/7952.change new file mode 100644 index 000000000..a302c6481 --- /dev/null +++ b/changelog.d/7952.change @@ -0,0 +1 @@ +Owners can't leave the room if they are the last owners while also not being the last member. \ No newline at end of file From ed921ea1011516157ed36fecd5b751f0493b127e Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 25 Jul 2025 11:19:46 +0200 Subject: [PATCH 48/61] check improved also for admins --- Riot/Categories/MXRoom.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Riot/Categories/MXRoom.swift b/Riot/Categories/MXRoom.swift index 02919c0a0..50fc18f8f 100644 --- a/Riot/Categories/MXRoom.swift +++ b/Riot/Categories/MXRoom.swift @@ -12,7 +12,9 @@ extension MXRoom { let userID = mxSession.myUserId let state = try await state() - guard RoomPowerLevelHelper.roomPowerLevel(from: state.powerLevelOfUser(withUserID: userID)) == .owner else { + let requiredPowerLevel: RoomPowerLevel = state.isMSC4289Supported() ? .owner : .admin + + guard state.powerLevelOfUser(withUserID: userID) >= requiredPowerLevel.rawValue else { return false } @@ -23,8 +25,8 @@ extension MXRoom { var isLastMember = true for member in joinedMembers where member.userId != userID { isLastMember = false - // If there are other owners they can leave - if RoomPowerLevelHelper.roomPowerLevel(from: state.powerLevelOfUser(withUserID: member.userId)) == .owner { + // If there are other owners/admins the user can leave + if state.powerLevelOfUser(withUserID: member.userId) >= requiredPowerLevel.rawValue { return false } } From bbe76e397d017b5c238ac5c1c784c7841e0eb2a0 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 25 Jul 2025 11:50:32 +0200 Subject: [PATCH 49/61] update the SDK --- matrix-ios-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-ios-sdk b/matrix-ios-sdk index d1fe456f9..b0f967c9c 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit d1fe456f97b3f3f390d928b7e66fe4ff914039fe +Subproject commit b0f967c9c884e1a24d037f516f40a5ffb6c29586 From 18a0a1de6542e8fe7c9a09c2c1c9ec39e1fabcf0 Mon Sep 17 00:00:00 2001 From: Mauro <34335419+Velin92@users.noreply.github.com> Date: Fri, 25 Jul 2025 12:03:15 +0200 Subject: [PATCH 50/61] Apply suggestions from code review Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> --- Riot/Categories/MXRoom.swift | 10 ++-------- .../Room/Members/RoomParticipantsViewController.m | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Riot/Categories/MXRoom.swift b/Riot/Categories/MXRoom.swift index 50fc18f8f..5446972e2 100644 --- a/Riot/Categories/MXRoom.swift +++ b/Riot/Categories/MXRoom.swift @@ -22,14 +22,8 @@ extension MXRoom { return false } - var isLastMember = true - for member in joinedMembers where member.userId != userID { - isLastMember = false - // If there are other owners/admins the user can leave - if state.powerLevelOfUser(withUserID: member.userId) >= requiredPowerLevel.rawValue { - return false - } + return joinedMembers.contains { member in + member.userId != userID && state.powerLevelOfUser(withUserID: member.userId) >= requiredPowerLevel.rawValue } - return !isLastMember } } diff --git a/Riot/Modules/Room/Members/RoomParticipantsViewController.m b/Riot/Modules/Room/Members/RoomParticipantsViewController.m index 392211da1..41a105508 100644 --- a/Riot/Modules/Room/Members/RoomParticipantsViewController.m +++ b/Riot/Modules/Room/Members/RoomParticipantsViewController.m @@ -1382,7 +1382,7 @@ Please see LICENSE in the repository root for full details. MXWeakify(self); [self.mxRoom isLastOwnerWithCompletionHandler:^(BOOL isLastOnwer, NSError* error) { - if (isLastOnwer) + if (isLastOwner) { MXStrongifyAndReturnIfNil(self); self->currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n error] From e6842a787a67f59fb8f6dce6e422b87a52bf5945 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 25 Jul 2025 12:28:39 +0200 Subject: [PATCH 51/61] pr suggestions --- Riot/Categories/MXRoom.swift | 11 +++- .../Services/RoomContextActionService.swift | 15 +++-- .../MXKRoomMemberDetailsViewController.m | 57 ++++++++----------- .../Members/RoomParticipantsViewController.m | 2 +- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/Riot/Categories/MXRoom.swift b/Riot/Categories/MXRoom.swift index 5446972e2..1ff03e03a 100644 --- a/Riot/Categories/MXRoom.swift +++ b/Riot/Categories/MXRoom.swift @@ -22,8 +22,15 @@ extension MXRoom { return false } - return joinedMembers.contains { member in - member.userId != userID && state.powerLevelOfUser(withUserID: member.userId) >= requiredPowerLevel.rawValue + var areOtherMembers = false + for member in joinedMembers where member.userId != userID { + // User is not the last member in the whole room. + areOtherMembers = true + // If there are other owners/admins the user can leave + if state.powerLevelOfUser(withUserID: member.userId) >= requiredPowerLevel.rawValue { + return false + } } + return areOtherMembers } } diff --git a/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift b/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift index b40cabfa8..fcf0e5d57 100644 --- a/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift +++ b/Riot/Modules/ContextMenu/Services/RoomContextActionService.swift @@ -139,21 +139,20 @@ class RoomContextActionService: NSObject, RoomContextActionServiceProtocol { Task { if try await room.isLastOwner() { - let alertController = await UIAlertController(title: VectorL10n.error, message: VectorL10n.roomParticipantsLeaveNotAllowedForLastOwnerMsg, preferredStyle: .alert) - await alertController.addAction(UIAlertAction(title: VectorL10n.ok, style: .cancel, handler: nil)) await MainActor.run { + let alertController = UIAlertController(title: VectorL10n.error, message: VectorL10n.roomParticipantsLeaveNotAllowedForLastOwnerMsg, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: VectorL10n.ok, style: .cancel, handler: nil)) self.delegate?.roomContextActionService(self, presentAlert: alertController) } } else { let title = room.isDirect ? VectorL10n.roomParticipantsLeavePromptTitleForDm : VectorL10n.roomParticipantsLeavePromptTitle let message = room.isDirect ? VectorL10n.roomParticipantsLeavePromptMsgForDm : VectorL10n.roomParticipantsLeavePromptMsg - - let alertController = await UIAlertController(title: title, message: message, preferredStyle: .alert) - await alertController.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: nil)) - await alertController.addAction(UIAlertAction(title: VectorL10n.leave, style: .default, handler: { action in - self.leaveRoom() - })) await MainActor.run { + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: nil)) + alertController.addAction(UIAlertAction(title: VectorL10n.leave, style: .default, handler: { [weak self] action in + self?.leaveRoom() + })) self.delegate?.roomContextActionService(self, presentAlert: alertController) } } diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m index 908a3e72c..c8cef3e34 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m @@ -220,7 +220,7 @@ Please see LICENSE in the repository root for full details. } case MXKRoomMemberDetailsActionLeave: { - __weak typeof(self) weakSelf = self; + MXWeakify(self); [self.mxRoom isLastOwnerWithCompletionHandler:^(BOOL isLastOwner, NSError* error){ if (isLastOwner) { @@ -231,43 +231,34 @@ Please see LICENSE in the repository root for full details. [isLastOwnerPrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - } + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; }]]; - if (weakSelf) - { - typeof(self) self = weakSelf; - dispatch_async(dispatch_get_main_queue(), ^{ - [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; - self->currentAlert = isLastOwnerPrompt; - }); - } + MXStrongifyAndReturnIfNil(self); + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; + self->currentAlert = isLastOwnerPrompt; + }); } else { - if (weakSelf) - { - typeof(self) self = weakSelf; - [self addPendingActionMask]; - [self.mxRoom leave:^{ - - [self removePendingActionMask]; - [self withdrawViewControllerAnimated:YES completion:nil]; - - } failure:^(NSError *error) { - - [self removePendingActionMask]; - MXLogDebug(@"[MXKRoomMemberDetailsVC] Leave room %@ failed", self->mxRoom.roomId); - // Notify MatrixKit user - NSString *myUserId = self.mainSession.myUser.userId; - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil]; - - }]; - } + MXStrongifyAndReturnIfNil(self); + [self addPendingActionMask]; + [self.mxRoom leave:^{ + + [self removePendingActionMask]; + [self withdrawViewControllerAnimated:YES completion:nil]; + + } failure:^(NSError *error) { + + [self removePendingActionMask]; + MXLogDebug(@"[MXKRoomMemberDetailsVC] Leave room %@ failed", self->mxRoom.roomId); + // Notify MatrixKit user + NSString *myUserId = self.mainSession.myUser.userId; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil]; + + }]; } }]; break; diff --git a/Riot/Modules/Room/Members/RoomParticipantsViewController.m b/Riot/Modules/Room/Members/RoomParticipantsViewController.m index 41a105508..b0a4188fc 100644 --- a/Riot/Modules/Room/Members/RoomParticipantsViewController.m +++ b/Riot/Modules/Room/Members/RoomParticipantsViewController.m @@ -1381,7 +1381,7 @@ Please see LICENSE in the repository root for full details. - (void)leaveRoom { MXWeakify(self); - [self.mxRoom isLastOwnerWithCompletionHandler:^(BOOL isLastOnwer, NSError* error) { + [self.mxRoom isLastOwnerWithCompletionHandler:^(BOOL isLastOwner, NSError* error) { if (isLastOwner) { MXStrongifyAndReturnIfNil(self); From 68b6ea9409fc0f5be938bdadf134d29f496d153e Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 25 Jul 2025 12:54:42 +0200 Subject: [PATCH 52/61] using wekify and strongify macros --- .../Common/Recents/RecentsViewController.m | 141 +++++++----------- .../MXKRoomMemberDetailsViewController.m | 5 +- .../Members/RoomParticipantsViewController.m | 1 + 3 files changed, 62 insertions(+), 85 deletions(-) diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index fca8a1300..211ebe8ba 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -1118,42 +1118,34 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro if (editedRoomId) { NSString *currentRoomId = editedRoomId; - __weak typeof(self) weakSelf = self; - + MXWeakify(self); MXRoom *room = [self.mainSession roomWithRoomId:currentRoomId]; __weak typeof(room) weakRoom = room; [room isLastOwnerWithCompletionHandler:^(BOOL isLastOwner, NSError* error){ if (isLastOwner) { UIAlertController *isLastOwnerPrompt = [UIAlertController alertControllerWithTitle:[VectorL10n error] - message:[VectorL10n roomParticipantsLeaveNotAllowedForLastOwnerMsg] - preferredStyle:UIAlertControllerStyleAlert]; + message:[VectorL10n roomParticipantsLeaveNotAllowedForLastOwnerMsg] + preferredStyle:UIAlertControllerStyleAlert]; [isLastOwnerPrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] - style:UIAlertActionStyleCancel - handler:^(UIAlertAction * action) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - } - + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; }]]; - if (weakSelf) - { - typeof(self) self = weakSelf; - dispatch_async(dispatch_get_main_queue(), ^{ - [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; - self->currentAlert = isLastOwnerPrompt; - }); - } + MXStrongifyAndReturnIfNil(self); + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:isLastOwnerPrompt animated:YES completion:nil]; + self->currentAlert = isLastOwnerPrompt; + }); } else { NSString *title, *message; - if ([weakSelf.mainSession roomWithRoomId:currentRoomId].isDirect) + MXStrongifyAndReturnIfNil(self); + if ([self.mainSession roomWithRoomId:currentRoomId].isDirect) { title = [VectorL10n roomParticipantsLeavePromptTitleForDm]; message = [VectorL10n roomParticipantsLeavePromptMsgForDm]; @@ -1169,87 +1161,70 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro message:message preferredStyle:UIAlertControllerStyleAlert]; + MXWeakify(self); [leavePrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - } - + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; }]]; [leavePrompt addAction:[UIAlertAction actionWithTitle:[VectorL10n leave] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; - if (weakSelf) + // Check whether the user didn't leave the room yet + // TODO: Handle multi-account + if (weakRoom) { - typeof(self) self = weakSelf; - self->currentAlert = nil; + [self startActivityIndicatorWithLabel:[VectorL10n roomParticipantsLeaveProcessing]]; + // cancel pending uploads/downloads + // they are useless by now + [MXMediaManager cancelDownloadsInCacheFolder:weakRoom.roomId]; - // Check whether the user didn't leave the room yet - // TODO: Handle multi-account - if (weakRoom) - { - [self startActivityIndicatorWithLabel:[VectorL10n roomParticipantsLeaveProcessing]]; - // cancel pending uploads/downloads - // they are useless by now - [MXMediaManager cancelDownloadsInCacheFolder:weakRoom.roomId]; + // TODO GFO cancel pending uploads related to this room + + MXLogDebug(@"[RecentsViewController] Leave room (%@)", weakRoom.roomId); + + MXWeakify(self); + [weakRoom leave:^{ + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + [self.userIndicatorStore presentSuccessWithLabel:[VectorL10n roomParticipantsLeaveSuccess]]; + // Force table refresh + [self cancelEditionMode:YES]; - // TODO GFO cancel pending uploads related to this room + } failure:^(NSError *error) { - MXLogDebug(@"[RecentsViewController] Leave room (%@)", weakRoom.roomId); + MXLogDebug(@"[RecentsViewController] Failed to leave room"); + MXStrongifyAndReturnIfNil(self); + // Notify the end user + NSString *userId = room.mxSession.myUser.userId; + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification + object:error + userInfo:userId ? @{kMXKErrorUserIdKey: userId} : nil]; + + [self stopActivityIndicator]; - [weakRoom leave:^{ - - if (weakSelf) - { - typeof(self) self = weakSelf; - [self stopActivityIndicator]; - [self.userIndicatorStore presentSuccessWithLabel:[VectorL10n roomParticipantsLeaveSuccess]]; - // Force table refresh - [self cancelEditionMode:YES]; - } - - } failure:^(NSError *error) { - - MXLogDebug(@"[RecentsViewController] Failed to leave room"); - if (weakSelf) - { - typeof(self) self = weakSelf; - // Notify the end user - NSString *userId = room.mxSession.myUser.userId; - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification - object:error - userInfo:userId ? @{kMXKErrorUserIdKey: userId} : nil]; - - [self stopActivityIndicator]; - - // Leave editing mode - [self cancelEditionMode:self->isRefreshPending]; - } - - }]; - } - else - { // Leave editing mode [self cancelEditionMode:self->isRefreshPending]; - } + + }]; + } + else + { + // Leave editing mode + [self cancelEditionMode:self->isRefreshPending]; } }]]; [leavePrompt mxk_setAccessibilityIdentifier:@"LeaveEditedRoomAlert"]; - if (weakSelf) - { - typeof(self) self = weakSelf; - dispatch_async(dispatch_get_main_queue(), ^{ - [self presentViewController:leavePrompt animated:YES completion:nil]; - self->currentAlert = leavePrompt; - }); - } + dispatch_async(dispatch_get_main_queue(), ^{ + [self presentViewController:leavePrompt animated:YES completion:nil]; + self->currentAlert = leavePrompt; + }); } }]; } diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m index c8cef3e34..968db509a 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.m @@ -245,13 +245,14 @@ Please see LICENSE in the repository root for full details. { MXStrongifyAndReturnIfNil(self); [self addPendingActionMask]; + MXWeakify(self); [self.mxRoom leave:^{ - + MXStrongifyAndReturnIfNil(self); [self removePendingActionMask]; [self withdrawViewControllerAnimated:YES completion:nil]; } failure:^(NSError *error) { - + MXStrongifyAndReturnIfNil(self); [self removePendingActionMask]; MXLogDebug(@"[MXKRoomMemberDetailsVC] Leave room %@ failed", self->mxRoom.roomId); // Notify MatrixKit user diff --git a/Riot/Modules/Room/Members/RoomParticipantsViewController.m b/Riot/Modules/Room/Members/RoomParticipantsViewController.m index b0a4188fc..b3e1a596d 100644 --- a/Riot/Modules/Room/Members/RoomParticipantsViewController.m +++ b/Riot/Modules/Room/Members/RoomParticipantsViewController.m @@ -1420,6 +1420,7 @@ Please see LICENSE in the repository root for full details. message:message preferredStyle:UIAlertControllerStyleAlert]; + MXWeakify(self); [self->currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { From fc7d72e8d6a6c39bcf207c2259b2dd0b09a56bfa Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Mon, 28 Jul 2025 11:00:38 +0200 Subject: [PATCH 53/61] use mint to run xcodegen 2.39.0 --- .github/workflows/ci-tests.yml | 3 +++ .github/workflows/ci-ui-tests.yml | 3 +++ Brewfile | 1 - RiotSwiftUI/targetUnitTests.yml | 1 - RiotTests/target.yml | 1 - 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index b3c8f6bac..1f667ead5 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -56,6 +56,9 @@ jobs: run: | bundle config path vendor/bundle bundle install --jobs 4 --retry 3 + + - name: Xcodegen + run: mint run yonaskolb/XcodeGen@2.39.0 # Main step - name: Unit tests diff --git a/.github/workflows/ci-ui-tests.yml b/.github/workflows/ci-ui-tests.yml index 06e117687..1e9ccf56a 100644 --- a/.github/workflows/ci-ui-tests.yml +++ b/.github/workflows/ci-ui-tests.yml @@ -51,6 +51,9 @@ jobs: run: | bundle config path vendor/bundle bundle install --jobs 4 --retry 3 + + - name: Xcodegen + run: mint run yonaskolb/XcodeGen@2.39.0 # Main step - name: UI tests diff --git a/Brewfile b/Brewfile index e7b7707b9..c1b2289ee 100644 --- a/Brewfile +++ b/Brewfile @@ -1,3 +1,2 @@ -brew "xcodegen" brew "mint" brew "getsentry/tools/sentry-cli" diff --git a/RiotSwiftUI/targetUnitTests.yml b/RiotSwiftUI/targetUnitTests.yml index ec16e078a..5debda940 100644 --- a/RiotSwiftUI/targetUnitTests.yml +++ b/RiotSwiftUI/targetUnitTests.yml @@ -49,7 +49,6 @@ targets: PRODUCT_BUNDLE_IDENTIFIER: org.matrix.$(PRODUCT_NAME:rfc1034identifier) PRODUCT_NAME: RiotSwiftUnitTests configs: - Debug: Release: PROVISIONING_PROFILE: $(RIOT_PROVISIONING_PROFILE) PROVISIONING_PROFILE_SPECIFIER: $(RIOT_PROVISIONING_PROFILE_SPECIFIER) diff --git a/RiotTests/target.yml b/RiotTests/target.yml index dccdda9c0..ba7c9f7ae 100644 --- a/RiotTests/target.yml +++ b/RiotTests/target.yml @@ -52,7 +52,6 @@ targets: SWIFT_OBJC_BRIDGING_HEADER: RiotTests/RiotTests-Bridging-Header.h TEST_HOST: $(BUILT_PRODUCTS_DIR)/Element.app/Element configs: - Debug: Release: PROVISIONING_PROFILE: $(RIOT_PROVISIONING_PROFILE) PROVISIONING_PROFILE_SPECIFIER: $(RIOT_PROVISIONING_PROFILE_SPECIFIER) From 4d79ce24ef869b2aac4e12d9e623a2fc019b1b29 Mon Sep 17 00:00:00 2001 From: Vasiliy Taranov Date: Sun, 22 Jun 2025 10:29:42 +0000 Subject: [PATCH 54/61] Translated using Weblate (Russian) Currently translated at 99.0% (2404 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ru/ --- Riot/Assets/ru.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/ru.lproj/Vector.strings b/Riot/Assets/ru.lproj/Vector.strings index d8ff3cf4b..d9ca5af43 100644 --- a/Riot/Assets/ru.lproj/Vector.strings +++ b/Riot/Assets/ru.lproj/Vector.strings @@ -2124,7 +2124,7 @@ "onboarding_use_case_existing_server_message" = "Хотите присоединиться к существующему серверу?"; "onboarding_use_case_skip_button" = "Пропустить вопрос"; /* The placeholder string contains onboarding_use_case_skip_button as a tappable action */ -"onboarding_use_case_not_sure_yet" = "Ещё не уверенны? %@"; +"onboarding_use_case_not_sure_yet" = "Ещё не уверены? %@"; "onboarding_use_case_community_messaging" = "Сообщества"; "onboarding_use_case_work_messaging" = "Команды"; "onboarding_use_case_personal_messaging" = "Друзья и семья"; From 542292b64e82b1b2e261c62dedaedf441f0d5a6c Mon Sep 17 00:00:00 2001 From: Someone Date: Wed, 25 Jun 2025 06:11:30 +0000 Subject: [PATCH 55/61] Translated using Weblate (Vietnamese) Currently translated at 63.8% (1550 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/vi/ --- Riot/Assets/vi.lproj/Vector.strings | 53 ++++++++++++++++++----------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/Riot/Assets/vi.lproj/Vector.strings b/Riot/Assets/vi.lproj/Vector.strings index dd731de4d..52cbc29e2 100644 --- a/Riot/Assets/vi.lproj/Vector.strings +++ b/Riot/Assets/vi.lproj/Vector.strings @@ -37,14 +37,14 @@ "auth_register" = "Đăng kí"; "auth_submit" = "Gửi đi"; "auth_skip" = "Bỏ qua"; -"auth_send_reset_email" = "Gửi email đặt lại"; +"auth_send_reset_email" = "Gửi thư đặt lại"; "auth_return_to_login" = "Trở về trang đăng kí"; -"auth_user_id_placeholder" = "Email hoặc tên đăng nhập"; +"auth_user_id_placeholder" = "Địa chỉ thư điện tử hoặc tên đăng nhập"; "auth_password_placeholder" = "Mật khẩu"; "auth_new_password_placeholder" = "Mật khẩu mới"; "auth_user_name_placeholder" = "Tên đăng nhập"; -"auth_optional_email_placeholder" = "Địa chỉ email (không bắt buộc)"; -"auth_email_placeholder" = "Địa chỉ email"; +"auth_optional_email_placeholder" = "Địa chỉ thư điện tử (không bắt buộc)"; +"auth_email_placeholder" = "Địa chỉ thư điện tử"; "auth_optional_phone_placeholder" = "Số điện thoại (không bắt buộc)"; "auth_phone_placeholder" = "Số điện thoại"; "auth_repeat_password_placeholder" = "Nhật lại mật khẩu"; @@ -55,38 +55,38 @@ "warning" = "Cảnh báo"; "auth_invalid_user_name" = "Tên đăng nhập chỉ được chứa các chữ cái, dấu chấm, dấu gạch ngang và dấu gạch dưới"; "auth_invalid_password" = "Mật khẩu quá ngắn (tối thiểu 6 kí tự)"; -"auth_invalid_email" = "Địa chỉ Email không hợp lệ"; +"auth_invalid_email" = "Địa chỉ Địa thư điện tử không hợp lệ"; "auth_invalid_phone" = "Số điện thoại không hợp lệ"; "auth_missing_password" = "Thiếu mật khẩu"; "auth_add_email_message" = "Thêm địa chỉ email vào tài khoản để người dùng khác có thể tìm thấy bạn và giúp bạn thay đổi mật khẩu về sau."; "auth_add_phone_message" = "Thêm số điện thoại vào tài khoản của bạn để giúp người dùng khác có thể tìm thấy bạn."; "auth_add_email_phone_message" = "Thêm địa chỉ email hoặc số điện thoại vào tài khoản để người dùng khác có thể tìm thấy bạn. Địa chỉ email cũng sẽ giúp bạn thay đổi mật khẩu về sau."; "auth_add_email_and_phone_message" = "Thêm địa chỉ email hoặc số điện thoại vào tài khoản để người dùng khác có thể tìm thấy bạn. Địa chỉ email cũng sẽ giúp bạn thay đổi mật khẩu về sau."; -"auth_missing_email" = "Thiếu địa chỉ email"; +"auth_missing_email" = "Thiếu địa chỉ thư điện tử"; "auth_missing_phone" = "Thiếu số điện thoại"; -"auth_missing_email_or_phone" = "Thiếu địa chỉ email hoặc số điện thoại"; -"auth_email_in_use" = "Địa chỉ email này đã được sử dụng"; +"auth_missing_email_or_phone" = "Thiếu địa chỉ thư điện tử hoặc số điện thoại"; +"auth_email_in_use" = "Địa chỉ thư điện tử này đã được sử dụng"; "auth_phone_in_use" = "Số điện thoại này đã được sử dụng"; "auth_untrusted_id_server" = "Máy chủ xác thực không được tin cậy"; "auth_password_dont_match" = "Mật khẩu không trùng khớp"; "auth_username_in_use" = "Tên đăng nhập đang được sử dụng"; "auth_forgot_password" = "Quên mật khẩu danh khoản Matrix?"; -"auth_email_not_found" = "Gửi email thất bại: Địa chỉ email này không thể tìm thấy"; +"auth_email_not_found" = "Gửi thư thất bại: Địa chỉ thư điện tử này không thể tìm thấy"; "auth_use_server_options" = "Sử dụng tùy chọn máy chủ tuỳ chỉnh (nâng cao)"; -"auth_email_validation_message" = "Vui lòng kiểm tra email của bẹn để tiếp tục đăng kí"; +"auth_email_validation_message" = "Vui lòng kiểm tra hòm thư của bẹn để tiếp tục đăng ký"; "auth_msisdn_validation_title" = "Xác minh đang chờ xử lí"; "auth_msisdn_validation_message" = "Chúng tôi đã gửi mã kích hoạt qua SMS. Vui lòng nhập mã kích hoạt bên dưới."; "auth_msisdn_validation_error" = "Không thể xác thực số điện thoại."; "auth_recaptcha_message" = "Home Server này muốn đảm bảo rằng bạn không phải là Robot"; -"auth_reset_password_message" = "Để thay đổi mật khẩu, nhập địa chỉ email được kết nối với tài khoản của bạn:"; -"auth_reset_password_missing_email" = "Bạn phải nhập địa chỉ email đã được kết nối với tài khoản của bạn."; +"auth_reset_password_message" = "Để thay đổi mật khẩu, nhập địa chỉ thư điện tử được kết nối với tài khoản của bạn:"; +"auth_reset_password_missing_email" = "Bạn phải nhập địa chỉ thư điện tử đã được kết nối với tài khoản của bạn."; "auth_reset_password_missing_password" = "Bạn phải nhập mật khẩu mới."; -"auth_reset_password_email_validation_message" = "Email đã được gửi tới %@. Khi bạn đã theo liên kết trong đó, bấm vào dưới đây."; -"auth_reset_password_next_step_button" = "Tôi đã xác thực địa chỉ email của tôi"; -"auth_reset_password_error_unauthorized" = "Xác thực địa chỉ email thất bại: hãy đảm bảo rằng bạn đã bấm vào địa chỉ đính kèm trong email"; -"auth_reset_password_error_not_found" = "Địa chỉ email có vẻ chưa được liên kết với Matrix ID trên homeserver này."; +"auth_reset_password_email_validation_message" = "Thư đã được gửi tới %@. Khi bạn đã theo liên kết trong đó, bấm vào dưới đây."; +"auth_reset_password_next_step_button" = "Tôi đã xác thực địa chỉ thư điện tử của tôi"; +"auth_reset_password_error_unauthorized" = "Xác thực địa chỉ thư điện tử thất bại: hãy đảm bảo rằng bạn đã bấm vào địa chỉ đính kèm trong thư"; +"auth_reset_password_error_not_found" = "Địa chỉ thư điện tử của bạn không có tài khoản trên máy chủ nhà này."; "auth_reset_password_success_message" = "Mật khẩu của bạn đã được thiết lập lại.\n\nBạn đã được đăng xuất khỏi tất cả các thiết bị và sẽ không còn nhận được thông báo. Để bật lại thông báo, đăng nhập lại trên mỗi thiết bị."; -"auth_add_email_and_phone_warning" = "Đăng kí với mật khẩu và số điện thoại cùng lúc chưa được hỗ trợ cho tới khi api được thiết lập. Duy nhất số điện thoại sẽ được liên kết với với tài khoản. Bạn sẽ phải thêm email vào hồ sơ trong mục cài đặt."; +"auth_add_email_and_phone_warning" = "Đăng ký bằng cả địa chỉ thư điện tử và số điện thoại chưa được hỗ trợ vì chưa có API. Chỉ có số điện thoại được thêm vào tài khoản của bạn. Bạn có thể thêm địa chỉ thư điện tử trong phần cài đặt hồ sơ."; // Chat creation "room_creation_title" = "Cuộc trò chuyện mới"; "room_creation_account" = "Tài khoản"; @@ -1594,10 +1594,10 @@ "auth_reset_password_error_is_required" = "Không có máy chủ xác thực nào được cấu hình: thêm một trong các tùy chọn máy chủ để đặt lại mật khẩu của bạn."; "auth_forgot_password_error_no_configured_identity_server" = "Không có máy chủ xác thực nào được cấu hình: thêm một để đặt lại mật khẩu của bạn."; "auth_phone_is_required" = "Không có máy chủ xác thực nào được cấu hình để bạn không thể thêm số điện thoại để đặt lại mật khẩu của mình trong tương lai."; -"auth_email_is_required" = "Không có máy chủ xác thực nào được cấu hình để bạn không thể thêm địa chỉ email để đặt lại mật khẩu của mình trong tương lai."; -"auth_add_email_phone_message_2" = "Đặt email để khôi phục tài khoản. Sử dụng email hoặc điện thoại sau này để được tùy chọn phát hiện bởi những người biết bạn."; +"auth_email_is_required" = "Không có máy chủ xác thực nào được cấu hình nên bạn không thể thêm địa chỉ thư điện tử để đặt lại mật khẩu của mình trong tương lai."; +"auth_add_email_phone_message_2" = "Đặt địa chỉ thư điện tử để khôi phục tài khoản. Sử dụng địa chỉ thư điện tử hoặc điện thoại sau này để được tùy chọn phát hiện bởi những người biết bạn."; "auth_add_phone_message_2" = "Đặt điện thoại và sau đó có thể tùy chọn được tìm kiếm bởi những người biết bạn."; -"auth_add_email_message_2" = "Đặt email để khôi phục tài khoản và sau đó có thể tùy chọn được tìm kiếm bởi những người biết bạn."; +"auth_add_email_message_2" = "Đặt địa chỉ thư điện tử để khôi phục tài khoản và sau đó có thể tùy chọn được tìm kiếm bởi những người biết bạn."; "auth_login_single_sign_on" = "Đăng nhập"; // Accessibility @@ -1994,3 +1994,16 @@ "onboarding_splash_register_button_title" = "Tạo danh khoản"; "accessibility_button_label" = "nút"; "enable" = "Bật"; +"authentication_choose_password_not_verified_title" = "Địa chỉ thư điện tử chưa được xác nhận"; +"authentication_verify_email_text_field_placeholder" = "Địa chỉ thư điện tử"; +"authentication_verify_email_waiting_title" = "Xác nhận địa chỉ thư điện tử của bạn."; +"authentication_forgot_password_input_title" = "Nhập địa chỉ thư điện tử"; +"authentication_forgot_password_text_field_placeholder" = "Địa chỉ thư điện tử"; +"authentication_forgot_password_waiting_button" = "Gửi lại"; +"authentication_login_username" = "Tên đăng nhập / Địa chỉ thư điện tử / Số điện thoại"; +"authentication_verify_email_input_title" = "Nhập địa chỉ thư điện tử"; +"authentication_verify_email_waiting_hint" = "Không nhận được thư?"; +"authentication_verify_email_waiting_button" = "Gửi lại"; +"authentication_verify_email_input_message" = "%@ cần xác thực tài khoản của bạn"; +"authentication_verify_email_waiting_message" = "Làm theo chỉ dẫn được gửi đến %@"; +"authentication_forgot_password_waiting_title" = "Kiểm tra hòm thư của bạn."; From 20fd4a1c85796b9d03ab56651696d35278761840 Mon Sep 17 00:00:00 2001 From: oxisol Date: Sun, 20 Jul 2025 06:42:53 +0000 Subject: [PATCH 56/61] Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 86.6% (2102 of 2427 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/zh_Hans/ --- Riot/Assets/zh_Hans.lproj/Vector.strings | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Riot/Assets/zh_Hans.lproj/Vector.strings b/Riot/Assets/zh_Hans.lproj/Vector.strings index ee805714c..ac013a687 100644 --- a/Riot/Assets/zh_Hans.lproj/Vector.strings +++ b/Riot/Assets/zh_Hans.lproj/Vector.strings @@ -1598,7 +1598,7 @@ "accessibility_button_label" = "按钮"; "enable" = "启用"; "onboarding_splash_page_1_message" = "独立安全的通信,为您提供与家中面谈相同的私密性。"; -"onboarding_splash_page_1_title" = "掌控你的对话。"; +"onboarding_splash_page_1_title" = "掌控您的对话。"; // Onboarding "onboarding_splash_register_button_title" = "注册"; @@ -2086,7 +2086,7 @@ "room_many_users_are_typing" = "%@、%@和其他人正在输入……"; /* The placeholder %1$tu will be replaced with a number and %2$@ with the user's search terms. */ "directory_search_results" = "为%2$@找到%1$tu个结果"; -"onboarding_splash_page_2_title" = "一切都在你的掌控中。"; +"onboarding_splash_page_2_title" = "一切都在您的掌控中。"; "onboarding_congratulations_personalize_button" = "个性化用户资料"; /* The placeholder string contains the user's matrix ID */ "onboarding_congratulations_message" = "你的账户%@已创建"; @@ -2101,7 +2101,7 @@ "onboarding_use_case_title" = "你会和谁聊得最多?"; "onboarding_splash_page_4_message" = "Element也很适合工作场所。受世界最安全的组织的信任。"; "onboarding_splash_page_3_message" = "端到端加密且不要求电话号码。无广告或数据挖掘。"; -"onboarding_splash_page_2_message" = "选择在哪里保存你的对话,给你控制和独立。通过Matrix连接。"; +"onboarding_splash_page_2_message" = "选择在哪里保存您的对话,给您控制和独立。通过Matrix连接。"; // MARK: Reactions @@ -2433,5 +2433,10 @@ "room_command_discard_session_description" = "强制当前已在加密房间中的外部群组会话失效"; "call_jitsi_unable_to_start" = "无法开始会议通话"; "room_suggestion_settings_screen_title" = "将房间设置为该空间中的建议房间"; -"room_suggestion_settings_screen_message" = "向空间成员推荐建议房间"; +"room_suggestion_settings_screen_message" = "向空间成员推荐建议房间。"; "key_backup_recover_from_private_key_progress" = "完成 %@%%"; +"sunset_download_banner_learn_more" = "了解更多"; +"sunset_delegated_oidc_registration_not_supported_message" = "下载 %1$@ 后才能在您的账户中使用 %2$@,或选择另一个家服务器。"; +"sunset_delegated_oidc_registration_not_supported_generic_error" = "您已无法用该家服务器在本应用中创建账户"; +"sunset_download_banner_title" = "下载 %1$@"; +"sunset_delegated_oidc_registration_not_supported_title" = "您已无法再用 %1$@ 在本应用中创建账户"; From 0e89f6f78cdda4f683996a06f86cc6cb872e088a Mon Sep 17 00:00:00 2001 From: Someone Date: Sun, 8 Jun 2025 13:47:04 +0000 Subject: [PATCH 57/61] Translated using Weblate (Vietnamese) Currently translated at 50.0% (4 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/vi/ --- Riot/Assets/vi.lproj/InfoPlist.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/vi.lproj/InfoPlist.strings b/Riot/Assets/vi.lproj/InfoPlist.strings index 41eb2f4aa..6ee4855d4 100644 --- a/Riot/Assets/vi.lproj/InfoPlist.strings +++ b/Riot/Assets/vi.lproj/InfoPlist.strings @@ -1,5 +1,5 @@ // Permissions usage explanations -"NSCameraUsageDescription" = "Máy ảnh được sử dụng để chụp ảnh và quay phim, thực hiện các cuộc gọi video."; +"NSCameraUsageDescription" = "Máy ảnh được dùng để gọi truyền hình hoặc quay phim, chụp ảnh."; "NSPhotoLibraryUsageDescription" = "Thư viện ảnh được dùng để gửi hình ảnh và videos."; "NSMicrophoneUsageDescription" = "Element cần quyền truy cập vào mi-crô của bạn để nhận và thực hiện cuộc gọi, quay video, và ghi âm các tin nhắn thoại."; "NSContactsUsageDescription" = "Element sẽ hiển thị danh bạ của bạn để bạn có thể mời họ trò chuyện."; From 31d00b55b357b2bfb00b3542a205bba9e82e2ad0 Mon Sep 17 00:00:00 2001 From: Linerly Date: Fri, 25 Jul 2025 06:40:53 +0000 Subject: [PATCH 58/61] Translated using Weblate (Indonesian) Currently translated at 100.0% (2429 of 2429 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index 5dae0ef11..fd4f779f5 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2990,3 +2990,5 @@ // MARK: Sunset "sunset_delegated_oidc_registration_not_supported_title" = "Anda sudah tidak bisa lagi membuat akun dengan %1$@ menggunakan aplikasi ini"; "sunset_delegated_oidc_registration_not_supported_generic_error" = "Anda sudah tidak bisa lagi membuat akun dengan homeserver yang ditentukan menggunakan aplikasi ini"; +"room_member_power_level_owner_in" = "Pemilik dalam %@"; +"room_member_power_level_short_owner" = "Pemilik"; From 5e88258b26e3322ee7d75a9e31419acdd99135df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Sat, 26 Jul 2025 08:06:16 +0000 Subject: [PATCH 59/61] Translated using Weblate (Estonian) Currently translated at 100.0% (2429 of 2429 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index f7c79fe3d..a562f4543 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2735,3 +2735,5 @@ // MARK: Sunset "sunset_delegated_oidc_registration_not_supported_title" = "Selle rakendusega enam ei saa luua kasutajakontot teenuses %1$@"; +"room_member_power_level_owner_in" = "„%@“ jututoa omanik"; +"room_member_power_level_short_owner" = "Omanik"; From 8fe28fb0c46f82529d00731fa2a692d328abd051 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Mon, 28 Jul 2025 15:05:18 +0200 Subject: [PATCH 60/61] version++ --- CHANGES.md | 16 ++++++++++++++++ changelog.d/7951.change | 1 - changelog.d/7952.change | 1 - changelog.d/pr-7950.feature | 1 - changelog.d/pr-7953.bugfix | 1 - 5 files changed, 16 insertions(+), 4 deletions(-) delete mode 100644 changelog.d/7951.change delete mode 100644 changelog.d/7952.change delete mode 100644 changelog.d/pr-7950.feature delete mode 100644 changelog.d/pr-7953.bugfix diff --git a/CHANGES.md b/CHANGES.md index 22b2255b0..f2b0bf418 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,19 @@ +## Changes in 1.11.31 (2025-07-28) + +✨ Features + +- Support for MSC 4289. ([#7950](https://github.com/element-hq/element-ios/pull/7950)) + +🙌 Improvements + +- PL 150 users will be displayed as Owners. ([#7951](https://github.com/element-hq/element-ios/issues/7951)) +- Owners can't leave the room if they are the last owners while also not being the last member. ([#7952](https://github.com/element-hq/element-ios/issues/7952)) + +🐛 Bugfixes + +- Room continuity fix for room version 12. ([#7953](https://github.com/element-hq/element-ios/pull/7953)) + + ## Changes in 1.11.30 (2025-06-10) No significant changes. diff --git a/changelog.d/7951.change b/changelog.d/7951.change deleted file mode 100644 index d1c32d168..000000000 --- a/changelog.d/7951.change +++ /dev/null @@ -1 +0,0 @@ -PL 150 users will be displayed as Owners. \ No newline at end of file diff --git a/changelog.d/7952.change b/changelog.d/7952.change deleted file mode 100644 index a302c6481..000000000 --- a/changelog.d/7952.change +++ /dev/null @@ -1 +0,0 @@ -Owners can't leave the room if they are the last owners while also not being the last member. \ No newline at end of file diff --git a/changelog.d/pr-7950.feature b/changelog.d/pr-7950.feature deleted file mode 100644 index b8f2018e8..000000000 --- a/changelog.d/pr-7950.feature +++ /dev/null @@ -1 +0,0 @@ -Support for MSC 4289. diff --git a/changelog.d/pr-7953.bugfix b/changelog.d/pr-7953.bugfix deleted file mode 100644 index 177893afa..000000000 --- a/changelog.d/pr-7953.bugfix +++ /dev/null @@ -1 +0,0 @@ -Room continuity fix for room version 12. \ No newline at end of file From 9757e9b519b2bec035d6e0be9bb49f511e6b7b6e Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Mon, 28 Jul 2025 15:09:55 +0200 Subject: [PATCH 61/61] finish version++