mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-17 15:09:31 +02:00
Merge branch 'release/1.11.5/master'
This commit is contained in:
21
CHANGES.md
21
CHANGES.md
@@ -1,3 +1,24 @@
|
||||
## Changes in 1.11.5 (2023-11-28)
|
||||
|
||||
🙌 Improvements
|
||||
|
||||
- Upgrade MatrixSDK version ([v0.27.4](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.27.4)).
|
||||
- Upgrade Rich Text Editor version. ([v2.18.0](https://github.com/matrix-org/matrix-rich-text-editor/releases/tag/2.18.0))
|
||||
|
||||
🐛 Bugfixes
|
||||
|
||||
- Call destroy in dealloc to remove all observers of SettingsViewController ([#7697](https://github.com/vector-im/element-ios/pull/7697))
|
||||
- Editing a message that ends with an emoji now works as expected. ([#7681](https://github.com/vector-im/element-ios/issues/7681))
|
||||
- The "Quote" action has been removed from the menu of the selected message. ([#7691](https://github.com/vector-im/element-ios/issues/7691))
|
||||
- The slide to end call for everyone button for the Jitsi widget now also ends the call for the current user. ([#7704](https://github.com/vector-im/element-ios/issues/7704))
|
||||
- If a Jitsi call in a room is ongoing when the Jitsi widget is removed from such room the call ends. ([#7706](https://github.com/vector-im/element-ios/issues/7706))
|
||||
- If a moderator ends a Jitsi call for everyone the call is now dismissed. ([#7709](https://github.com/vector-im/element-ios/issues/7709))
|
||||
|
||||
⚠️ API Changes
|
||||
|
||||
- Drop support for iOS 14, raising the deployment target to iOS 15 to support the latest Rich Text Editor version. ([#7711](https://github.com/vector-im/element-ios/pull/7711))
|
||||
|
||||
|
||||
## Changes in 1.11.4 (2023-10-04)
|
||||
|
||||
🙌 Improvements
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
//
|
||||
|
||||
// Version
|
||||
MARKETING_VERSION = 1.11.4
|
||||
CURRENT_PROJECT_VERSION = 1.11.4
|
||||
MARKETING_VERSION = 1.11.5
|
||||
CURRENT_PROJECT_VERSION = 1.11.5
|
||||
|
||||
@@ -26,7 +26,7 @@ KEYCHAIN_ACCESS_GROUP = $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER).keychain
|
||||
BROADCAST_UPLOAD_EXTENSION_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).broadcastUploadExtension
|
||||
|
||||
// Build settings
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0
|
||||
SDKROOT = iphoneos
|
||||
TARGETED_DEVICE_FAMILY = 1,2
|
||||
SWIFT_VERSION = 5.6
|
||||
|
||||
4
Podfile
4
Podfile
@@ -1,7 +1,7 @@
|
||||
source 'https://cdn.cocoapods.org/'
|
||||
|
||||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '14.0'
|
||||
platform :ios, '15.0'
|
||||
|
||||
# By default, ignore all warnings from any pod
|
||||
inhibit_all_warnings!
|
||||
@@ -16,7 +16,7 @@ use_frameworks!
|
||||
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI
|
||||
#
|
||||
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
|
||||
$matrixSDKVersion = '= 0.27.3'
|
||||
$matrixSDKVersion = '= 0.27.4'
|
||||
# $matrixSDKVersion = :local
|
||||
# $matrixSDKVersion = { :branch => 'develop'}
|
||||
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }
|
||||
|
||||
18
Podfile.lock
18
Podfile.lock
@@ -39,9 +39,9 @@ PODS:
|
||||
- LoggerAPI (1.9.200):
|
||||
- Logging (~> 1.1)
|
||||
- Logging (1.4.0)
|
||||
- MatrixSDK (0.27.3):
|
||||
- MatrixSDK/Core (= 0.27.3)
|
||||
- MatrixSDK/Core (0.27.3):
|
||||
- MatrixSDK (0.27.4):
|
||||
- MatrixSDK/Core (= 0.27.4)
|
||||
- MatrixSDK/Core (0.27.4):
|
||||
- AFNetworking (~> 4.0.0)
|
||||
- GZIP (~> 1.3.0)
|
||||
- libbase58 (~> 0.1.4)
|
||||
@@ -49,7 +49,7 @@ PODS:
|
||||
- OLMKit (~> 3.2.5)
|
||||
- Realm (= 10.27.0)
|
||||
- SwiftyBeaver (= 1.9.5)
|
||||
- MatrixSDK/JingleCallStack (0.27.3):
|
||||
- MatrixSDK/JingleCallStack (0.27.4):
|
||||
- JitsiMeetSDKLite (= 8.1.2-lite)
|
||||
- MatrixSDK/Core
|
||||
- MatrixSDKCrypto (0.3.13)
|
||||
@@ -102,8 +102,8 @@ DEPENDENCIES:
|
||||
- KeychainAccess (~> 4.2.2)
|
||||
- KTCenterFlowLayout (~> 1.3.1)
|
||||
- libPhoneNumber-iOS (~> 0.9.13)
|
||||
- MatrixSDK (= 0.27.3)
|
||||
- MatrixSDK/JingleCallStack (= 0.27.3)
|
||||
- MatrixSDK (= 0.27.4)
|
||||
- MatrixSDK/JingleCallStack (= 0.27.4)
|
||||
- OLMKit
|
||||
- PostHog (~> 2.0.0)
|
||||
- ReadMoreTextView (~> 3.0.1)
|
||||
@@ -187,7 +187,7 @@ SPEC CHECKSUMS:
|
||||
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
|
||||
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
|
||||
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
||||
MatrixSDK: 83fd36133b8e9147aa2f770953dc7921dda4e8b5
|
||||
MatrixSDK: da1df31afa59611ec7251ec419a2ceca6d41c7c4
|
||||
MatrixSDKCrypto: bf08b72f2cd015d8749420a2b8b92fc0536bedf4
|
||||
OLMKit: da115f16582e47626616874e20f7bb92222c7a51
|
||||
PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d
|
||||
@@ -208,6 +208,6 @@ SPEC CHECKSUMS:
|
||||
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
|
||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||
|
||||
PODFILE CHECKSUM: 20f5e721c3f48c117b9610409e79661637454aa1
|
||||
PODFILE CHECKSUM: 3b328f8bb8500a6dd81136ab8a065e7434959805
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
COCOAPODS: 1.13.0
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/Cocoanetics/DTCoreText",
|
||||
"state" : {
|
||||
"revision" : "9d2d4d2296e5d2d852a7d3c592b817d913a5d020",
|
||||
"version" : "1.6.27"
|
||||
"revision" : "b664664825da565b4c2b7a17dbe2369f68ae43d9",
|
||||
"version" : "1.6.26"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -50,8 +50,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift",
|
||||
"state" : {
|
||||
"revision" : "1100b217c04d096dfe072afb4484660ff794d805",
|
||||
"version" : "2.2.2"
|
||||
"revision" : "dfb74c89bf54b41ea000d564d6435ac6444ba6b4",
|
||||
"version" : "2.18.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1083,3 +1083,118 @@
|
||||
// Others
|
||||
"or" = "أو";
|
||||
"accessibility_selected" = "تم تحديده";
|
||||
"media_type_accessibility_sticker" = "مُلصَق";
|
||||
"unknown_devices_call_anyway" = "اتصل على أي حال";
|
||||
"notice_voice_broadcast_ended_by_you" = "لقد أنهيت بث صوتي.";
|
||||
"thread_copy_link_to_thread" = "نسخ الرابط إلى الموضوع";
|
||||
"pill_message_in" = "رسالة في %@";
|
||||
"room_accessibility_record_voice_message" = "قم بتسجيل رسالة صوتية";
|
||||
"media_type_accessibility_image" = "صُورَة";
|
||||
"pill_message" = "رِسَالَة";
|
||||
"pill_message_from" = "رسالة من %@";
|
||||
|
||||
// Room commands descriptions
|
||||
"room_command_change_display_name_description" = "قم بتغيير اسم العرض الخاص بك";
|
||||
"room_command_emote_description" = "يعرض الإجراء";
|
||||
"room_command_join_room_description" = "ينضم إلى الغرفة بالعنوان المعطى";
|
||||
"room_command_part_room_description" = "مغادرة الغرفة";
|
||||
"room_command_invite_user_description" = "يدعو المستخدم بالمعرف المعطى للانضمام إلى الغرفة الحالية";
|
||||
"room_command_set_user_power_level_description" = "تعريف مستوى الصلاحية للمستخدم";
|
||||
"room_title_multiple_active_members" = "%@/%@ أعضاء نشطين";
|
||||
"room_first_message_placeholder" = "أرسل أول رسالة لك…";
|
||||
"threads_empty_title" = "حافظ على تنظيم المناقشات باستخدام المواضيع";
|
||||
"message_from_a_thread" = "من موضوع";
|
||||
"authentication_qr_login_failure_device_not_supported" = "الربط مع هذا الجهاز غير مَدعُومَ.";
|
||||
"threads_action_my_threads" = "مواضيعي";
|
||||
"threads_beta_title" = "مواضيع";
|
||||
"room_title_members" = "%@ أعضاء";
|
||||
"settings_sending_media" = "إرسال الصور ومقاطع الفيديو";
|
||||
|
||||
// MARK: Password policy errors
|
||||
"password_policy_too_short_pwd_error" = "كلمة مرور قصيرة جدً";
|
||||
"password_policy_weak_pwd_error" = "هذه كلمة المرور ضعيفة جدًا. يجب أن تحتوي على ما لا يقل عن 8 أحرف، بما في ذلك حرف كبير، حرف صغير، رقم وحرف خاص واحد على الأقل.";
|
||||
"threads_beta_information_link" = "تعلم أكثر";
|
||||
"room_title_one_member" = "عضو واحد";
|
||||
|
||||
// MARK: Threads
|
||||
"room_thread_title" = "موضوع";
|
||||
"threads_beta_cancel" = "ليس الآن";
|
||||
"media_type_accessibility_audio" = "صَوت";
|
||||
"unknown_devices_answer_anyway" = "أجب على أي حال";
|
||||
"threads_notice_done" = "فهمت";
|
||||
"notice_voice_broadcast_ended" = "%@ أنهى بثًا صوتيًا.";
|
||||
"authentication_login_with_qr" = "تسجيل الدخول بواسطة رمز الاستجابة السريعة";
|
||||
"authentication_qr_login_start_step2" = "الإعدَادَات -> الأمَان والخُصُوصِيَّة";
|
||||
"authentication_qr_login_start_need_alternative" = "هل تحتاج إلى طريقة بديلة؟";
|
||||
"authentication_qr_login_start_subtitle" = "استخدم الكاميرا على هذا الجهاز لمسح رمز الاستجابة السريعة المعروض على جهازك الآخر:";
|
||||
"authentication_qr_login_start_step1" = "افتج برنامج Element على جهازك الأخر";
|
||||
"authentication_qr_login_start_display_qr" = "عرض رمز الاستجابة السريعة على هذا الجهاز";
|
||||
"authentication_qr_login_display_step2" = "اختر 'تسجيل الدخول بواسطة رمز الاستجابة السريعة'";
|
||||
"authentication_qr_login_confirm_title" = "تم إنشاء اتصال آمن";
|
||||
"authentication_qr_login_loading_connecting_device" = "الاتصال بالجهاز";
|
||||
"authentication_qr_login_loading_waiting_signin" = "انتظر حتى يقوم الجهاز بتسجيل الدخول.";
|
||||
"authentication_qr_login_loading_signed_in" = "تم تسجيل دخولك على جهازك الآخر.";
|
||||
"authentication_qr_login_failure_title" = "فشل الربط";
|
||||
"authentication_qr_login_failure_invalid_qr" = "رمز الاستجابة السريعة غير صالح.";
|
||||
"authentication_qr_login_failure_retry" = "حاول مرة أخرى";
|
||||
"room_accessibility_record_voice_message_hint" = "انقر مزدوجًا واستمر في الضغط للتسجيل.";
|
||||
"media_type_accessibility_file" = "مَلَفّ";
|
||||
"unknown_devices_title" = "الجلسات المجهولة";
|
||||
"room_title_invite_members" = "ادعو الأعضاء";
|
||||
"settings_user_settings" = "إعدَادَات المُستَخدِم";
|
||||
"notice_voice_broadcast_live" = "بث مباشر";
|
||||
"room_no_privileges_to_create_group_call" = "يجب أن تكون مشرفًا أو مديرًا لبدء مكالمة.";
|
||||
"external_link_confirmation_title" = "قم بالتحقق تكرارا من هذا الرابط";
|
||||
"unknown_devices_verify" = "تحقق…";
|
||||
"settings_links" = "روابط";
|
||||
"room_creation_only_one_email_invite" = "يمكنك دعوة بريد إلكتروني واحد فقط في كل مرة";
|
||||
"room_command_kick_user_description" = "يزيل المستخدم بالمعرف من هذه الغرفة";
|
||||
"room_command_ban_user_description" = "يمنع المستخدم بالمعرف المعطى";
|
||||
"room_command_unban_user_description" = "يلغي الحظر عن المستخدم بالمعرف المعطى";
|
||||
"room_command_reset_user_power_level_description" = "إلغاء صلاحيات المستخدم بالمعرف المعطى";
|
||||
"room_command_change_room_topic_description" = "تعيين موضوع الغرفة";
|
||||
"threads_title" = "مواضيع";
|
||||
"threads_action_all_threads" = "جميع المواضيع";
|
||||
"threads_notice_title" = "المواضيع لم تعد تجريبية 🎉";
|
||||
"threads_empty_show_all_threads" = "عرض جميع المواضيع";
|
||||
"threads_beta_enable" = "جربها";
|
||||
"media_type_accessibility_video" = "مَقطَع مَرئي";
|
||||
"media_type_accessibility_location" = "مَوقِع جُغرَافِيّ";
|
||||
"room_multiple_typing_notification" = "%@ وغيرهم";
|
||||
|
||||
// Unknown devices
|
||||
"unknown_devices_alert_title" = "الغرفة تحتوي على جلسات مجهولة";
|
||||
"unknown_devices_send_anyway" = "أرسل على أي حال";
|
||||
"room_title_one_active_member" = "%@/%@ عضو نشط";
|
||||
|
||||
// Room Title
|
||||
"room_title_new_room" = "غرفة جديدة";
|
||||
|
||||
// Settings
|
||||
"settings_title" = "الإعدَادَات";
|
||||
"notice_error_unformattable_event" = "** غير قادر على عرض الرسالة. يُرجى الإبلاغ عن خلل";
|
||||
"authentication_qr_login_start_step3" = "حَّدِد 'اربط الجهاز'";
|
||||
"authentication_qr_login_start_title" = "امسح رمز الاستجابة السريعة";
|
||||
"authentication_qr_login_start_step4" = "حَّدِد 'إظهَر رمز الQR الموجود في الجهاز'";
|
||||
"authentication_qr_login_display_title" = "ربط جهاز";
|
||||
"authentication_qr_login_display_subtitle" = "امسح رمز الاستجابة السريعة أدناه باستخدام جهازك الذي تم تسجيل الخروج منه.";
|
||||
"authentication_qr_login_display_step1" = "افتح تطبيق Element على جهازك الآخر";
|
||||
"authentication_qr_login_scan_title" = "امسح رمز الاستجابة السريعة";
|
||||
"authentication_qr_login_failure_request_denied" = "تم رفض الطلب على الجهاز الآخر.";
|
||||
"authentication_qr_login_failure_request_timed_out" = "لم يتم الانتهاء من الربط في الوقت المطلوب.";
|
||||
"authentication_qr_login_scan_subtitle" = "ضع رمز الاستجابة السريعة في المربع أدناه";
|
||||
"authentication_qr_login_confirm_subtitle" = "تأكد أن الرمز أدناه متطابق مع جهازك الآخر:";
|
||||
"authentication_qr_login_confirm_alert" = "يرجى التأكد من مصدر هذا الرمز. من خلال ربط الأجهزة، ستمنح الشخص الأخر الصلاحية الكاملة على حسابك.";
|
||||
"room_creation_user_not_found_prompt_title" = "تَأكيد";
|
||||
"room_creation_user_not_found_prompt_message" = "تعذر العثور على الهوية على مُعَرِّف Matrix. هل ترغب في بدء رسالة مباشرة على أي حال؟";
|
||||
"room_creation_user_not_found_prompt_invite_action" = "ابدأ الرسالة المباشرة على أي حال";
|
||||
"room_participants_invite_unknown_participant_prompt_to_msg" = "تعذر العثور على هذه الهوية على مُعَرِّف Matrix. هل أنت متأكد أنك تريد دعوة %@ إلى %@؟";
|
||||
"room_participants_invite_anyway" = "ادعُ بأي حال";
|
||||
"threads_empty_tip" = "نصيحة: انقر فوق رسالة واستخدم 'موضوع' لبدء رسالة جديدة.";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "المساحة/الغرفة";
|
||||
"room_command_discard_session_description" = "يجبر على تجاهل الجلسة الجماعية الصادرة حاليا في غرفة مشفرة";
|
||||
"room_command_error_unknown_command" = "أمر غير صالح أو غير معالَج";
|
||||
"threads_empty_info_all" = "المواضيع تساعد في الحفاظ على محادثاتك ذات موضوع معين وتسهل تتبعها.";
|
||||
"threads_empty_info_my" = "الرد على موضوع قائم أو النقر فوق الرسالة واستخدم خاصية 'الموضوع' لبدء رِسَالَة جديد.";
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Permissions usage explanations
|
||||
"NSCameraUsageDescription" = "La càmera s'utilitza per fer fotos i vídeos, fer vídeo conferència.";
|
||||
"NSPhotoLibraryUsageDescription" = "La fototeca s'utilitza per enviar fotos i vídeos.";
|
||||
"NSCameraUsageDescription" = "La càmera s'utilitza per a fer videotrucades, o per a fer i pujar fotos i vídeos.";
|
||||
"NSPhotoLibraryUsageDescription" = "Permeteu l'accés a les fotos per a pujar fotos i vídeos de la galeria.";
|
||||
"NSMicrophoneUsageDescription" = "Element necessita accedir al vostre micròfon per a fer i rebre trucades, vídeos i gravar missatges de veu.";
|
||||
"NSContactsUsageDescription" = "Element us mostrarà els vostres contactes per si els voleu convidar a xatejar.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Quan compartiu la vostra localització amb altres, Element en necessita accés per mostrar-lis un mapa.";
|
||||
"NSFaceIDUsageDescription" = "Face ID es fa servir per accedir a la vostra app.";
|
||||
"NSContactsUsageDescription" = "Es compartiran amb el vostre servidor d'identitat per ajudar-vos a trobar contactes al Matrix.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Quan compartiu la vostra ubicació, l'Element en necessita accés per mostrar-los un mapa.";
|
||||
"NSFaceIDUsageDescription" = "Face ID es fa servir per a accedir a l'aplicació.";
|
||||
"NSCalendarsUsageDescription" = "Consulteu la vostra agenda de reunions a l'app.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Quan compartiu la vostra ubicació, l'Element en necessita accés per a mostrar-los un mapa.";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* New message from a specific person, not referencing a room */
|
||||
"MSG_FROM_USER" = "%@ ha enviat un missatge";
|
||||
/* New message from a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM" = "%@ publicat a %@";
|
||||
"MSG_FROM_USER_IN_ROOM" = "%@ ha publicat a %@";
|
||||
/* New message from a specific person, not referencing a room. Content included. */
|
||||
"MSG_FROM_USER_WITH_CONTENT" = "%@: %@";
|
||||
/* New message from a specific person in a named room. Content included. */
|
||||
@@ -14,19 +14,19 @@
|
||||
/* New action message from a specific person in a named room. */
|
||||
"IMAGE_FROM_USER_IN_ROOM" = "%@ ha publicat una foto %@ a %@";
|
||||
/* Multiple unread messages in a room */
|
||||
"UNREAD_IN_ROOM" = "%@ nous missatges a %@";
|
||||
"UNREAD_IN_ROOM" = "%@ missatges nous a %@";
|
||||
/* Multiple unread messages from a specific person, not referencing a room */
|
||||
"MSGS_FROM_USER" = "%@ nou missatge a %@";
|
||||
"MSGS_FROM_USER" = "%@ missatge nou a %@";
|
||||
/* Multiple unread messages from two people */
|
||||
"MSGS_FROM_TWO_USERS" = "%@ nous missatges de %@ i %@";
|
||||
"MSGS_FROM_TWO_USERS" = "%@ missatges nous de: %@ i %@";
|
||||
/* Multiple unread messages from three people */
|
||||
"MSGS_FROM_THREE_USERS" = "%@ nous missatges de %@, %@ i %@";
|
||||
"MSGS_FROM_THREE_USERS" = "%@ missatges nous de: %@, %@ i %@";
|
||||
/* Multiple unread messages from two plus people (ie. for 4+ people: 'others' replaces the third person) */
|
||||
"MSGS_FROM_TWO_PLUS_USERS" = "%@ nous missatges de %@, %@ i altres";
|
||||
"MSGS_FROM_TWO_PLUS_USERS" = "%@ missatges nous de: %@, %@ i altres";
|
||||
/* Multiple messages in two rooms */
|
||||
"MSGS_IN_TWO_ROOMS" = "%@ nous missatges a %@ i %@";
|
||||
"MSGS_IN_TWO_ROOMS" = "%@ missatges nous a %@ i %@";
|
||||
/* Look, stuff's happened, alright? Just open the app. */
|
||||
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ nous missatges a %@, %@ i altres";
|
||||
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ missatges nous a %@, %@ i altres";
|
||||
/* A user has invited you to a chat */
|
||||
"USER_INVITE_TO_CHAT" = "%@ t'ha convidat a xatejar";
|
||||
/* A user has invited you to an (unamed) group chat */
|
||||
@@ -34,17 +34,17 @@
|
||||
/* A user has invited you to a named room */
|
||||
"USER_INVITE_TO_NAMED_ROOM" = "%@ t'ha convidat a %@";
|
||||
/* Incoming one-to-one voice call */
|
||||
"VOICE_CALL_FROM_USER" = "Trucada de %@";
|
||||
"VOICE_CALL_FROM_USER" = "Trucada de: %@";
|
||||
/* Incoming one-to-one video call */
|
||||
"VIDEO_CALL_FROM_USER" = "Vídeo trucada de %@";
|
||||
"VIDEO_CALL_FROM_USER" = "Videotrucada de: %@";
|
||||
/* Incoming unnamed voice conference invite from a specific person */
|
||||
"VOICE_CONF_FROM_USER" = "Trucada grupal de %@";
|
||||
"VOICE_CONF_FROM_USER" = "Trucada grupal de: %@";
|
||||
/* Incoming unnamed video conference invite from a specific person */
|
||||
"VIDEO_CONF_FROM_USER" = "Vídeo trucada grupal de %@";
|
||||
"VIDEO_CONF_FROM_USER" = "Videotrucada grupal de: %@";
|
||||
/* Incoming named voice conference invite from a specific person */
|
||||
"VOICE_CONF_NAMED_FROM_USER" = "Trucada grupal de %@: '%@'";
|
||||
"VOICE_CONF_NAMED_FROM_USER" = "Trucada grupal de: %@: '%@'";
|
||||
/* Incoming named video conference invite from a specific person */
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Vídeo trucada grupal de %@: '%@'";
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Videotrucada grupal de: %@: '%@'";
|
||||
/* A single unread message in a room */
|
||||
"SINGLE_UNREAD_IN_ROOM" = "Has rebut un missatge a %@";
|
||||
/* A single unread message */
|
||||
@@ -56,7 +56,7 @@
|
||||
/* New message indicator on unknown room */
|
||||
"MESSAGE" = "Missatge";
|
||||
/* New message indicator from a DM */
|
||||
"MESSAGE_FROM_X" = "Missatge de %@";
|
||||
"MESSAGE_FROM_X" = "Missatge de: %@";
|
||||
/* New message indicator on a room */
|
||||
"MESSAGE_IN_X" = "Missatge a %@";
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ vol verificar";
|
||||
@@ -90,10 +90,10 @@
|
||||
"REACTION_FROM_USER" = "%@ ha reaccionat amb %@";
|
||||
|
||||
/* New message with hidden content due to PIN enabled */
|
||||
"MESSAGE_PROTECTED" = "Nou missatge";
|
||||
"MESSAGE_PROTECTED" = "Missatge nou";
|
||||
|
||||
/* New file message from a specific person, not referencing a room. */
|
||||
"LOCATION_FROM_USER" = "%@ ha compartit la localització";
|
||||
"LOCATION_FROM_USER" = "%@ ha compartit la ubicació";
|
||||
|
||||
/* New file message from a specific person, not referencing a room. */
|
||||
"FILE_FROM_USER" = "%@ ha enviat un fitxer %@";
|
||||
@@ -113,10 +113,13 @@
|
||||
"PICTURE_FROM_USER" = "%@ ha enviat una foto";
|
||||
|
||||
/* New message reply from a specific person in a named room. */
|
||||
"REPLY_FROM_USER_IN_ROOM_TITLE" = "%@ respost a %@";
|
||||
"REPLY_FROM_USER_IN_ROOM_TITLE" = "%@ ha respost a %@";
|
||||
|
||||
/* New message reply from a specific person, not referencing a room. */
|
||||
"REPLY_FROM_USER_TITLE" = "%@ respost";
|
||||
"REPLY_FROM_USER_TITLE" = "%@ ha respost";
|
||||
/** General **/
|
||||
|
||||
"Notification" = "Notificació";
|
||||
|
||||
/* New voice broadcast from a specific person, not referencing a room. */
|
||||
"VOICE_BROADCAST_FROM_USER" = "%@ ha iniciat una retransmissió de veu";
|
||||
|
||||
@@ -5,23 +5,23 @@
|
||||
"title_rooms" = "Sales";
|
||||
"warning" = "Avís";
|
||||
// Actions
|
||||
"view" = "Veure";
|
||||
"view" = "Mostra";
|
||||
"next" = "Següent";
|
||||
"back" = "Torna";
|
||||
"continue" = "Continua";
|
||||
"create" = "Crear";
|
||||
"start" = "Començar";
|
||||
"leave" = "Sortir";
|
||||
"remove" = "Esborrar";
|
||||
"create" = "Crea";
|
||||
"start" = "Comença";
|
||||
"leave" = "Surt";
|
||||
"remove" = "Suprimeix";
|
||||
"invite" = "Convida";
|
||||
"retry" = "Torna a provar";
|
||||
"on" = "Activa";
|
||||
"off" = "Apaga";
|
||||
"cancel" = "Cancel·lar";
|
||||
"save" = "Desar";
|
||||
"join" = "Entrar";
|
||||
"decline" = "Declinar";
|
||||
"accept" = "Acceptar";
|
||||
"on" = "Activat";
|
||||
"off" = "Desactivat";
|
||||
"cancel" = "Cancel·la";
|
||||
"save" = "Desa";
|
||||
"join" = "Entra";
|
||||
"decline" = "Rebutja";
|
||||
"accept" = "Accepta";
|
||||
"preview" = "Vista prèvia";
|
||||
"camera" = "Càmera";
|
||||
"voice" = "Veu";
|
||||
@@ -29,10 +29,10 @@
|
||||
"active_call" = "Trucada en curs";
|
||||
"active_call_details" = "Trucada en curs (%@)";
|
||||
"later" = "Més tard";
|
||||
"rename" = "Reanomenar";
|
||||
"collapse" = "Contraure";
|
||||
"send_to" = "Enviar a %@";
|
||||
"sending" = "Enviant";
|
||||
"rename" = "Canvia el nom";
|
||||
"collapse" = "contrau";
|
||||
"send_to" = "Envia a %@";
|
||||
"sending" = "S'està enviant";
|
||||
// Authentication
|
||||
"auth_login" = "Iniciar sessió";
|
||||
"auth_register" = "Registre";
|
||||
@@ -551,7 +551,7 @@
|
||||
// String for App Store
|
||||
"store_short_description" = "Xat/VoIP segur i descentralitzat";
|
||||
"close" = "Tanca";
|
||||
"skip" = "Salta";
|
||||
"skip" = "Omet";
|
||||
"joined" = "Unit";
|
||||
"switch" = "Canvia";
|
||||
"more" = "Més";
|
||||
@@ -562,7 +562,6 @@
|
||||
|
||||
// MARK: - MatrixKit
|
||||
|
||||
|
||||
"matrix" = "Matrix";
|
||||
"login_password_placeholder" = "Contrasenya";
|
||||
"login_optional_field" = "opcional";
|
||||
@@ -909,3 +908,43 @@
|
||||
"ssl_unexpected_existing_expl" = "El certificat ha canviat respecte al que el teu telèfon hi havia confiat. Això es MOLT INUSUAL. Es recomana que NO ACCEPTIS aquest nou certificat.";
|
||||
"ssl_expected_existing_expl" = "El certificat ha canviat del prèviament confiat a un que no es confiable. El servidor pot haver renovat el certificat. Posa't en contacte amb l'administrador del servidor per obtenir l'empremta digital desitjada.";
|
||||
"ssl_only_accept" = "NOMÉS accepteu el certificat si l'administrador del servidor ha publicat una empremta digital que coincideixi amb l'anterior.";
|
||||
"store_full_description" = "Element és un tipus nou d'aplicació de missatgeria i col·laboració que:\n\n1. Us dona el control per a preservar la vostra privadesa\n2. Us permet comunicar-vos amb qualsevol persona de la xarxa Matrix, i encara més enllà integrant aplicacions com ara Slack\n3. Us protegeix de la publicitat, mineria de dades, portes ocultes i jardins emmurallats\n4. Us salvaguarda mitjançant el xifratge extrem a extrem, amb signatura creuada per a la verificació dels altres\n\nElement és completament diferent d'altres aplicacions de missatgeria i col·laboració perquè és descentralitzada i de codi obert.\n\nElement us permet muntar-vos un servidor propi (o triar un amfitrió) perquè tingueu privadesa i el control sobre les dades i les converses. Us dona accés a una xarxa oberta, no parlareu només amb altres usuaris d'Element. I és molt segura.\n\nElement pot fer tot això perquè opera en Matrix, l'estàndard de les comunicacions obertes i descentralitzades.\n\nElement us dona el control, permetent-vos triar qui és l'amfitrió de les vostres converses. Des de l'aplicació d'Element podeu triar l'amfitrió de maneres diferents:\n\n1. Creeu un compte gratuït al servidor públic de matrix.org\n2. Munteu un servidor local per a acollir el vostre compte\n3. Creeu un compte en un servidor personalitzat subscrivint-vos a la plataforma d'allotjament d'Element Matrix Services \n\nPer què triar Element?\n\nCONTROLEU LES VOSTRES DADES: Vós decidiu on desar les vostres dades i missatges. En sou el propietari i les controleu, no cap MEGACORPORACIÓ que les mina les vostres dades i permet que terceres parts hi accedeixen.\n\nCOL·LABORACIÓ I MISSATGERIA OBERTA: Podeu xatejar amb qualsevol a la xarxa Matrix, tant si utilitzen Element com qualsevol altra aplicació Matrix, i fins i tot si utilitzen algun sistema de missatgeria diferent, com ara Slack, IRC o XMPP.\n\nSUPERSEGURA: Xifratge extrem a extrem real (només els participants de la conversa poden desxifrar els missatges), i signatura creuada per a verificar els dispositius dels participants de la conversa.\n\nCOMUNICACIÓ COMPLETA: Missatges, trucades d'àudio i vídeo, compartició de fitxers, de pantalla i moltes altres integracions, bots i ginys. Construïu sales, comunitats, estigueu en contacte i aconseguir que les coses es facin.\n\nESTIGUEU ON ESTIGUEU: Comuniqueu-vos estigueu on estigueu amb l'historial de missatges completament sincronitzat a tots els dispositius i al web, a https://app.element.io.";
|
||||
"store_promotional_text" = "Aplicació de col·laboració i missatgeria que preserva la privadesa, en una xarxa oberta. Descentralitzada per a donar-vos el control. Sense mineria de dades, portes ocultes ni accés a tercers.";
|
||||
|
||||
// MARK: Onboarding
|
||||
"onboarding_splash_register_button_title" = "Crea un compte";
|
||||
"onboarding_splash_page_3_message" = "Xifrat extrem a extrem i no cal cap número de telèfon. Sense publicitat ni mineria de dades.";
|
||||
"confirm" = "Confirma";
|
||||
"callbar_only_multiple_paused" = "%@ trucades en espera";
|
||||
"existing" = "Existent";
|
||||
"add" = "Afegeix";
|
||||
"joining" = "Unió";
|
||||
"stop" = "Atura";
|
||||
"new_word" = "Nou";
|
||||
"suggest" = "Suggereix";
|
||||
"edit" = "Edita";
|
||||
|
||||
// Activities
|
||||
"loading" = "S'està carregant";
|
||||
"saving" = "S'està desant";
|
||||
"accessibility_button_label" = "botó";
|
||||
"onboarding_splash_login_button_title" = "Ja tinc un compte";
|
||||
"onboarding_splash_page_1_title" = "Controleu les vostres converses.";
|
||||
"onboarding_splash_page_1_message" = "Comunicació independent i segura que us dona el mateix nivell de privadesa que una conversa cara a cara en casa.";
|
||||
"onboarding_splash_page_2_title" = "Sou en control.";
|
||||
"onboarding_splash_page_2_message" = "Trieu on es desen les vostres converses, el que us dona control i independència. Connectat via Matrix.";
|
||||
"onboarding_splash_page_3_title" = "Missatgeria segura.";
|
||||
"open" = "Obre";
|
||||
"callbar_return" = "Torna";
|
||||
"invite_to" = "Convida a %@";
|
||||
"callbar_only_single_active_group" = "Toqueu per a unir-vos a la trucada grupal (%@)";
|
||||
"callbar_active_and_multiple_paused" = "1 trucada activa (%@) · %@ trucades en espera";
|
||||
"callbar_only_single_paused" = "Trucada en espera";
|
||||
"enable" = "Activa";
|
||||
"done" = "Fet";
|
||||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Toqueu per a tornar a la trucada (%@)";
|
||||
"callbar_active_and_single_paused" = "1 trucada activa (%@) · 1 trucada en espera";
|
||||
"accessibility_selected" = "seleccionat";
|
||||
"less" = "Menys";
|
||||
|
||||
@@ -135,8 +135,8 @@
|
||||
"directory_cell_title" = "Duyệt danh mục";
|
||||
"directory_cell_description" = "%tu phòng";
|
||||
"directory_search_results_title" = "Kết quả duyệt danh mục";
|
||||
"directory_search_results" = "%tu kết quả được tìm thấy cho %@";
|
||||
"directory_search_results_more_than" = ">%tu kết quả được tìm thấy cho %@";
|
||||
"directory_search_results" = "%1$tu kết quả được tìm thấy cho %2$@";
|
||||
"directory_search_results_more_than" = ">%1$tu kết quả được tìm thấy cho %2$@";
|
||||
"directory_searching_title" = "Đang tìm danh mục…";
|
||||
"directory_search_fail" = "Không thể tìm nạp dữ liệu";
|
||||
// Contacts
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
"room_details_access_section_anyone" = "任何知道此房间链接的人,包括访客";
|
||||
"room_details_access_section_no_address_warning" = "要链接一个房间必须设置地址";
|
||||
"room_details_access_section_directory_toggle" = "将此房间列入房间目录";
|
||||
"room_details_history_section" = "谁可以阅读历史?";
|
||||
"room_details_history_section" = "谁可以读取历史?";
|
||||
"room_details_history_section_anyone" = "任何人";
|
||||
"room_details_history_section_members_only" = "只有成员(从选择这个选项的时间开始)";
|
||||
"room_details_history_section_members_only_since_invited" = "只有成员(从他们被邀请开始)";
|
||||
@@ -2275,7 +2275,7 @@
|
||||
"user_session_learn_more" = "了解更多";
|
||||
"manage_session_name_info_link" = "了解更多";
|
||||
"threads_beta_information_link" = "了解更多";
|
||||
"authentication_qr_login_display_subtitle" = "用你登出的设备扫描下面的QR码。";
|
||||
"authentication_qr_login_display_subtitle" = "用你已登出的设备扫描下面的QR码。";
|
||||
"room_invite_to_space_option_detail" = "他们可以探索 %@,但不会成为 %@ 的成员。";
|
||||
"analytics_prompt_message_new_user" = "通过分享匿名的使用数据,帮助我们识别问题并改进 %@ 。为了了解人们如何使用多个设备,我们将生成一个随机的标识符,由你的设备共享。";
|
||||
"threads_notice_done" = "知道了";
|
||||
@@ -2367,3 +2367,41 @@
|
||||
"settings_presence_offline_mode" = "离线模式";
|
||||
"room_details_polls" = "投票历史";
|
||||
"settings_labs_enable_new_app_layout" = "新版应用布局";
|
||||
"room_details_access_row_title" = "访问";
|
||||
"room_access_settings_screen_restricted_message" = "让空间中的任何人都能找到并加入。\n将要求你确认哪些空间。";
|
||||
"room_access_settings_screen_upgrade_required" = "需要升级";
|
||||
"room_participants_invite_unknown_participant_prompt_to_msg" = "未找到该 Matrix ID 的配置文件。您确定要邀请 %@ 到 %@?";
|
||||
"room_access_settings_screen_upgrade_alert_auto_invite_switch" = "自动邀请成员到新房间";
|
||||
"room_preview_decline_invitation_options" = "您想拒绝邀请还是忽略该用户?";
|
||||
"room_access_settings_screen_title" = "谁能进入此房间?";
|
||||
"room_access_settings_screen_message" = "决定谁能找到并加入 %@。";
|
||||
"room_access_settings_screen_edit_spaces" = "编辑空间";
|
||||
"room_access_settings_screen_public_message" = "任何人都可以找到并加入。";
|
||||
"settings_presence" = "存在";
|
||||
"room_details_promote_room_suggest_title" = "推荐给空间成员";
|
||||
"settings_push_rules_error" = "更新您的个性化通知时发生错误。请再试一次。";
|
||||
"room_access_settings_screen_private_message" = "只有受邀者才能找到并加入。";
|
||||
"room_access_settings_screen_upgrade_alert_message" = "%@ 中的任何人都能找到并加入此房间,无需手动邀请所有人。您可随时在房间设置中进行更改。";
|
||||
"room_access_settings_screen_upgrade_alert_note" = "请注意,升级后将创建一个新版本的房间。当前所有消息都将保留在此归档房间中。";
|
||||
"room_access_settings_screen_upgrade_alert_upgrade_button" = "升级";
|
||||
"settings_acceptable_use" = "可接受使用政策";
|
||||
"room_command_reset_user_power_level_description" = "删除指定 id 的用户";
|
||||
"settings_manage_account_title" = "账户";
|
||||
"settings_manage_account_action" = "管理账户";
|
||||
"settings_manage_account_description" = "在 %@ 管理您的账户";
|
||||
"manage_session_redirect" = "你将被重定向到服务器的验证提供者以完成登出。";
|
||||
"manage_session_redirect_error" = "功能目前不可用。请联系你的家服务器管理员";
|
||||
"room_details_promote_room_title" = "推广房间";
|
||||
|
||||
// Room Access Settings
|
||||
"room_access_settings_screen_nav_title" = "进入房间";
|
||||
"room_access_settings_screen_upgrade_alert_title" = "升级房间";
|
||||
"room_access_settings_screen_upgrade_alert_message_no_param" = "上级房间中的任何人都能找到并加入此房间,无需手动邀请所有人。您可随时在房间设置中进行更改。";
|
||||
"room_access_settings_screen_upgrade_alert_upgrading" = "升级房间";
|
||||
"room_access_settings_screen_setting_room_access" = "设置房间权限";
|
||||
|
||||
// Room suggestion Settings
|
||||
"room_suggestion_settings_screen_nav_title" = "建议房间";
|
||||
"room_access_space_chooser_known_spaces_section" = "您知道的包含 %@ 的空间";
|
||||
"room_access_space_chooser_other_spaces_section_info" = "这些很可能是 %@ 的管理员参与。";
|
||||
"room_access_space_chooser_other_spaces_section" = "其他空间或房间";
|
||||
|
||||
@@ -412,6 +412,13 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
|
||||
// Broadcast the generic notification
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kWidgetManagerDidUpdateWidgetNotification object:widget];
|
||||
// End jitsi call if a active call exists and widget has been updated to not be active
|
||||
if ([[AppDelegate theDelegate].callPresenter.jitsiVC.widget.widgetId isEqualToString: widget.widgetId] &&
|
||||
[[AppDelegate theDelegate].callPresenter.jitsiVC.widget.roomId isEqualToString: event.roomId] &&
|
||||
!widget.isActive)
|
||||
{
|
||||
[[AppDelegate theDelegate].callPresenter endActiveJitsiCall];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -321,26 +321,25 @@ static NSString * _Nonnull kJitsiFeatureFlagScreenSharingEnabled = @"ios.screens
|
||||
|
||||
- (void)conferenceTerminated:(NSDictionary *)data
|
||||
{
|
||||
// If the call is terminated by a moderator the error key contains the "conference.destroyed" value
|
||||
if (data[kJitsiDataErrorKey] != nil)
|
||||
{
|
||||
MXLogDebug(@"[JitsiViewController] conferenceTerminated - data: %@", data);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
// The conference is over. Let the delegate close this view controller.
|
||||
if (self.delegate)
|
||||
{
|
||||
[self.delegate jitsiViewController:self dismissViewJitsiController:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do it ourself
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
// The conference is over. Let the delegate close this view controller.
|
||||
if (self.delegate)
|
||||
{
|
||||
[self.delegate jitsiViewController:self dismissViewJitsiController:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do it ourself
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)enterPictureInPicture:(NSDictionary *)data
|
||||
|
||||
@@ -47,7 +47,9 @@ class HTMLFormatter: NSObject {
|
||||
|
||||
var options: [AnyHashable: Any] = [
|
||||
DTUseiOS6Attributes: true,
|
||||
DTDefaultFontDescriptor: font.fontDescriptor,
|
||||
DTDefaultFontFamily: font.familyName,
|
||||
DTDefaultFontName: font.fontName,
|
||||
DTDefaultFontSize: font.pointSize,
|
||||
DTDefaultLinkDecoration: false,
|
||||
DTDefaultLinkColor: ThemeService.shared().theme.colors.links,
|
||||
DTWillFlushBlockCallBack: sanitizeCallback
|
||||
|
||||
@@ -25,7 +25,6 @@ enum EventMenuItemType: Int {
|
||||
case cancelSending
|
||||
case cancelDownloading
|
||||
case saveMedia
|
||||
case quote
|
||||
case forward
|
||||
case permalink
|
||||
case share
|
||||
|
||||
@@ -4056,26 +4056,6 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self cancelEventSelection];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (!isJitsiCallEvent && !selectedEvent.isTimelinePollEvent &&
|
||||
selectedEvent.eventType != MXEventTypeBeaconInfo)
|
||||
{
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypeQuote
|
||||
action:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionQuote]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
// Quote the message a la Markdown into the input toolbar composer
|
||||
NSString *prefix = [self.inputToolbarView.textMessage length] ? [NSString stringWithFormat:@"%@\n", self.inputToolbarView.textMessage] : @"";
|
||||
self.inputToolbarView.textMessage = [NSString stringWithFormat:@"%@>%@\n\n", prefix, selectedComponent.textMessage];
|
||||
|
||||
// And display the keyboard
|
||||
[self.inputToolbarView becomeFirstResponder];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (selectedEvent.sentState == MXEventSentStateSent &&
|
||||
!selectedEvent.isTimelinePollEvent &&
|
||||
@@ -8053,7 +8033,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
self.removeJitsiWidgetView.delegate = nil;
|
||||
|
||||
// end active call if exists
|
||||
if ([self isRoomHavingAJitsiCallForWidgetId:jitsiWidget.widgetId])
|
||||
if ([self isRoomHavingAJitsiCall])
|
||||
{
|
||||
[self endActiveJitsiCall];
|
||||
}
|
||||
|
||||
@@ -200,15 +200,7 @@ extension RoomViewController {
|
||||
optionalTextView?.becomeFirstResponder()
|
||||
originalRect = wysiwygInputToolbar.convert(wysiwygInputToolbar.frame, to: view)
|
||||
}
|
||||
// This tirggers a SwiftUI update that is handled correctly on iOS 16, but needs to be dispatchted async on older versions
|
||||
// Dispatching on iOS 16 instead causes some weird SwiftUI update behaviours
|
||||
if #available(iOS 16, *) {
|
||||
wysiwygInputToolbar.showKeyboard()
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
wysiwygInputToolbar.showKeyboard()
|
||||
}
|
||||
}
|
||||
|
||||
roomInputToolbarContainer.removeFromSuperview()
|
||||
let dimmingView = UIView()
|
||||
dimmingView.translatesAutoresizingMaskIntoConstraints = false
|
||||
@@ -235,7 +227,18 @@ extension RoomViewController {
|
||||
}
|
||||
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didPanRoomToolbarContainer(_ :)))
|
||||
roomInputToolbarContainer.addGestureRecognizer(panGesture)
|
||||
optionalTextView?.removeFromSuperview()
|
||||
if let optionalTextView {
|
||||
// This tirggers a SwiftUI update that is handled correctly on iOS 16, but needs to be dispatchted async on older versions
|
||||
// Dispatching on iOS 16 instead causes some weird SwiftUI update behaviours
|
||||
if #available(iOS 16, *) {
|
||||
wysiwygInputToolbar.showKeyboard()
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
wysiwygInputToolbar.showKeyboard()
|
||||
}
|
||||
}
|
||||
optionalTextView.removeFromSuperview()
|
||||
}
|
||||
} else {
|
||||
let originalRect = wysiwygInputToolbar.convert(wysiwygInputToolbar.frame, to: view)
|
||||
var optionalTextView: UITextView?
|
||||
@@ -244,7 +247,6 @@ extension RoomViewController {
|
||||
optionalTextView = textView
|
||||
self.view.window?.addSubview(textView)
|
||||
optionalTextView?.becomeFirstResponder()
|
||||
wysiwygInputToolbar.showKeyboard()
|
||||
}
|
||||
self.roomInputToolbarContainer.removeFromSuperview()
|
||||
maximisedToolbarDimmingView?.removeFromSuperview()
|
||||
@@ -257,7 +259,10 @@ extension RoomViewController {
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
roomInputToolbarContainer.gestureRecognizers?.removeAll()
|
||||
optionalTextView?.removeFromSuperview()
|
||||
if let optionalTextView {
|
||||
wysiwygInputToolbar.showKeyboard()
|
||||
optionalTextView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,8 +389,8 @@ extension RoomViewController: ComposerLinkActionBridgePresenterDelegate {
|
||||
}
|
||||
|
||||
// MARK: - PermalinkReplacer
|
||||
extension RoomViewController: PermalinkReplacer {
|
||||
public func replacementForLink(_ url: String, text: String) -> NSAttributedString? {
|
||||
extension RoomViewController: MentionReplacer {
|
||||
public func replacementForMention(_ url: String, text: String) -> NSAttributedString? {
|
||||
guard #available(iOS 15.0, *),
|
||||
let url = URL(string: url),
|
||||
let session = roomDataSource.mxSession,
|
||||
|
||||
@@ -140,6 +140,20 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
|
||||
wysiwygViewModel.maxCompressedHeight
|
||||
}
|
||||
|
||||
override func paste(_ sender: Any?) {
|
||||
let pasteboard = MXKPasteboardManager.shared.pasteboard
|
||||
let types = pasteboard.types.map { UTI(rawValue: $0) }
|
||||
|
||||
// Minimise the composer and dismiss the keyboard if it's an image, a video or a file
|
||||
if types.contains(where: { $0.conforms(to: .image) || $0.conforms(to: .movie) || $0.conforms(to: .video) || $0.conforms(to: .application) }) {
|
||||
wysiwygViewModel.maximised = false
|
||||
DispatchQueue.main.async {
|
||||
self.viewModel.dismissKeyboard()
|
||||
}
|
||||
}
|
||||
super.paste(sender)
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
override class func instantiate() -> MXKRoomInputToolbarView! {
|
||||
@@ -150,8 +164,8 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
|
||||
return (delegate as? RoomInputToolbarViewDelegate) ?? nil
|
||||
}
|
||||
|
||||
private var permalinkReplacer: PermalinkReplacer? {
|
||||
return (delegate as? PermalinkReplacer)
|
||||
private var permalinkReplacer: MentionReplacer? {
|
||||
return (delegate as? MentionReplacer)
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
@@ -192,6 +206,7 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
|
||||
}
|
||||
|
||||
func showKeyboard() {
|
||||
self.wysiwygViewModel.textView.becomeFirstResponder()
|
||||
self.viewModel.showKeyboard()
|
||||
}
|
||||
|
||||
@@ -238,7 +253,7 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
|
||||
self?.handleViewModelResult(result)
|
||||
}
|
||||
wysiwygViewModel.plainTextMode = !RiotSettings.shared.enableWysiwygTextFormatting
|
||||
wysiwygViewModel.permalinkReplacer = permalinkReplacer
|
||||
wysiwygViewModel.mentionReplacer = permalinkReplacer
|
||||
|
||||
inputAccessoryViewForKeyboard = UIView(frame: .zero)
|
||||
|
||||
|
||||
@@ -340,6 +340,11 @@ SSOAuthenticationPresenterDelegate>
|
||||
self.screenTracker = [[AnalyticsScreenTracker alloc] initWithScreen:AnalyticsScreenSettings];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
// Fix for destroy not being called
|
||||
[self destroy];
|
||||
}
|
||||
|
||||
- (void)updateSections
|
||||
{
|
||||
NSMutableArray<Section*> *tmpSections = [NSMutableArray arrayWithCapacity:SECTION_TAG_DEACTIVATE_ACCOUNT + 1];
|
||||
|
||||
@@ -156,7 +156,7 @@ extension FormatItem {
|
||||
|
||||
extension FormatType {
|
||||
/// Convenience method to map it to the external ViewModel action
|
||||
var action: WysiwygAction {
|
||||
var action: ComposerAction {
|
||||
switch self {
|
||||
case .bold:
|
||||
return .bold
|
||||
|
||||
@@ -32,6 +32,7 @@ struct Composer: View {
|
||||
@Environment(\.theme) private var theme: ThemeSwiftUI
|
||||
|
||||
@State private var isActionButtonShowing = false
|
||||
@FocusState private var focused: Bool
|
||||
|
||||
private let horizontalPadding: CGFloat = 12
|
||||
private let borderHeight: CGFloat = 40
|
||||
@@ -58,17 +59,8 @@ struct Composer: View {
|
||||
viewModel.viewState.shouldDisplayContext ? contextBannerHeight + standardVerticalPadding + verticalComponentSpacing : 0
|
||||
}
|
||||
|
||||
/// Computes the total height of the composer (excluding the RTE formatting bar).
|
||||
/// This height includes the text view, as well as the context banner
|
||||
/// and user suggestion list when displayed.
|
||||
private var composerHeight: CGFloat {
|
||||
wysiwygViewModel.idealHeight
|
||||
+ composerTopPadding
|
||||
+ composerVerticalPadding
|
||||
// Extra padding added on top of the VStack containing the composer
|
||||
+ standardVerticalPadding
|
||||
+ additionalHeightForContextBanner
|
||||
}
|
||||
/// the total height of the composer (excluding the RTE formatting bar).
|
||||
@State private var composerHeight: CGFloat = .zero
|
||||
|
||||
private var cornerRadius: CGFloat {
|
||||
if shouldFixRoundCorner {
|
||||
@@ -139,20 +131,39 @@ struct Composer: View {
|
||||
.padding(.horizontal, horizontalPadding)
|
||||
}
|
||||
HStack(alignment: shouldFixRoundCorner ? .top : .center, spacing: 0) {
|
||||
WysiwygComposerView(
|
||||
focused: $viewModel.focused,
|
||||
viewModel: wysiwygViewModel
|
||||
)
|
||||
.tintColor(theme.colors.accent)
|
||||
.placeholder(viewModel.viewState.placeholder, color: theme.colors.tertiaryContent)
|
||||
.onAppear {
|
||||
if wysiwygViewModel.isContentEmpty {
|
||||
wysiwygViewModel.setup()
|
||||
// Use a GeometryReader to force the composer to fill the HStack
|
||||
GeometryReader { _ in
|
||||
WysiwygComposerView(
|
||||
placeholder: viewModel.viewState.placeholder ?? "",
|
||||
viewModel: wysiwygViewModel,
|
||||
itemProviderHelper: nil,
|
||||
keyCommandHandler: handleKeyCommand,
|
||||
pasteHandler: nil
|
||||
)
|
||||
.clipped()
|
||||
.tint(theme.colors.accent)
|
||||
.focused($focused)
|
||||
.onChange(of: focused) { newValue in
|
||||
viewModel.focused = newValue
|
||||
}
|
||||
.onChange(of: viewModel.focused) { newValue in
|
||||
guard focused != newValue else { return }
|
||||
focused = newValue
|
||||
}
|
||||
.onAppear {
|
||||
if wysiwygViewModel.isContentEmpty {
|
||||
wysiwygViewModel.setup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !viewModel.viewState.isMinimiseForced {
|
||||
Button {
|
||||
wysiwygViewModel.maximised.toggle()
|
||||
viewModel.focused = true
|
||||
// Use a dispatched block so the focus state will be up to date when the composer size changes.
|
||||
DispatchQueue.main.async {
|
||||
wysiwygViewModel.maximised.toggle()
|
||||
}
|
||||
} label: {
|
||||
Image(toggleButtonImageName)
|
||||
.resizable()
|
||||
@@ -167,15 +178,14 @@ struct Composer: View {
|
||||
.padding(.horizontal, horizontalPadding)
|
||||
.padding(.top, composerTopPadding)
|
||||
.padding(.bottom, composerVerticalPadding)
|
||||
.layoutPriority(1)
|
||||
}
|
||||
.clipShape(rect)
|
||||
.overlay(rect.stroke(borderColor, lineWidth: 1))
|
||||
.animation(.easeInOut(duration: resizeAnimationDuration), value: wysiwygViewModel.idealHeight)
|
||||
.padding(.top, standardVerticalPadding)
|
||||
.onTapGesture {
|
||||
if viewModel.focused {
|
||||
viewModel.focused = true
|
||||
}
|
||||
viewModel.focused = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +228,29 @@ struct Composer: View {
|
||||
}
|
||||
}
|
||||
|
||||
func handleKeyCommand(_ keyCommand: WysiwygKeyCommand) -> Bool {
|
||||
switch keyCommand {
|
||||
case .enter:
|
||||
sendMessageAction(wysiwygViewModel.content)
|
||||
wysiwygViewModel.clearContent()
|
||||
return true
|
||||
case .shiftEnter:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the total height of the composer (excluding the RTE formatting bar).
|
||||
/// This height includes the text view, as well as the context banner
|
||||
/// and user suggestion list when displayed.
|
||||
private func updateComposerHeight(idealHeight: CGFloat) {
|
||||
composerHeight = idealHeight
|
||||
+ composerTopPadding
|
||||
+ composerVerticalPadding
|
||||
// Extra padding added on top of the VStack containing the composer
|
||||
+ standardVerticalPadding
|
||||
+ additionalHeightForContextBanner
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
|
||||
init(
|
||||
@@ -287,6 +320,15 @@ struct Composer: View {
|
||||
.onChange(of: wysiwygViewModel.suggestionPattern) { newValue in
|
||||
sendMentionPattern(pattern: newValue)
|
||||
}
|
||||
.onChange(of: wysiwygViewModel.idealHeight) { newValue in
|
||||
updateComposerHeight(idealHeight: newValue)
|
||||
}
|
||||
.onChange(of: viewModel.viewState.shouldDisplayContext) { _ in
|
||||
updateComposerHeight(idealHeight: wysiwygViewModel.idealHeight)
|
||||
}
|
||||
.task {
|
||||
updateComposerHeight(idealHeight: wysiwygViewModel.idealHeight)
|
||||
}
|
||||
}
|
||||
|
||||
private func storeCurrentSelection() {
|
||||
|
||||
@@ -59,10 +59,10 @@ packages:
|
||||
branch: 0.0.1
|
||||
WysiwygComposer:
|
||||
url: https://github.com/matrix-org/matrix-wysiwyg-composer-swift
|
||||
version: 2.2.2
|
||||
version: 2.18.0
|
||||
DeviceKit:
|
||||
url: https://github.com/devicekit/DeviceKit
|
||||
majorVersion: 4.7.0
|
||||
DTCoreText:
|
||||
url: https://github.com/Cocoanetics/DTCoreText
|
||||
version: 1.6.27
|
||||
version: 1.6.26
|
||||
|
||||
Reference in New Issue
Block a user