Merge remote-tracking branch 'origin/sc_beta' into sc
Change-Id: I61bf897abe30e5763047852bdc4128f6df3a1660
This commit is contained in:
commit
07a0d315f5
23
CHANGES.md
23
CHANGES.md
|
@ -1,3 +1,26 @@
|
|||
Changes in Element v1.5.30 (2023-04-05)
|
||||
=======================================
|
||||
|
||||
Features ✨
|
||||
----------
|
||||
- Permalinks to a room/space are pillified ([#8219](https://github.com/vector-im/element-android/issues/8219))
|
||||
- Permalinks to a matrix user are pillified ([#8220](https://github.com/vector-im/element-android/issues/8220))
|
||||
- Permalinks to messages are pillified ([#8221](https://github.com/vector-im/element-android/issues/8221))
|
||||
|
||||
Bugfixes 🐛
|
||||
----------
|
||||
- Custom sticker picker loads indefinitely ([#8026](https://github.com/vector-im/element-android/issues/8026))
|
||||
- Replace hardcoded colors by theming colors on save button. ([#8208](https://github.com/vector-im/element-android/issues/8208))
|
||||
- Add RTL support to RemoveJitsiWidgetView ([#8210](https://github.com/vector-im/element-android/issues/8210))
|
||||
- Add user completion for matrix ids ([#8217](https://github.com/vector-im/element-android/issues/8217))
|
||||
- Long name are truncated in the pills ([#8218](https://github.com/vector-im/element-android/issues/8218))
|
||||
- The read marker is stuck in the past ([#8268](https://github.com/vector-im/element-android/issues/8268))
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
- Replace Terms and Conditions with Acceptable Use Policy. ([#8286](https://github.com/vector-im/element-android/issues/8286))
|
||||
|
||||
|
||||
Changes in Element v1.5.28 (2023-03-08)
|
||||
=======================================
|
||||
|
||||
|
|
|
@ -24,13 +24,13 @@ buildscript {
|
|||
classpath libs.gradle.gradlePlugin
|
||||
classpath libs.gradle.kotlinPlugin
|
||||
classpath libs.gradle.hiltPlugin
|
||||
classpath 'com.google.firebase:firebase-appdistribution-gradle:3.2.0'
|
||||
classpath 'com.google.firebase:firebase-appdistribution-gradle:4.0.0'
|
||||
classpath 'com.google.gms:google-services:4.3.15'
|
||||
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929'
|
||||
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6'
|
||||
classpath "com.likethesalad.android:stem-plugin:2.3.0"
|
||||
classpath 'org.owasp:dependency-check-gradle:8.1.2'
|
||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.20"
|
||||
classpath 'org.owasp:dependency-check-gradle:8.2.1'
|
||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.8.10"
|
||||
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
|
||||
classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'
|
||||
classpath libs.squareup.paparazziPlugin
|
||||
|
|
|
@ -11,23 +11,23 @@ def gradle = "7.4.2"
|
|||
def kotlin = "1.8.10"
|
||||
def kotlinCoroutines = "1.6.4"
|
||||
def dagger = "2.45"
|
||||
def firebaseBom = "31.2.2"
|
||||
def firebaseBom = "31.4.0"
|
||||
def appDistribution = "16.0.0-beta06"
|
||||
def retrofit = "2.9.0"
|
||||
def markwon = "4.6.2"
|
||||
def moshi = "1.14.0"
|
||||
def lifecycle = "2.5.1"
|
||||
def flowBinding = "1.2.0"
|
||||
def flipper = "0.183.0"
|
||||
def flipper = "0.188.0"
|
||||
def epoxy = "5.0.0"
|
||||
def mavericks = "3.0.1"
|
||||
def mavericks = "3.0.2"
|
||||
def glide = "4.14.2"
|
||||
def bigImageViewer = "1.8.1"
|
||||
def jjwt = "0.11.5"
|
||||
def vanniktechEmoji = "0.16.0"
|
||||
def sentry = "6.15.0"
|
||||
def sentry = "6.17.0"
|
||||
// Use 1.6.0 alpha to fix issue with test
|
||||
def fragment = "1.6.0-alpha04"
|
||||
def fragment = "1.6.0-alpha08"
|
||||
// Testing
|
||||
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819
|
||||
def espresso = "3.5.1"
|
||||
|
@ -48,11 +48,11 @@ ext.libs = [
|
|||
'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
|
||||
],
|
||||
androidx : [
|
||||
'activity' : "androidx.activity:activity-ktx:1.6.1",
|
||||
'activity' : "androidx.activity:activity-ktx:1.7.0",
|
||||
'appCompat' : "androidx.appcompat:appcompat:1.6.1",
|
||||
'biometric' : "androidx.biometric:biometric:1.1.0",
|
||||
'core' : "androidx.core:core-ktx:1.9.0",
|
||||
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
|
||||
'recyclerview' : "androidx.recyclerview:recyclerview:1.3.0",
|
||||
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.6",
|
||||
'fragmentKtx' : "androidx.fragment:fragment-ktx:$fragment",
|
||||
'fragmentTesting' : "androidx.fragment:fragment-testing:$fragment",
|
||||
|
@ -87,7 +87,7 @@ ext.libs = [
|
|||
//'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution",
|
||||
//'appdistribution' : "com.google.firebase:firebase-appdistribution:$appDistribution",
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
'phonenumber' : "com.googlecode.libphonenumber:libphonenumber:8.13.7"
|
||||
'phonenumber' : "com.googlecode.libphonenumber:libphonenumber:8.13.8"
|
||||
],
|
||||
dagger : [
|
||||
'dagger' : "com.google.dagger:dagger:$dagger",
|
||||
|
@ -102,7 +102,7 @@ ext.libs = [
|
|||
],
|
||||
element : [
|
||||
'opusencoder' : "io.element.android:opusencoder:1.1.0",
|
||||
'wysiwyg' : "io.element.android:wysiwyg:1.1.1"
|
||||
'wysiwyg' : "io.element.android:wysiwyg:1.2.2"
|
||||
],
|
||||
squareup : [
|
||||
'moshi' : "com.squareup.moshi:moshi:$moshi",
|
||||
|
|
|
@ -39,6 +39,12 @@ ext.groups = [
|
|||
'com.google.testing.platform',
|
||||
]
|
||||
],
|
||||
snapshot: [
|
||||
regex: [
|
||||
],
|
||||
group: [
|
||||
]
|
||||
],
|
||||
mavenCentral: [
|
||||
regex: [
|
||||
],
|
||||
|
|
|
@ -880,7 +880,7 @@
|
|||
<string name="create_room_name_hint">Nom</string>
|
||||
<string name="create_room_public_title">Públic</string>
|
||||
<string name="create_room_public_description">Qualsevol podrà unir-se a aquesta sala</string>
|
||||
<string name="keys_backup_unable_to_get_trust_info">Hi ha hagut un error rebent informació de confança</string>
|
||||
<string name="keys_backup_unable_to_get_trust_info">S\'ha produït un error en obtenir la informació de confiança</string>
|
||||
<string name="keys_backup_unable_to_get_keys_backup_data">Hi ha hagut un error rebent dades de la còpia de seguretat de les claus</string>
|
||||
<string name="import_e2e_keys_from_file">Importa claus E2E des del fitxer \"%1$s\".</string>
|
||||
<string name="settings_sdk_version">Versió de l\'SDK de Matrix</string>
|
||||
|
@ -2848,4 +2848,39 @@
|
|||
<string name="notice_voice_broadcast_ended_by_you">Has finalitzat una emissió de veu.</string>
|
||||
<string name="notice_voice_broadcast_ended">%1$s a finalitzat una emissió de veu.</string>
|
||||
<string name="action_stop">Sí, atura</string>
|
||||
<string name="ended_poll_indicator">Ha finalitzat l\'enquesta.</string>
|
||||
<string name="room_polls_active">Enquestes actives</string>
|
||||
<string name="room_polls_active_no_item">No hi ha enquestes actives a la sala</string>
|
||||
<string name="room_polls_wait_for_display">Mostrant enquestes</string>
|
||||
<string name="room_polls_load_more">Carrega més enquestes</string>
|
||||
<string name="room_polls_loading_error">Error obtenint enquestes.</string>
|
||||
<string name="device_manager_verification_status_detail_session_encryption_not_supported">Aquesta sessió no admet xifrat i, per tant, no es pot verificar.</string>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Tanca sessió</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Tanca %1$d sessió</item>
|
||||
<item quantity="other">Tanca %1$d sessions</item>
|
||||
</plurals>
|
||||
<string name="device_manager_signout_all_other_sessions">Tanca totes les altres sessions</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Mostra l\'adreça IP</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Amaga l\'adreça IP</string>
|
||||
<string name="set_link_text">Text</string>
|
||||
<string name="set_link_link">Enllaç</string>
|
||||
<string name="set_link_create">Crea un enllaç</string>
|
||||
<string name="set_link_edit">Edita l\'enllaç</string>
|
||||
<string name="settings_access_token">\'Token\' d\'accés</string>
|
||||
<string name="message_reply_to_ended_poll_preview">Enquesta finalitzada</string>
|
||||
<string name="message_reply_to_poll_preview">Enquesta</string>
|
||||
<string name="message_reply_to_sender_ended_poll">ha finalitzat una enquesta.</string>
|
||||
<string name="message_reply_to_sender_created_poll">ha creat una enquesta.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">ha enviat un adhesiu.</string>
|
||||
<string name="message_reply_to_sender_sent_video">ha enviat un vídeo.</string>
|
||||
<string name="message_reply_to_sender_sent_image">ha enviat una imatge.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">ha enviat un missatge de veu.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">ha enviat un àudio.</string>
|
||||
<string name="message_reply_to_sender_sent_file">ha enviat un fitxer.</string>
|
||||
<string name="message_reply_to_prefix">En resposta a</string>
|
||||
<string name="unable_to_decrypt_some_events_in_poll">Per culpa d\'errors de desxifrat, és possible que alguns vots no s\'hagin comptat</string>
|
||||
<string name="error_voice_broadcast_unable_to_play">No es pot reproduir l\'emissió de veu.</string>
|
||||
<string name="error_voice_broadcast_unable_to_decrypt">No s\'ha pogut desxifrar l\'emissió de veu.</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Error de connexió - Enregistrament pausat</string>
|
||||
</resources>
|
|
@ -2688,7 +2688,7 @@
|
|||
<string name="onboarding_new_app_layout_welcome_title">Vítejte v novém zobrazení!</string>
|
||||
<string name="home_empty_no_unreads_message">Zde se zobrazí nepřečtené zprávy, pokud nějaké máte.</string>
|
||||
<string name="home_empty_no_unreads_title">Nic k nahlášení.</string>
|
||||
<string name="home_empty_no_rooms_message">Univerzální zabezpečená chatovací aplikace pro týmy, přátele a organizace. Vytvořte si chat nebo se připojte k existující místnosti a začněte.</string>
|
||||
<string name="home_empty_no_rooms_message">Univerzální zabezpečený komunikátor pro týmy, přátele a organizace. Vytvořte si chat nebo se připojte k existující místnosti a začněte.</string>
|
||||
<string name="home_empty_no_rooms_title">Vítejte v aplikaci ${app_name},
|
||||
\n%s.</string>
|
||||
<string name="home_empty_space_no_rooms_message">Prostory představují nový způsob seskupování místností a osob. Pomocí tlačítka vpravo dole můžete přidat stávající místnost nebo vytvořit novou.</string>
|
||||
|
@ -2989,4 +2989,7 @@
|
|||
<string name="settings_external_account_management">Údaje o vašem účtu jsou spravovány odděleně na adrese %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Účet</string>
|
||||
<string name="settings_notification_error_on_update">Při aktualizaci předvoleb oznámení došlo k chybě. Zkuste to prosím znovu.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Jakmile se pozvaní uživatelé připojí do aplikace ${app_name}, budete moci komunikovat a místnost bude koncově šifrovaná</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Čekání na uživatele, než se připojí do ${app_name}</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Můžete pozvat pouze jeden e-mail najednou</string>
|
||||
</resources>
|
|
@ -1249,7 +1249,7 @@
|
|||
<string name="room_member_power_level_moderators">Moderatoren</string>
|
||||
<string name="room_member_power_level_custom">Benutzerdefiniert</string>
|
||||
<string name="room_member_power_level_invites">Eingeladen</string>
|
||||
<string name="room_member_power_level_users">Nutzer</string>
|
||||
<string name="room_member_power_level_users">Benutzer</string>
|
||||
<string name="room_member_power_level_admin_in">Administrator in %1$s</string>
|
||||
<string name="room_member_power_level_moderator_in">Moderator in %1$s</string>
|
||||
<string name="room_member_jump_to_read_receipt">Springen und als gelesen markieren</string>
|
||||
|
@ -1859,7 +1859,7 @@
|
|||
<string name="re_authentication_activity_title">Erneute Authentifizierung erforderlich</string>
|
||||
<string name="failed_to_initialize_cross_signing">Quersignierung konnte nicht eingerichtet werden</string>
|
||||
<string name="error_unauthorized">Nicht autorisierte, fehlende gültige Authentifizierungsdaten</string>
|
||||
<string name="call_transfer_users_tab_title">Nutzer</string>
|
||||
<string name="call_transfer_users_tab_title">Benutzer</string>
|
||||
<string name="call_transfer_failure">Beim Weiterleiten des Anrufs ist ein Fehler aufgetreten</string>
|
||||
<string name="call_transfer_title">Weiterleiten</string>
|
||||
<string name="call_transfer_connect_action">Verbinden</string>
|
||||
|
@ -2928,4 +2928,7 @@
|
|||
<string name="settings_external_account_management_title">Konto</string>
|
||||
<string name="settings_external_account_management">Deine Kontodetails werden separat verwaltet bei %1$s.</string>
|
||||
<string name="settings_notification_error_on_update">Ein Fehler ist während der Aktualisierung deiner Benachrichtigungseinstellungen aufgetreten. Bitte versuche es erneut.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Sobald eingeladene Benutzer ${app_name} beigetreten sind, werdet ihr euch unterhalten können und der Raum Ende-zu-Ende-verschlüsselt sein</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Warte darauf, dass Benutzer ${app_name} beitreten</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Du kannst E-Mail-Einladung nur nacheinander verschicken</string>
|
||||
</resources>
|
|
@ -2920,4 +2920,16 @@
|
|||
<string name="rich_text_editor_quote">Lülita tsiteerimine sisse/välja</string>
|
||||
<string name="rich_text_editor_code_block">Lülita koodiblokk sisse/välja</string>
|
||||
<string name="settings_notification_error_on_update">Sinu teavituste seadistuste muutmisel tekkis viga. Palu proovi uuesti.</string>
|
||||
<string name="settings_troubleshoot_test_current_endpoint_failed">Lõppsõlme ei õnnestu leida.</string>
|
||||
<string name="settings_troubleshoot_test_current_endpoint_success">Hetkel kasutatav lõppsõlm: %s</string>
|
||||
<string name="settings_troubleshoot_test_current_endpoint_title">Lõppsõlm</string>
|
||||
<string name="settings_troubleshoot_test_endpoint_registration_failed">Lõppsõlme tunnusloa registreerimine koduserveris ei õnnestunud:
|
||||
\n%1$s</string>
|
||||
<string name="settings_troubleshoot_test_endpoint_registration_success">Lõppsõlme registreerimine koduserveris õnnestus.</string>
|
||||
<string name="settings_troubleshoot_test_endpoint_registration_title">Lõppsõlme registreerimine</string>
|
||||
<string name="settings_troubleshoot_test_current_gateway_title">Lüüs</string>
|
||||
<string name="settings_troubleshoot_test_current_gateway">Praegune lüüs: %s</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">E-posti teel saad saata kutseid vaid ükshaaval</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Kasutajate liitumise ootel ${app_name} või mõnes muud ühilduvas rakenduses</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Kui kutse saanud kasutajad on liitunud jututoaga ${app_name}, siis saad sa nendega suhelda ja jututuba on läbivalt krüptitud</string>
|
||||
</resources>
|
|
@ -1229,7 +1229,7 @@
|
|||
<string name="settings_troubleshoot_diagnostic_running_status">در حال اجرا (%1$d از %2$d)</string>
|
||||
<string name="settings_troubleshoot_diagnostic_run_button_title">تستها را اجرا کن</string>
|
||||
<string name="settings_troubleshoot_diagnostic">در حال تشخیص مشکل</string>
|
||||
<string name="error_threepid_auth_failed">مطمئن شوید لینک فعالسازیای را که به ایمیل شما ارسال شده، باز کردهاید.</string>
|
||||
<string name="error_threepid_auth_failed">مطمئن شوید روی پیوند درون رایانامهای که بهتان فرستادهایم زدهاید.</string>
|
||||
<string name="settings_remove_three_pid_confirmation_content">برداشتن %s؟</string>
|
||||
<string name="settings_phone_numbers">شماره تلفنها</string>
|
||||
<string name="settings_emails_empty">هیچ نشانی رایانامهای به حسابتان افزوده نشده</string>
|
||||
|
@ -1303,12 +1303,12 @@
|
|||
<string name="bootstrap_dont_reuse_pwd">ترجیحا از گذرواژه حساب خود استفاده نکنید.</string>
|
||||
<string name="verify_not_me_self_verification">ممکن است یکی از موارد زیر به خطر افتادهباشد:
|
||||
\n
|
||||
\n- گذرواژه شما
|
||||
\n- سرور شما
|
||||
\n- این دستگاه یا دستگاه دیگر
|
||||
\n- اتصال اینترنت دستگاه
|
||||
\n- گذرواژهتان
|
||||
\n- کارساز خانکیتان
|
||||
\n- این افزاره یا افزارهٔ دیگر
|
||||
\n- اتّصال اینترنتی هر یک از افزارهها
|
||||
\n
|
||||
\nما توصیه میکنیم گذرواژه و کلید بازیابی خود را بلافاصله در تنظیمات تغییر دهید.</string>
|
||||
\nتوصیه میکنیم فوراً گذرواژه و کلید بازیابیتان را در تنظیمات تغییر دهید.</string>
|
||||
<string name="verify_cancel_other">اگر اکنون انصراف دهید، %1$s (%2$s) را تأیید نخواهید کرد. دوباره در نمایهاش آغاز کنید.</string>
|
||||
<string name="verify_cancel_self_verification_from_trusted">اگر لغو کنید، نمی توانید پیام های رمزگذاری شده را در دستگاه جدید خود بخوانید و سایر کاربران به آن اعتماد نخواهند کرد</string>
|
||||
<string name="verify_cancel_self_verification_from_untrusted">در صورت لغو ، نمی توانید پیام های رمزشده را در این دستگاه بخوانید و سایر کاربران به آن اعتماد نخواهند کرد</string>
|
||||
|
@ -1341,19 +1341,19 @@
|
|||
<string name="room_settings_enable_encryption">به کار انداختن رمزنگاری سرتاسری…</string>
|
||||
<string name="command_description_rainbow_emote">شکلک را با رنگبندی رنگین گمان ارسال می کند</string>
|
||||
<string name="command_description_rainbow">پیام را با رنگبندی رنگین کمان ارسال می کند</string>
|
||||
<string name="verify_cannot_cross_sign">این نشست نمیتواند تائید را با نشستهای دیگر شما به اشتراک بگذارد.
|
||||
\nتائید به صورت محلی ذخیره میشود و در نسخهی بعدی برنامه به اشتراک گذاشته میشود.</string>
|
||||
<string name="verify_cannot_cross_sign">این نشست نمیتواند این تائید را با دیگر نشستهایتان همرسانی کند.
|
||||
\nتائید به صورت محلی ذخیره شده و در نگارشی جدیدتر از کاره همرسانی خواهد شد.</string>
|
||||
<string name="rendering_event_error_exception">المنت هنگام ارائه محتوای رویدادی با شناسه \'%1$s\' با مشکل روبرو شد</string>
|
||||
<string name="rendering_event_error_type_of_event_not_handled">المنت رویداد \'%1$s\' را پشتیبانی نمیکند</string>
|
||||
<string name="verification_conclusion_compromised">ممکن است یکی از موارد زیر به خطر افتاده باشد:
|
||||
\n
|
||||
\n- سرور میزبان شما
|
||||
\n- سرور کاربری که او را تائید میکنید
|
||||
\n- اتصال اینترنت شما یا کاربران دیگر
|
||||
\n- دستگاه شما یا دستگاه سایر کاربران</string>
|
||||
\n- کارساز خانگیتان
|
||||
\n- کارساز خانگی کاربری که دارید تائیدش میکنید
|
||||
\n- اتّصال اینترنتی شما یا دیگر کاربران
|
||||
\n- افزارهٔ شما یا دیگر کاربران</string>
|
||||
<string name="login_error_threepid_denied">دامنهٔ رایانامهتان مجاز به ثبتنام روی این کارساز نیست</string>
|
||||
<string name="command_description_shrug">¯\\\\_(ツ)_/¯ را به یک پیام متنی ساده تغییر می دهد</string>
|
||||
<string name="permalink_malformed">لینک مشکل دارد</string>
|
||||
<string name="permalink_malformed">پیوند matrix.toتان بدریخت است</string>
|
||||
<string name="soft_logout_sso_not_same_user_error">نشست فعلی مربوط به کاربر %1$s است و شما اطلاعات حساب کاربر %2$s را ارائه دادهاید. این مورد توسط المنت پشتیبانی نمیشود .
|
||||
\nلطفا ابتدا داده ها را پاک کنید، سپس با یک حساب دیگر وارد برنامه شوید.</string>
|
||||
<string name="soft_logout_clear_data_dialog_e2e_warning_content">دسترسی به پیامهای رمزشده را از دست خواهید داد مگر اینکه برای بازیابی کلیدهای رمزگذاری خود، به حساب خود وارد شوید.</string>
|
||||
|
@ -1364,13 +1364,13 @@
|
|||
\nاگر کارتان با این افزاره تمام شده یا میخواهید به حساب دیگری وارد شوید، پاکشان کنید.</string>
|
||||
<string name="soft_logout_signin_e2e_warning_notice">برای بازیابی کلیدهای رمزگذاری ذخیره شده در این دستگاه، وارد حساب خود شوید. شما برای خواندن همه پیامهای رمزشدهی خود در هر دستگاهی به این کلیدها نیاز دارید.</string>
|
||||
<string name="soft_logout_signin_notice">مدیر کارساز خانگیتان (%1$s) شما (%2$s) را از حسابتان (%3$s) خارج کرد.</string>
|
||||
<string name="signed_out_notice">این می تواند به دلایل مختلف باشد:
|
||||
<string name="signed_out_notice">میتواند به دلایل مختلفی باشد:
|
||||
\n
|
||||
\n• شما گذرواژه خود را در نشست دیگری تغییر دادهاید.
|
||||
\n• گذرواژهتان را در نشستی دیگر تغییر دادهاید.
|
||||
\n
|
||||
\n• این نشست را در یکی از نشست دیگر خود حذف کردهاید.
|
||||
\n• این نشست را از نشستی دیگر حذف کردهاید.
|
||||
\n
|
||||
\n• ادمین سرور حساب شما را غیرفعال کردهاست.</string>
|
||||
\n• مدیر کارسازتان دسترسی حسابتان را به دلایل امنیت نامعتبر کرده.</string>
|
||||
<string name="autodiscover_well_known_error">ناتوان در یافتن یک کارساز خانگی معتبر. لطفاً شناسهتان را بررسی کنید</string>
|
||||
<string name="login_signin_matrix_id_error_invalid_matrix_id">این یک شناسه کاربری معتبر نیست. قالب صحیح: \\\'@user:homeserver.org\\\'</string>
|
||||
<string name="login_signin_matrix_id_password_notice">اگر گذرواژه خود را نمیدانید، برای تنظیم مجدد آن بازگردید.</string>
|
||||
|
@ -1379,19 +1379,19 @@
|
|||
<item quantity="one">درخواست های زیادی ارسال شده است. می توانید در %1$d ثانیه دوباره امتحان کنید…</item>
|
||||
<item quantity="other">درخواست های زیادی ارسال شده است. می توانید در %1$d ثانیه دوباره امتحان کنید…</item>
|
||||
</plurals>
|
||||
<string name="login_error_outdated_homeserver_warning_content">این نسخه سرور بسیار قدیمی است. از ادمین خود بخواهید که آن را ارتقا دهد. البته شما میتوانید ادامه دهید ، اما برخی از ویژگی ها ممکن است به درستی کار نکنند.</string>
|
||||
<string name="login_error_outdated_homeserver_warning_content">این کارساز خانگی نگارشی قدیمی را اجرا میکند. از مدیر درخواست ارتقا کنید. میتوانید ادامه دهید؛ گرچه ممکن است برخی ویژگیها درست کار نکنند.</string>
|
||||
<string name="login_error_outdated_homeserver_title">کارساز خانگی قدیمی</string>
|
||||
<string name="login_validation_code_is_not_correct">کد وارد شده صحیح نیست. لطفا بررسی فرمائید.</string>
|
||||
<string name="login_wait_for_email_notice">ما ایمیلی به %1$s ارسال کردیم.
|
||||
\nلطفاً برای ادامه فرآیند ایجاد حسابکاربری بر روی لینک موجود در آن کلیک کنید.</string>
|
||||
<string name="login_wait_for_email_title">لطفا ایمیل خود را بررسی کنید</string>
|
||||
<string name="login_wait_for_email_notice">رایانامهای به %1$s فرستادیم.
|
||||
\nلطفاً برای ادامهٔ ایجاد حساب، پیوند درونش را بزنید.</string>
|
||||
<string name="login_wait_for_email_title">لطفاً رایانامهتان را بررسی کنید</string>
|
||||
<string name="login_terms_title">برای ادامه، شرایط را قبول کنید</string>
|
||||
<string name="login_a11y_captcha_container">لطفا کپچا را حل کنید</string>
|
||||
<string name="login_a11y_choose_other">گزینش یک کارساز خانگی سفارشی</string>
|
||||
<string name="login_a11y_choose_modular">گزینش خدمات ماتریکس المنت</string>
|
||||
<string name="login_a11y_choose_matrix_org">انتخاب matrix.org</string>
|
||||
<string name="login_signup_cancel_confirmation_content">حسابتان هنوز ایجاد نشده. توقّف فرآیند ثبتنام؟</string>
|
||||
<string name="login_signin_username_hint">نامکاربری یا ایمیل</string>
|
||||
<string name="login_signin_username_hint">نامکاربری یا رایانامه</string>
|
||||
<string name="login_signup_to">ثبت نام در %1$s</string>
|
||||
<string name="login_msisdn_error_other">شماره تلفن نامعتبر است. لطفا آن را بررسی کنید</string>
|
||||
<string name="login_msisdn_confirm_notice">ما یک کد فعالسازی به %1$s ارسال کردیم. لطفا آن را وارد کنید.</string>
|
||||
|
@ -1401,28 +1401,28 @@
|
|||
\n
|
||||
\nفرآیند تغییر گذرواژه را متوقف میکنید؟</string>
|
||||
<string name="login_reset_password_success_notice_2">از تمام نشستها خارج شده و دیگر آگاهیای دریافت نخواهید کرد. برای به کار انداختن دوبارهٔ آگاهیها، روی هر دستگاهی، دوباره وارد شوید.</string>
|
||||
<string name="login_reset_password_mail_confirmation_submit">ایمیل را تایید کردم</string>
|
||||
<string name="login_reset_password_mail_confirmation_notice_2">برای تایید گذرواژه جدید لینک ارسالی را باز کرده، سپس روی متن زیر کلیک کنید.</string>
|
||||
<string name="login_reset_password_mail_confirmation_notice">یک ایمیل تائید به %1$s ارسال شد.</string>
|
||||
<string name="login_reset_password_mail_confirmation_title">صندوق ایمیل خود را بررسی کنید</string>
|
||||
<string name="login_reset_password_mail_confirmation_submit">نشانی رایانامهام را تأیید کردهام</string>
|
||||
<string name="login_reset_password_mail_confirmation_notice_2">برای تأیید گذرواژهٔ جدیدتان روی پیوند بزنید. پس از پیروی از پیوند درونش، پایین را بزنید.</string>
|
||||
<string name="login_reset_password_mail_confirmation_notice">رایانامهٔ تأییدی به %1$s فرستاده شد.</string>
|
||||
<string name="login_reset_password_mail_confirmation_title">صندوق ورودیتان را بررسی کنید</string>
|
||||
<string name="login_reset_password_error_not_found">این نشانی رایانامه به هیچ حسابی پیوند داده نشده</string>
|
||||
<string name="login_reset_password_warning_content">با تغییر گذرواژه ، کلیدهای رمزگذاری سرتاسر در تمام نشستهای شما تغییر کرده و تاریخچه گفتگوی رمزشدهی شما غیرقابل خواندن میشود. قبل از تغییر گذرواژه، کلید امنیتی یا کلید پشتیبان را وارد کرده و یا کلیدهای اتاق خود را از نشست دیگری استخراج کنید.</string>
|
||||
<string name="login_reset_password_submit">بعدی</string>
|
||||
<string name="login_reset_password_notice">برای تأیید تنظیم گذرواژهی جدید ، یک ایمیل تأیید به آدرس ایمیل شما ارسال خواهد شد.</string>
|
||||
<string name="login_reset_password_notice">برای تأیید تنظیم گذرواژهٔ جدیدتان رایانامهٔ تأییدی به صندوق وردیتان فرستاده خواهد شد.</string>
|
||||
<string name="login_reset_password_on">بازنشانی گذرواژه در %1$s</string>
|
||||
<string name="login_login_with_email_error">این نشانی رایانامه به هیچ حسابی مرتبط نیست.</string>
|
||||
<string name="login_registration_not_supported">برنامه قادر به ایجاد حساب در این سرور نیست.
|
||||
<string name="login_registration_not_supported">برنامه قادر به ایجاد حساب روی این کارساز خانگی نیست.
|
||||
\n
|
||||
\nآیا می خواهید با استفاده از مرورگر حساب کاربری بسازید؟</string>
|
||||
\nمیخواهید با یک کارخواه وب ثبت نام کنید؟</string>
|
||||
<string name="login_registration_disabled">متأسفانه این کارساز، حساب جدید نمیپذیرد.</string>
|
||||
<string name="login_mode_not_supported">برنامه نمیتواند به این سرور متصل شود. سرور از این مکانیزم(ها) برای ورود پشتیبانی می کند: %1$s.
|
||||
<string name="login_mode_not_supported">برنامه قادر به ورود به این کارساز خانگی نیست. کارساز خانگی از گونههای ورود زیر پشتیبانی می کند: %1$s.
|
||||
\n
|
||||
\nآیا می خواهید با استفاده از مرورگر وارد شوید؟</string>
|
||||
\nمیخواهید با یک کارخواه وب وارد شوید؟</string>
|
||||
<string name="login_sso_error_message">هنگام بارگیری صفحه، خطایی روی داد: %1$s (%2$d)</string>
|
||||
<string name="login_server_url_form_common_notice">نشانی کارسازی که میخواهید استفاده کنید را وارد کنید</string>
|
||||
<string name="login_server_url_form_modular_notice">نشانی کارساز یا المنت ماژولاری که میخواهید استفاده کنید را وارد کنید</string>
|
||||
<string name="login_server_matrix_org_text">به میلیونها نفر در بزرگترین کارساز عمومی بپیوندید</string>
|
||||
<string name="login_server_text">درست مانند ایمیل، حسابهای کاربری یک خانه دارند؛ اگرچه می توانید با هر کسی که دوست دارید، صحبت کنید</string>
|
||||
<string name="login_server_text">درست مانند رایانامه، حسابها یک خانه دارند؛ گرچه می توانید با هر کسی صحبت کنید</string>
|
||||
<string name="login_server_title">کارسازی برگزینید</string>
|
||||
<string name="login_splash_submit">شروع کنید</string>
|
||||
<string name="login_splash_text3">تجربههایتان را گسترش داده و شخصیسازی کنید</string>
|
||||
|
@ -1434,8 +1434,8 @@
|
|||
<string name="direct_room_join_rules_invite">%1$s اتاق را به گونهای تنظیم کرده که تنها افراد با دعوت بتوانند به اتاق بپیوندند.</string>
|
||||
<string name="room_join_rules_invite_by_you">شما اتاق را به گونهای تنظیم کردهاید که تنها افراد با دعوت بتوانند به اتاق بپیوندند.</string>
|
||||
<string name="room_join_rules_invite">%1$s اتاق را به گونهای تنظیم کردهاست که تنها اعضا با دعوت بتوانند به اتاق بپیوندند.</string>
|
||||
<string name="room_join_rules_public_by_you">شما اتاق را برای هر فردی که لینک آن را دارد عمومی کردید.</string>
|
||||
<string name="room_join_rules_public">%1$s اتاق را برای هر کس که لینک آن را دارد، عمومی کن.</string>
|
||||
<string name="room_join_rules_public_by_you">اتاق را برای هرکسی که پیوندش را دارد عمومی کردید.</string>
|
||||
<string name="room_join_rules_public">%1$s اتاق را برای هرکسی که پیوندش را دارد عمومی کرد.</string>
|
||||
<string name="help_long_click_on_room_for_more_options">برای دیدن گزینههای بیشتر، روی یک اتاق کلیک طولانی کنید</string>
|
||||
<string name="spoiler">تباهکننده</string>
|
||||
<string name="command_description_spoiler">ارسال به عنوان پیام تباهکننده</string>
|
||||
|
@ -1470,21 +1470,21 @@
|
|||
<string name="a11y_create_menu_open">گشودن فهرست ایجاد اتاق</string>
|
||||
<string name="a11y_open_drawer">کشوی پیمایش را باز کنید</string>
|
||||
<string name="send_attachment">ارسال ضمیمه</string>
|
||||
<string name="error_network_timeout">به نظر می رسد پاسخگویی سرور بسیار طولانی شدهاست، این امر میتواند به دلیل اتصال ضعیف یا خطای موجود در سرور باشد. لطفا پس از مدتی دوباره امتحان کنید.</string>
|
||||
<string name="error_terms_not_accepted">لطفاً هنگامی که شرایط و ضوابط سرور خود را پذیرفتید، دوباره امتحان کنید.</string>
|
||||
<string name="settings_agree_to_terms">با شرایط خدمات سرور هویتسنجی (%s) موافقت کنید تا بتوانید از طریق آدرس ایمیل یا شماره تلفن قابل پیدا شدن باشید.</string>
|
||||
<string name="settings_discovery_disconnect_with_bound_pid">شما در حال حاضر آدرسهای ایمیل یا شماره تلفنها را در سرور هویتسنجی %1$s به اشتراک می گذارید. برای توقف اشتراک آنها باید دوباره به %2$s متصل شوید.</string>
|
||||
<string name="error_network_timeout">به نظر کارساز بیش از حد برای پاسخ وقت میگیرد. این امر میتواند ناشی از اتّصال ضعیف یا خطایی در کارساز باشد. لطفاً پس از مدتی دوباره تلاش کنید.</string>
|
||||
<string name="error_terms_not_accepted">لطفاً پس از پذیرش شرایط و ضوابط کارساز خانگیتان دوباره تلاش کنید.</string>
|
||||
<string name="settings_agree_to_terms">برای قابل کشف بودن با نشانی رایانامه یا شماره تلفن با شرایط خدمت کارساز هویت (%s) موافقت کنید.</string>
|
||||
<string name="settings_discovery_disconnect_with_bound_pid">دارید نشانیهای رایانامه یا شمارههای تلفن را روی کارساز هویت %1$s همرسانی میکنید برای توقّف همرسانیشان باید دوباره به %2$s وصل شوید.</string>
|
||||
<string name="settings_text_message_sent_wrong_code">کد تائید صحیح نیست.</string>
|
||||
<string name="settings_text_message_sent_hint">کد</string>
|
||||
<string name="settings_text_message_sent">پیامکی به %s ارسال شده است. لطفاً کد تأیید موجود در آن را وارد کنید.</string>
|
||||
<string name="settings_discovery_no_terms">سرور هویتسنجیای که انتخاب کردهاید هیچگونه شرایط و ضوابطی ندارد. فقط اگر به صاحب سرویس اعتماد دارید ادامه دهید</string>
|
||||
<string name="settings_discovery_no_terms">کارساز هویت گزیدهتان هیچ شرایط خدمتی ندارد. تنها اگر به صاحب خدمت اعتماد دارید ادامه دهید</string>
|
||||
<string name="settings_discovery_no_terms_title">کارساز هویت، شرایط و ضوابط استفاده ندارد</string>
|
||||
<string name="settings_discovery_please_enter_server">لطفاً نشانی کارساز هویت را وارد کنید</string>
|
||||
<string name="settings_discovery_bad_identity_server">نتوانست به کارساز هویت وصل شود</string>
|
||||
<string name="settings_discovery_enter_identity_server">یک نشانی کارساز هویت وارد کنید</string>
|
||||
<string name="settings_discovery_confirm_mail_not_clicked">رایانامهای به %s فرستادیم. لطفاً نخست رایانامهتان را بررسی کرده و روی پیوند تأیید کلیک کنید</string>
|
||||
<string name="settings_discovery_confirm_mail">رایانامهای به %s فرستادیم. رایانامهتان را بررسی کرده و روی پیوند تأیید کلیک کنید</string>
|
||||
<string name="settings_discovery_disconnect_identity_server_info">قطع ارتباط با سرور هویتسنجی به این معنی است که توسط کاربران دیگر قابل شناسایی نخواهید بود و نمی توانید دیگران را از طریق ایمیل یا تلفن دعوت کنید.</string>
|
||||
<string name="settings_discovery_disconnect_identity_server_info">قطع شدن ازکارساز هویت به معنی قابل کشف نبودنتان به دست دیگر کابران است و نخواهید توانست دیگران را با رایانامه یا تلفن دعوت کنید.</string>
|
||||
<string name="settings_discovery_identity_server_info_none">در حال استفاده از کارساز هویتی نیستید. برای کشق و قابل کشف بودن به دست آشنایان موجودی که میشناسید، یک کارساز هویت در زیر پیکربندی کنید.</string>
|
||||
<string name="settings_discovery_identity_server_info">دارید برای کشف و قابل کشف بودن به دست آشنایان موجودی که میشناسید از %1$s استفاده میکنید.</string>
|
||||
<string name="settings_troubleshoot_test_token_registration_quick_fix">ثبت ژتون</string>
|
||||
|
@ -1526,7 +1526,7 @@
|
|||
<string name="keys_backup_banner_in_progress">پشتیبانگیری از کلیدهای شما. این ممکن است چند دقیقه طول بکشد…</string>
|
||||
<string name="keys_backup_banner_update_line2">مدیریت در بخش پشتیبانگیری از کلید</string>
|
||||
<string name="keys_backup_banner_update_line1">کلیدهای رمزگذاری جدید</string>
|
||||
<string name="keys_backup_settings_delete_confirm_message">کلیدهای رمزگذاری پشتیبان شما از سرور حذف شوند؟ در اینن صورت دیگر نخواهید توانست از کلید بازیابی خود برای خواندن پیام رمزشدهی قبلی خود استفاده کنید.</string>
|
||||
<string name="keys_backup_settings_delete_confirm_message">حذف کلیدهای رمزنگاری پشتیبان گرفته از کارساز؟ دیگر قادر به استفاده از کلید بازیابیتان برای خواندن تاریخچهٔ پیامهای رمزشدهتان نخواهید بود.</string>
|
||||
<string name="keys_backup_settings_delete_confirm_title">حذف نسخهی پشتیبان</string>
|
||||
<string name="keys_backup_settings_checking_backup_state">در حال بررسی وضعیت نسخهی پشتیبان</string>
|
||||
<string name="keys_backup_settings_deleting_backup">در حال حذف نسخهی پشتیبان…</string>
|
||||
|
@ -1571,9 +1571,9 @@
|
|||
\nکلید بازیابی خود را در جایی بسیار امن نظیر برنامههای شناختهشدهی مدیریت گذرواژه نگه دارید</string>
|
||||
<string name="keys_backup_setup_step3_text_line1">درحال پشتیبانگیری از کلیدهای شما.</string>
|
||||
<string name="keys_backup_setup_step1_recovery_key_alternative">یا، نسخهی پشتیبان خود را با یک کلید بازیابی ایمن کنید، و آن را در جایی امن ذخیره کنید.</string>
|
||||
<string name="keys_backup_setup_step2_text_description">ما یک نسخه رمزگذاری شده از کلیدهای شما را در سرور ذخیره خواهیم کرد. با استفاده از کلید امنیتی قوی، از نسخهی پشتیبان خود محافظت کنید.
|
||||
<string name="keys_backup_setup_step2_text_description">نگارشی رمز شده از کلیدهایتان را روی کارساز خانگیتان ذخیره خواهیم کرد. برای امن نگه داشنتن پشتیبانتان با عبارت عبوری محافظتش کنید.
|
||||
\n
|
||||
\nبرای حداکثر امنیت، کلید امنیتی باید با رمز ورود حساب شما متفاوت باشد.</string>
|
||||
\nبرای امنیت بیشینه باید با گذرواژهٔ حسابتان فرق داشته باشد.</string>
|
||||
<string name="keys_backup_setup_step1_description">پیامها در اتاقهای رمزشده، با رمزنگاری سرتاسری امن شدهاند. فقط شما و گیرنده(ها) کلیدهای خواندم این پیامها را دارید.
|
||||
\n
|
||||
\nبرای جلوگیری از گم کردن کلیدهایتان، از آنها به صورت امن، پشتیبان بگیرید.</string>
|
||||
|
@ -1656,8 +1656,8 @@
|
|||
<string name="settings_media">رسانه</string>
|
||||
<string name="settings_select_country">گزینش یک کشور</string>
|
||||
<string name="account_phone_number_already_used_error">این شماره تلفن قبلا استفاده شدهاست.</string>
|
||||
<string name="account_email_already_used_error">این آدرس ایمیل قبلا استفاده شدهاست.</string>
|
||||
<string name="account_email_validation_message">لطفاً ایمیل خود را بررسی کنید و روی لینک ارسال شده، کلیک کنید. پس از انجام این کار، روی ادامه کلیک کنید.</string>
|
||||
<string name="account_email_already_used_error">این نشانی رایانامه در حال استفاده است.</string>
|
||||
<string name="account_email_validation_message">لطفاً رایانامهتان را بررسی کرده رو روی پیوند درونش بزنید. پس از این کار، ادامه را بزنید.</string>
|
||||
<string name="disabled_integration_dialog_content">برای انجام این کار اجازهی یکپارچهسازی را در تنظیمات فعال کنید.</string>
|
||||
<string name="disabled_integration_dialog_title">یکپارچهسازیها غیر فعال هستند</string>
|
||||
<string name="devices_details_last_seen_format">%1$s @ %2$s</string>
|
||||
|
@ -1736,7 +1736,7 @@
|
|||
<string name="permissions_denied_qr_code">برای پویش یک رمز QR نیاز است دسترسی به دوربین را مجاز کنید.</string>
|
||||
<string name="start_chatting">آغاز به گپ</string>
|
||||
<string name="settings_export_trail">برونریزی بازرسی</string>
|
||||
<string name="create_room_disable_federation_description">اگر اتاق فقط برای تعامل با افراد داخل سرور خانه شما میباشد، این قابلیت را فعال کنید. این تنظیم را بعدا نمیتوانید تغییر دهید.</string>
|
||||
<string name="create_room_disable_federation_description">اگر اتاق فقط برای تعامل با گروههای داخلی روی کارساز خانگیتان است، این قابلیت را به کار بیندازید. بعداُ قابل تغییر نیست.</string>
|
||||
<string name="bottom_sheet_setup_secure_backup_security_key_subtitle">یک کلید امنیتی ایجاد کنید تا در مکانی امن مانند سامانه مدیریت رمز عبور یا گاوصندوق آن را ذخیره کنید.</string>
|
||||
<string name="identity_server_error_no_current_binding_error">ارتباطی با این شناسه وجود ندارد.</string>
|
||||
<string name="confirm_your_identity_quad_s">هویت خود را تأیید کنید تا به پیامهای رمز شده دسترسی پیدا کنید.</string>
|
||||
|
@ -1877,10 +1877,10 @@
|
|||
<item quantity="other">%d ورودی</item>
|
||||
</plurals>
|
||||
<string name="settings_server_upload_size_unknown">این محدودیت ناشناخته است.</string>
|
||||
<string name="settings_server_upload_size_content">سرور شما فایلهای ضمیمه (پروندهها، فایلهای چندرسانهای و غیره) تا حجم %s را میپذیرد.</string>
|
||||
<string name="settings_server_upload_size_title">محدودیت بارگذاری فایل بر روی سرور</string>
|
||||
<string name="settings_server_version">ورژن سرور</string>
|
||||
<string name="settings_server_name">نام سرور</string>
|
||||
<string name="settings_server_upload_size_content">کارساز خانگیتان پیوست(پروندهها، رسانه و…) را تا %s میپذیرد.</string>
|
||||
<string name="settings_server_upload_size_title">کران بارگذاری پروندهٔ کارساز</string>
|
||||
<string name="settings_server_version">نگارش کارساز</string>
|
||||
<string name="settings_server_name">نام کارساز</string>
|
||||
<string name="room_list_quick_actions_room_settings">تنظیمات اتاق</string>
|
||||
<string name="jitsi_leave_conf_to_join_another_one_content">آیا مایل به ترک جلسهی فعلی و ورود به جلسهی دیگری هستید؟</string>
|
||||
<string name="room_settings_room_version_title">ورژن اتاق</string>
|
||||
|
@ -1962,8 +1962,8 @@
|
|||
<string name="invite_just_to_this_room">فقط به این اتاق</string>
|
||||
<string name="invite_to_space_with_name_desc">آنها قادر به کاوش در %s خواهند بود</string>
|
||||
<string name="invite_to_space_with_name">دعوت به %s</string>
|
||||
<string name="invite_by_link">به اشتراکگذاری لینک</string>
|
||||
<string name="invite_by_email">دعوت با ایمیل</string>
|
||||
<string name="invite_by_link">همرسانی پیوند</string>
|
||||
<string name="invite_by_email">دعوت با رایانامه</string>
|
||||
<string name="invite_people_to_your_space_desc">در حال حاضر فقط شما هستید. %s با دیگران حتی بهتر خواهد بود.</string>
|
||||
<string name="invite_people_menu">دعوت افراد</string>
|
||||
<string name="invite_people_to_your_space">دعوت افراد به فضایتان</string>
|
||||
|
@ -2929,4 +2929,7 @@
|
|||
<string name="error_voice_broadcast_unable_to_decrypt">ناتوان در رمزگشایی این پخش صوتی.</string>
|
||||
<string name="settings_external_account_management">جزییات حسابتان جداگانه در %1$s مدیریت میشود.</string>
|
||||
<string name="settings_notification_error_on_update">هنگام بهروز رسانی ترجیحات آگاهیتان خطایی رخ داد. لطفاً دوباره تلاش کنید.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">به محض پیوستن کاربران دعوت شده، قادر به گپ خواهید بود و اتاق رمزنگاری سرتاسری میشود</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">منتظر پیوستن کاربران به ${app_name}</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">در هر زمان تنها میتوانید یک رایانامه را دعوت کنید</string>
|
||||
</resources>
|
|
@ -2929,4 +2929,7 @@
|
|||
<string name="settings_external_account_management">Les détails de votre compte sont gérés séparément sur %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Compte</string>
|
||||
<string name="settings_notification_error_on_update">Nous avons rencontré une erreur lors de la mise-à-jour de vos préférences de notification. Veuillez réessayer.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Une fois que les utilisateurs invités seront connectés sur ${app_name}, vous pourrez discuter et le salon sera chiffré de bout en bout</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">En attente de la connexion des utilisateurs sur ${app_name}</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Vous ne pouvez envoyer qu’une seule invitation par e-mail à la fois</string>
|
||||
</resources>
|
|
@ -2929,4 +2929,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
|
|||
<string name="settings_external_account_management">A fiókadatok külön vannak kezelve itt: %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Fiók</string>
|
||||
<string name="settings_notification_error_on_update">Hiba történt az értesítések beállításának frissítésekor. Próbáld újra.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Miután a meghívott felhasználók csatlakoztak a(z) ${app_name} alkalmazáshoz, beszélhetsz velük és a szoba végpontok között titkosítva lesz</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">${app_name} alkalmazáshoz csatlakozó emberekre várakozás</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">E-mail meghívóból egyszerre csak egy küldhető</string>
|
||||
</resources>
|
|
@ -2871,4 +2871,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
|
|||
<string name="settings_external_account_management">Detail akun Anda dikelola secara terpisah di %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Akun</string>
|
||||
<string name="settings_notification_error_on_update">Terjadi kesalahan saat memperbarui preferensi notifikasi Anda. Silakan coba lagi.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Ketika pengguna yang diundang trlah bergabung ${app_name}, Anda akan dapat mengobrol dan ruangannya akan terenkripsi secara ujung ke ujung</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Menunggu pengguna untuk bergabung ${app_name}</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Amda hanya dapat mengundang satu surel satu-satu</string>
|
||||
</resources>
|
|
@ -2920,4 +2920,7 @@
|
|||
<string name="settings_external_account_management">I dettagli del tuo account sono gestiti separatamente su %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Account</string>
|
||||
<string name="settings_notification_error_on_update">Si è verificato un errore aggiornando le tue preferenze di notifica. Riprova.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Una volta che gli utenti si saranno uniti a ${app_name}, potrete scrivervi e la stanza sarà crittografata end-to-end</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">In attesa che gli utenti si uniscano a ${app_name}</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Puoi invitare una sola email alla volta</string>
|
||||
</resources>
|
|
@ -2989,4 +2989,7 @@
|
|||
<string name="settings_external_account_management">Údaje o vašom účte sú spravované samostatne na %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Účet</string>
|
||||
<string name="settings_notification_error_on_update">Pri aktualizácii vašich predvolieb oznámení došlo k chybe. Skúste prosím znova.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Keď sa pozvaní používatelia pripoja k aplikácii ${app_name}, budete môcť konverzovať a miestnosť bude end-to-end šifrovaná</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Čaká sa na pripojenie používateľov k aplikácii ${app_name}</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Naraz môžete pozvať len jeden e-mail</string>
|
||||
</resources>
|
|
@ -2915,4 +2915,7 @@
|
|||
<string name="settings_external_account_management">Hollësitë e llogarisë tuaj administrohen më vete, te %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Llogari</string>
|
||||
<string name="settings_notification_error_on_update">Ndodhi një gabim, kur u përditësuan parapëlqimet tuaja për njoftime. Ju lutemi, riprovoni.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Po pritet që përdoruesit të bëhen pjesë e ${app_name}</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Pasi përdoruesit e ftuar të jenë bërë pjesë e ${app_name}, do të jeni në gjendje të bisedoni dhe dhoma do të jetë e fshehtëzuar skaj-më-skaj</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Mund të ftoni vetëm një email në herë</string>
|
||||
</resources>
|
|
@ -3049,4 +3049,7 @@
|
|||
<string name="settings_external_account_management">Керування подробицями вашого облікового запису відбувається окремо на %1$s.</string>
|
||||
<string name="settings_external_account_management_title">Обліковий запис</string>
|
||||
<string name="settings_notification_error_on_update">Сталася помилка під час оновлення налаштувань сповіщень. Повторіть спробу.</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users_tile_description">Після того, як запрошені користувачі приєднаються до ${app_name}, ви зможете спілкуватися з ними, а кімната буде захищена наскрізним шифруванням</string>
|
||||
<string name="direct_room_encryption_enabled_waiting_users">Очікування на приєднання користувачів до ${app_name}</string>
|
||||
<string name="direct_room_user_list_only_invite_one_email">Ви можете запросити лише одну адресу електронної пошти за раз</string>
|
||||
</resources>
|
File diff suppressed because it is too large
Load Diff
|
@ -1002,6 +1002,7 @@
|
|||
<string name="settings_version">Version</string>
|
||||
<string name="settings_olm_version">olm version</string>
|
||||
<string name="settings_app_term_conditions">Terms & conditions</string>
|
||||
<string name="settings_acceptable_use_policy">Acceptable Use Policy</string>
|
||||
<string name="settings_third_party_notices">Third party notices</string>
|
||||
<string name="settings_copyright">Copyright</string>
|
||||
<string name="settings_privacy_policy">Privacy policy</string>
|
||||
|
@ -3539,4 +3540,11 @@
|
|||
|
||||
<string name="settings_access_token">Access Token</string>
|
||||
<string name="settings_access_token_summary">Your access token gives full access to your account. Do not share it with anyone.</string>
|
||||
|
||||
<!-- Pills -->
|
||||
<string name="pill_message_from_user">Message from %s</string>
|
||||
<string name="pill_message_from_unknown_user">Message</string>
|
||||
<string name="pill_message_in_room">Message in %s</string>
|
||||
<string name="pill_message_in_unknown_room">Message in room</string>
|
||||
<string name="pill_message_unknown_room_or_space">Room/Space</string>
|
||||
</resources>
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
<item name="dialog_width_ratio" format="float" type="dimen">0.75</item>
|
||||
|
||||
<dimen name="pill_avatar_size">16dp</dimen>
|
||||
<dimen name="pill_min_height">20dp</dimen>
|
||||
<dimen name="pill_avatar_size">20sp</dimen>
|
||||
<dimen name="pill_min_height">26sp</dimen>
|
||||
<dimen name="pill_text_padding">4dp</dimen>
|
||||
|
||||
<dimen name="call_pip_height">128dp</dimen>
|
||||
|
|
|
@ -62,7 +62,7 @@ android {
|
|||
// that the app's state is completely cleared between tests.
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
|
||||
buildConfigField "String", "SDK_VERSION", "\"1.5.28\""
|
||||
buildConfigField "String", "SDK_VERSION", "\"1.5.30\""
|
||||
|
||||
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
|
||||
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""
|
||||
|
|
|
@ -65,27 +65,14 @@ object MatrixPatterns {
|
|||
private const val APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/"
|
||||
const val SEP_REGEX = "/"
|
||||
|
||||
private const val LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = LINK_TO_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
private const val LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = LINK_TO_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
private const val LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = LINK_TO_APP_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
private const val LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
|
||||
private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = LINK_TO_APP_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE)
|
||||
private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK = PERMALINK_BASE_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
private val PATTERN_CONTAIN_APP_PERMALINK = APP_BASE_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// ascii characters in the range \x20 (space) to \x7E (~)
|
||||
val ORDER_STRING_REGEX = "[ -~]+".toRegex()
|
||||
|
||||
// list of patterns to find some matrix item.
|
||||
val MATRIX_PATTERNS = listOf(
|
||||
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID,
|
||||
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS,
|
||||
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID,
|
||||
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS,
|
||||
PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER,
|
||||
PATTERN_CONTAIN_MATRIX_ALIAS,
|
||||
PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER,
|
||||
|
@ -146,6 +133,12 @@ object MatrixPatterns {
|
|||
return str != null && str matches PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER
|
||||
}
|
||||
|
||||
fun isPermalink(str: String?): Boolean {
|
||||
return str != null &&
|
||||
(PATTERN_CONTAIN_MATRIX_TO_PERMALINK.containsMatchIn(str) ||
|
||||
PATTERN_CONTAIN_APP_PERMALINK.containsMatchIn(str))
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract server name from a matrix id.
|
||||
*
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.matrix.android.sdk.api.session.permalinks
|
||||
|
||||
import android.text.Spannable
|
||||
import android.util.Patterns
|
||||
import org.matrix.android.sdk.api.MatrixPatterns
|
||||
|
||||
/**
|
||||
|
@ -44,22 +45,26 @@ object MatrixLinkify {
|
|||
}
|
||||
val text = spannable.toString()
|
||||
var hasMatch = false
|
||||
for (pattern in MatrixPatterns.MATRIX_PATTERNS) {
|
||||
for (pattern in listOf(Patterns.WEB_URL.toRegex()).plus(MatrixPatterns.MATRIX_PATTERNS)) {
|
||||
for (match in pattern.findAll(spannable)) {
|
||||
hasMatch = true
|
||||
val startPos = match.range.first
|
||||
if (startPos == 0 || text[startPos - 1] != '/') {
|
||||
val endPos = match.range.last + 1
|
||||
var url = text.substring(match.range)
|
||||
if (MatrixPatterns.isUserId(url) ||
|
||||
val isPermalink = MatrixPatterns.isPermalink(url)
|
||||
if (isPermalink ||
|
||||
MatrixPatterns.isUserId(url) ||
|
||||
MatrixPatterns.isRoomAlias(url) ||
|
||||
MatrixPatterns.isRoomId(url) ||
|
||||
MatrixPatterns.isGroupId(url) ||
|
||||
MatrixPatterns.isEventId(url)) {
|
||||
url = PermalinkService.MATRIX_TO_URL_BASE + url
|
||||
if (!isPermalink) {
|
||||
url = PermalinkService.MATRIX_TO_URL_BASE + url
|
||||
}
|
||||
val span = MatrixPermalinkSpan(url, callback)
|
||||
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
val span = MatrixPermalinkSpan(url, callback)
|
||||
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ data class RoomMemberQueryParams(
|
|||
val displayName: QueryStringValue,
|
||||
val memberships: List<Membership>,
|
||||
val userId: QueryStringValue,
|
||||
val excludeSelf: Boolean
|
||||
val excludeSelf: Boolean,
|
||||
val displayNameOrUserId: QueryStringValue,
|
||||
) {
|
||||
|
||||
class Builder {
|
||||
|
@ -39,12 +40,14 @@ data class RoomMemberQueryParams(
|
|||
var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
|
||||
var memberships: List<Membership> = Membership.all()
|
||||
var excludeSelf: Boolean = false
|
||||
var displayNameOrUserId: QueryStringValue = QueryStringValue.NoCondition
|
||||
|
||||
fun build() = RoomMemberQueryParams(
|
||||
displayName = displayName,
|
||||
memberships = memberships,
|
||||
userId = userId,
|
||||
excludeSelf = excludeSelf
|
||||
excludeSelf = excludeSelf,
|
||||
displayNameOrUserId = displayNameOrUserId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,8 @@ sealed class MatrixItem(
|
|||
data class RoomItem(
|
||||
override val id: String,
|
||||
override val displayName: String? = null,
|
||||
override val avatarUrl: String? = null
|
||||
override val avatarUrl: String? = null,
|
||||
val roomDisplayName: String? = null
|
||||
) :
|
||||
MatrixItem(id, displayName, avatarUrl) {
|
||||
init {
|
||||
|
@ -103,7 +104,8 @@ sealed class MatrixItem(
|
|||
data class RoomAliasItem(
|
||||
override val id: String,
|
||||
override val displayName: String? = null,
|
||||
override val avatarUrl: String? = null
|
||||
override val avatarUrl: String? = null,
|
||||
val roomDisplayName: String? = null
|
||||
) :
|
||||
MatrixItem(id, displayName, avatarUrl) {
|
||||
init {
|
||||
|
@ -147,6 +149,8 @@ sealed class MatrixItem(
|
|||
val displayName = when (this) {
|
||||
// use the room display name for the notify everyone item
|
||||
is EveryoneInRoomItem -> roomDisplayName
|
||||
is RoomItem -> roomDisplayName ?: displayName
|
||||
is RoomAliasItem -> roomDisplayName ?: displayName
|
||||
else -> displayName
|
||||
}
|
||||
return (displayName?.takeIf { it.isNotBlank() } ?: id)
|
||||
|
|
|
@ -17,14 +17,13 @@
|
|||
package org.matrix.android.sdk.internal.session.room.membership
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.otaliastudios.opengl.core.use
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.room.members.MembershipService
|
||||
|
@ -58,7 +57,6 @@ internal class DefaultMembershipService @AssistedInject constructor(
|
|||
private val cryptoService: CryptoService,
|
||||
@UserId
|
||||
private val userId: String,
|
||||
private val matrixConfiguration: MatrixConfiguration,
|
||||
private val queryStringValueProcessor: QueryStringValueProcessor
|
||||
) : MembershipService {
|
||||
|
||||
|
@ -120,6 +118,13 @@ internal class DefaultMembershipService @AssistedInject constructor(
|
|||
if (queryParams.excludeSelf) {
|
||||
notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
|
||||
}
|
||||
if (queryParams.displayNameOrUserId != QueryStringValue.NoCondition) {
|
||||
beginGroup()
|
||||
process(RoomMemberSummaryEntityFields.USER_ID, queryParams.displayNameOrUserId)
|
||||
or()
|
||||
process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayNameOrUserId)
|
||||
endGroup()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13238,6 +13238,9 @@
|
|||
"o’clock",
|
||||
"twelve",
|
||||
"twelve_o_clock",
|
||||
"00:00",
|
||||
"0000",
|
||||
"1200",
|
||||
"time",
|
||||
"noon",
|
||||
"midnight",
|
||||
|
@ -13258,6 +13261,9 @@
|
|||
"twelve",
|
||||
"twelve-thirty",
|
||||
"twelve_thirty",
|
||||
"00:30",
|
||||
"0030",
|
||||
"1230",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13275,6 +13281,9 @@
|
|||
"o’clock",
|
||||
"one",
|
||||
"one_o_clock",
|
||||
"100",
|
||||
"13:00",
|
||||
"1300",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13292,6 +13301,9 @@
|
|||
"one-thirty",
|
||||
"thirty",
|
||||
"one_thirty",
|
||||
"130",
|
||||
"13:30",
|
||||
"1330",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13309,6 +13321,9 @@
|
|||
"o’clock",
|
||||
"two",
|
||||
"two_o_clock",
|
||||
"200",
|
||||
"14:00",
|
||||
"1400",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13326,6 +13341,9 @@
|
|||
"two",
|
||||
"two-thirty",
|
||||
"two_thirty",
|
||||
"230",
|
||||
"14:30",
|
||||
"1430",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13343,6 +13361,9 @@
|
|||
"o’clock",
|
||||
"three",
|
||||
"three_o_clock",
|
||||
"300",
|
||||
"15:00",
|
||||
"1500",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13360,6 +13381,9 @@
|
|||
"three",
|
||||
"three-thirty",
|
||||
"three_thirty",
|
||||
"330",
|
||||
"15:30",
|
||||
"1530",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13377,6 +13401,9 @@
|
|||
"four",
|
||||
"o’clock",
|
||||
"four_o_clock",
|
||||
"400",
|
||||
"16:00",
|
||||
"1600",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13394,6 +13421,9 @@
|
|||
"four-thirty",
|
||||
"thirty",
|
||||
"four_thirty",
|
||||
"430",
|
||||
"16:30",
|
||||
"1630",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13411,6 +13441,9 @@
|
|||
"five",
|
||||
"o’clock",
|
||||
"five_o_clock",
|
||||
"500",
|
||||
"17:00",
|
||||
"1700",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13428,6 +13461,9 @@
|
|||
"five-thirty",
|
||||
"thirty",
|
||||
"five_thirty",
|
||||
"530",
|
||||
"17:30",
|
||||
"1730",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13445,6 +13481,9 @@
|
|||
"o’clock",
|
||||
"six",
|
||||
"six_o_clock",
|
||||
"600",
|
||||
"18:00",
|
||||
"1800",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13464,6 +13503,9 @@
|
|||
"six-thirty",
|
||||
"thirty",
|
||||
"six_thirty",
|
||||
"630",
|
||||
"18:30",
|
||||
"1830",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13481,6 +13523,9 @@
|
|||
"o’clock",
|
||||
"seven",
|
||||
"seven_o_clock",
|
||||
"700",
|
||||
"19:00",
|
||||
"1900",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13498,6 +13543,9 @@
|
|||
"seven-thirty",
|
||||
"thirty",
|
||||
"seven_thirty",
|
||||
"730",
|
||||
"19:30",
|
||||
"1930",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13515,6 +13563,9 @@
|
|||
"eight",
|
||||
"o’clock",
|
||||
"eight_o_clock",
|
||||
"800",
|
||||
"20:00",
|
||||
"2000",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13532,6 +13583,9 @@
|
|||
"eight-thirty",
|
||||
"thirty",
|
||||
"eight_thirty",
|
||||
"830",
|
||||
"20:30",
|
||||
"2030",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13549,6 +13603,9 @@
|
|||
"nine",
|
||||
"o’clock",
|
||||
"nine_o_clock",
|
||||
"900",
|
||||
"21:00",
|
||||
"2100",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13566,6 +13623,9 @@
|
|||
"nine-thirty",
|
||||
"thirty",
|
||||
"nine_thirty",
|
||||
"930",
|
||||
"21:30",
|
||||
"2130",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13583,6 +13643,9 @@
|
|||
"o’clock",
|
||||
"ten",
|
||||
"ten_o_clock",
|
||||
"1000",
|
||||
"22:00",
|
||||
"2200",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13600,6 +13663,9 @@
|
|||
"ten-thirty",
|
||||
"thirty",
|
||||
"ten_thirty",
|
||||
"1030",
|
||||
"22:30",
|
||||
"2230",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13617,6 +13683,9 @@
|
|||
"eleven",
|
||||
"o’clock",
|
||||
"eleven_o_clock",
|
||||
"1100",
|
||||
"23:00",
|
||||
"2300",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -13634,6 +13703,9 @@
|
|||
"eleven-thirty",
|
||||
"thirty",
|
||||
"eleven_thirty",
|
||||
"1130",
|
||||
"23:30",
|
||||
"2330",
|
||||
"time",
|
||||
"late",
|
||||
"early",
|
||||
|
@ -20066,7 +20138,11 @@
|
|||
"1234",
|
||||
"input",
|
||||
"numbers",
|
||||
"blue-square"
|
||||
"blue-square",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4"
|
||||
]
|
||||
},
|
||||
"input-symbols": {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Hlavní změny v této verzi: Hlavně opravy chyb.
|
||||
Úplný seznam změn: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Die wichtigsten Änderungen in dieser Version: Hauptsächlich Fehlerbehebungen.
|
||||
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Main changes in this version: permalinks to rooms, spaces, users and messages are now displayed as pills in the timeline. We also fixed some issues with custom stickers and the read marker getting stuck in the past.
|
||||
Full changelog: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Põhilised muutused selles versioonis: põhiliselt veaparandused.
|
||||
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
تغییرات عمده در این نگارش: عمدتاً رفع اشکال.
|
||||
گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Principaux changements pour cette version : Principalement des corrections de bugs.
|
||||
Intégralité des changements : https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Fő változás ebben a verzióban: hibajavítások.
|
||||
Teljes változásnapló: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Perubahan utama dalam versi ini: Kebanyakan perbaikan kutu.
|
||||
Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Modifiche principali in questa versione: correzioni di errori.
|
||||
Cronologia completa: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Hlavné zmeny v tejto verzii: Hlavne opravy chýb.
|
||||
Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Ndryshimet kryesore në këtë version: Kryesisht ndreqje të metash.
|
||||
Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Ndryshimet kryesore në këtë version: Kryesisht ndreqje të metash.
|
||||
Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основні зміни у цій версії: Переважно виправлення помилок.
|
||||
Повний перелік змін: https://github.com/vector-im/element-android/releases
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:語音訊息的預設為啟用。
|
||||
此版本的主要變動:預設啟用語音訊息功能。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.2.0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:對 VoIP 與空間功能的諸多改善(仍在測試中)。
|
||||
此版本的主要變動:對 VoIP 與聊天空間功能的諸多改善(仍在測試中)。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.2.1
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:使用空間來整理您的聊天室!
|
||||
此版本的主要變動:使用聊天空間來整理您的聊天室!
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:使用空間來整理您的聊天室!v1.3.1 修復了在 v1.3.0 中遇到的當機問題。
|
||||
此版本的主要變動:使用聊天空間來整理您的聊天室!v1.3.1 修復了在 v1.3.0 中遇到的當機問題。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.1
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:為直接訊息聊天室新增 Presence 支援(請注意:此功能在 matrix.org 上停用)。恢復對 Android Auto 的支援。
|
||||
此版本的主要變動:為私人訊息聊天室新增 Presence 支援(請注意:此功能在 matrix.org 上停用)。加回 Android Auto 支援。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.5
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:為直接訊息聊天室新增 Presence 支援(請注意:此功能在 matrix.org 上停用)。加回 Android Auto 支援。
|
||||
此版本的主要變動:為私人訊息聊天室新增 Presence 支援(請注意:此功能在 matrix.org 上停用)。加回 Android Auto 支援。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.6
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:富文本編輯器全螢幕模式的全新建置與錯誤修復。
|
||||
此版本的主要變動:全新實作的富文本編輯器全螢幕模式與錯誤修復。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本的主要變動:富文本編輯器全螢幕模式全新建置與錯誤修復。
|
||||
此版本的主要變動:全新實作的富文本編輯器全螢幕模式與錯誤修復。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本中的主要變動:討論串現在預設啟用。
|
||||
此版本的主要變動:預設開啟對話串功能。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
此版本中的主要變動:討論串現在預設啟用。
|
||||
此版本的主要變動:預設開啟對話串功能。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
此版本中的主要變動:主要是臭蟲修復。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases
|
|
@ -37,7 +37,7 @@ ext.versionMinor = 5
|
|||
// Note: even values are reserved for regular release, odd values for hotfix release.
|
||||
// When creating a hotfix, you should decrease the value, since the current value
|
||||
// is the value for the next regular release.
|
||||
ext.versionPatch = 28
|
||||
ext.versionPatch = 30
|
||||
|
||||
ext.scVersion = 65
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ fun initialSyncIdlingResource(session: Session): IdlingResource {
|
|||
this.callback = callback
|
||||
}
|
||||
|
||||
override fun onChanged(t: SyncState?) {
|
||||
override fun onChanged(value: SyncState) {
|
||||
val isIdle = session.syncService().hasAlreadySynced()
|
||||
if (isIdle) {
|
||||
callback?.onTransitionToIdle()
|
||||
|
@ -241,10 +241,10 @@ fun allSecretsKnownIdling(session: Session): IdlingResource {
|
|||
this.callback = callback
|
||||
}
|
||||
|
||||
override fun onChanged(t: Optional<PrivateKeysInfo>?) {
|
||||
println("*** [$name] allSecretsKnownIdling ${t?.getOrNull()}")
|
||||
privateKeysInfo = t?.getOrNull()
|
||||
if (t?.getOrNull()?.allKnown() == true) {
|
||||
override fun onChanged(value: Optional<PrivateKeysInfo>) {
|
||||
println("*** [$name] allSecretsKnownIdling ${value.getOrNull()}")
|
||||
privateKeysInfo = value.getOrNull()
|
||||
if (value.getOrNull()?.allKnown() == true) {
|
||||
session.cryptoService().crossSigningService().getLiveCrossSigningPrivateKeys().removeObserver(this)
|
||||
callback?.onTransitionToIdle()
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ abstract class VerificationTestBase {
|
|||
session.syncService().getSyncStateLive()
|
||||
}
|
||||
val syncObserver = object : Observer<SyncState> {
|
||||
override fun onChanged(t: SyncState?) {
|
||||
override fun onChanged(value: SyncState) {
|
||||
if (session.syncService().hasAlreadySynced()) {
|
||||
lock.countDown()
|
||||
syncLiveData.removeObserver(this)
|
||||
|
|
|
@ -133,7 +133,7 @@ dependencies {
|
|||
implementation libs.androidx.biometric
|
||||
|
||||
api "org.threeten:threetenbp:1.4.0:no-tzdb"
|
||||
api "com.gabrielittner.threetenbp:lazythreetenbp:0.13.0"
|
||||
api "com.gabrielittner.threetenbp:lazythreetenbp:0.14.0"
|
||||
|
||||
implementation libs.squareup.moshi
|
||||
implementation libs.squareup.moshiKt
|
||||
|
@ -244,7 +244,7 @@ dependencies {
|
|||
// UnifiedPush
|
||||
implementation 'com.github.UnifiedPush:android-connector:2.1.1'
|
||||
|
||||
implementation "androidx.emoji2:emoji2:1.2.0"
|
||||
implementation "androidx.emoji2:emoji2:1.3.0"
|
||||
|
||||
// WebRTC
|
||||
// org.webrtc:google-webrtc is for development purposes only
|
||||
|
|
|
@ -21,13 +21,16 @@ import android.text.Editable
|
|||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.autofill.HintConstants
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.app.core.platform.SimpleTextWatcher
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import reactivecircus.flowbinding.android.widget.textChanges
|
||||
|
||||
fun TextInputLayout.editText() = this.editText!!
|
||||
|
@ -85,7 +88,7 @@ fun TextInputLayout.setOnImeDoneListener(action: () -> Unit) {
|
|||
fun TextInputLayout.setOnFocusLostListener(lifecycleOwner: LifecycleOwner, action: () -> Unit) {
|
||||
editText().setOnFocusChangeListener { _, hasFocus ->
|
||||
when (hasFocus) {
|
||||
false -> lifecycleOwner.lifecycleScope.launchWhenResumed { action() }
|
||||
false -> lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { action() } }
|
||||
else -> {
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -291,17 +291,6 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
|
|||
}
|
||||
}
|
||||
|
||||
// SC-TODO: this is the pre-v1.5.18 implementation of observeViewEvents, to fix custom widgets. Revert me once upstream implements a fix.
|
||||
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.oldObserveViewEvents(observer: (T) -> Unit) {
|
||||
val tag = this@VectorBaseFragment::class.simpleName.toString()
|
||||
viewEvents
|
||||
.stream(tag)
|
||||
.onEach {
|
||||
observer(it)
|
||||
}
|
||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
* Views
|
||||
* ========================================================================================== */
|
||||
|
|
|
@ -15,6 +15,7 @@ import im.vector.app.features.html.HtmlCodeSpan
|
|||
import io.noties.markwon.core.spans.EmphasisSpan
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* TextView that reserves space at the bottom for overlaying it with a footer, e.g. in a FrameLayout or RelativeLayout
|
||||
|
@ -73,7 +74,7 @@ interface AbstractFooteredTextView {
|
|||
val looksLikeRtl = layout.isRtlCharAt(lastVisibleCharacter)
|
||||
*/
|
||||
|
||||
// Get required width for all lines
|
||||
// Get required width for all lines (not using measuredWidth so wrap_content doesn't go match_parent if long lines enforced some line breaks)
|
||||
var maxLineWidth = 0f
|
||||
for (i in 0 until layout.lineCount) {
|
||||
// For some reasons, the getLineWidth is not working too well with RTL lines when rendering replies.
|
||||
|
@ -87,6 +88,9 @@ interface AbstractFooteredTextView {
|
|||
max(layout.getLineWidth(i), maxLineWidth)
|
||||
}
|
||||
}
|
||||
// Huge PillImageSpans might want to reserve more horizontal space with above approach than what is available,
|
||||
// so ensure we don't give them more then super would, such that their auto-ellipsize feature works properly.
|
||||
maxLineWidth = min(maxLineWidth, measuredWidth.toFloat())
|
||||
|
||||
// Fix wrap_content in multi-line texts by using maxLineWidth instead of measuredWidth here
|
||||
// (compare WrapWidthTextView.kt)
|
||||
|
|
|
@ -48,9 +48,7 @@ open class LiveEvent<out T>(private val content: T) {
|
|||
* [onEventUnhandledContent] is *only* called if the [LiveEvent]'s contents has not been handled.
|
||||
*/
|
||||
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<LiveEvent<T>> {
|
||||
override fun onChanged(event: LiveEvent<T>?) {
|
||||
event?.getContentIfNotHandled()?.let { value ->
|
||||
onEventUnhandledContent(value)
|
||||
}
|
||||
override fun onChanged(value: LiveEvent<T>) {
|
||||
value.getContentIfNotHandled()?.let { onEventUnhandledContent(it) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,19 +41,23 @@ private val IGNORED_OPTIONS: Options? = null
|
|||
|
||||
@Singleton
|
||||
class DefaultVectorAnalytics @Inject constructor(
|
||||
postHogFactory: PostHogFactory,
|
||||
private val postHogFactory: PostHogFactory,
|
||||
private val sentryAnalytics: SentryAnalytics,
|
||||
analyticsConfig: AnalyticsConfig,
|
||||
private val analyticsConfig: AnalyticsConfig,
|
||||
private val analyticsStore: AnalyticsStore,
|
||||
private val lateInitUserPropertiesFactory: LateInitUserPropertiesFactory,
|
||||
@NamedGlobalScope private val globalScope: CoroutineScope
|
||||
) : VectorAnalytics {
|
||||
|
||||
private val posthog: PostHog? = when {
|
||||
analyticsConfig.isEnabled -> postHogFactory.createPosthog()
|
||||
else -> {
|
||||
Timber.tag(analyticsTag.value).w("Analytics is disabled")
|
||||
null
|
||||
private var posthog: PostHog? = null
|
||||
|
||||
private fun createPosthog(): PostHog? {
|
||||
return when {
|
||||
analyticsConfig.isEnabled -> postHogFactory.createPosthog()
|
||||
else -> {
|
||||
Timber.tag(analyticsTag.value).w("Analytics is disabled")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,6 +154,7 @@ class DefaultVectorAnalytics @Inject constructor(
|
|||
userConsent?.let { _userConsent ->
|
||||
when (_userConsent) {
|
||||
true -> {
|
||||
posthog = createPosthog()
|
||||
posthog?.optOut(false)
|
||||
identifyPostHog()
|
||||
pendingUserProperties?.let { doUpdateUserProperties(it) }
|
||||
|
@ -159,6 +164,8 @@ class DefaultVectorAnalytics @Inject constructor(
|
|||
// When opting out, ensure that the queue is flushed first, or it will be flushed later (after user has revoked consent)
|
||||
posthog?.flush()
|
||||
posthog?.optOut(true)
|
||||
posthog?.shutdown()
|
||||
posthog = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ class AutocompleteMemberController @Inject constructor(private val context: Cont
|
|||
roomMember.roomMemberSummary.let { user ->
|
||||
id(user.userId)
|
||||
matrixItem(user.toMatrixItem())
|
||||
subName(user.userId)
|
||||
avatarRenderer(host.avatarRenderer)
|
||||
clickListener { host.listener?.onItemClick(roomMember) }
|
||||
}
|
||||
|
|
|
@ -112,8 +112,8 @@ class AutocompleteMemberPresenter @AssistedInject constructor(
|
|||
* ========================================================================================== */
|
||||
|
||||
private fun createQueryParams(query: CharSequence?) = roomMemberQueryParams {
|
||||
displayName = if (query.isNullOrBlank()) {
|
||||
QueryStringValue.IsNotEmpty
|
||||
displayNameOrUserId = if (query.isNullOrBlank()) {
|
||||
QueryStringValue.NoCondition
|
||||
} else {
|
||||
QueryStringValue.Contains(query.toString(), QueryStringValue.Case.INSENSITIVE)
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.app.R
|
|||
import im.vector.app.databinding.ViewRemoveJitsiWidgetBinding
|
||||
import im.vector.app.features.home.room.detail.RoomDetailViewState
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility") class RemoveJitsiWidgetView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
@ -55,7 +56,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||
return@setOnTouchListener when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
if (currentState == State.Idle) {
|
||||
val initialX = views.removeJitsiSlidingContainer.x - event.rawX
|
||||
val initialX = event.rawX
|
||||
updateState(State.Sliding(initialX, 0f, false))
|
||||
}
|
||||
true
|
||||
|
@ -73,8 +74,9 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (currentState is State.Sliding) {
|
||||
val translationX = (currentState.initialX + event.rawX).coerceAtLeast(0f)
|
||||
val hasReachedActivationThreshold = translationX >= views.root.width / 4
|
||||
val deltaX = event.rawX - currentState.initialX
|
||||
val translationX = if (!isRtl) deltaX.coerceAtLeast(0f) else deltaX.coerceAtMost(0f)
|
||||
val hasReachedActivationThreshold = translationX.absoluteValue >= views.root.width / 4
|
||||
updateState(State.Sliding(currentState.initialX, translationX, hasReachedActivationThreshold))
|
||||
}
|
||||
true
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.util.MatrixItem
|
|||
|
||||
fun MatrixItem.getBestName(): String {
|
||||
// Note: this code is copied from [DisplayNameResolver] in the SDK
|
||||
return if (this is MatrixItem.RoomAliasItem) {
|
||||
return if (this is MatrixItem.RoomAliasItem && displayName.isNullOrBlank()) {
|
||||
// Best name is the id, and we keep the displayName of the room for the case we need the first letter
|
||||
id
|
||||
} else {
|
||||
|
|
|
@ -30,7 +30,9 @@ import androidx.core.view.isVisible
|
|||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.airbnb.mvrx.Mavericks
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
@ -417,8 +419,8 @@ class HomeActivity :
|
|||
|
||||
private fun handleStartRecoverySetup() {
|
||||
// To avoid IllegalStateException in case the transaction was executed after onSaveInstanceState
|
||||
lifecycleScope.launchWhenResumed {
|
||||
navigator.open4SSetup(this@HomeActivity, SetupMode.NORMAL)
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) { navigator.open4SSetup(this@HomeActivity, SetupMode.NORMAL) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||
data class UndoReaction(val targetEventId: String, val reaction: String, val reason: String? = "") : RoomDetailAction()
|
||||
data class RedactAction(val targetEventId: String, val reason: String? = "") : RoomDetailAction()
|
||||
data class UpdateQuickReactAction(val targetEventId: String, val selectedReaction: String, val add: Boolean) : RoomDetailAction()
|
||||
data class NavigateToEvent(val eventId: String, val highlight: Boolean) : RoomDetailAction()
|
||||
data class NavigateToEvent(val eventId: String, val highlight: Boolean, val isFirstUnreadEvent: Boolean = false) : RoomDetailAction()
|
||||
data class MarkAllAsRead(val forceIfOpenedAnonymously: Boolean = false) : RoomDetailAction()
|
||||
data class DownloadOrOpen(val eventId: String, val senderId: String?, val messageFileContent: MessageWithAttachmentContent) : RoomDetailAction()
|
||||
object JoinAndOpenReplacementRoom : RoomDetailAction()
|
||||
|
|
|
@ -42,7 +42,7 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
|||
|
||||
data class OpenRoom(val roomId: String, val closeCurrentRoom: Boolean = false) : RoomDetailViewEvents()
|
||||
|
||||
data class NavigateToEvent(val eventId: String) : RoomDetailViewEvents()
|
||||
data class NavigateToEvent(val eventId: String, val isFirstUnreadEvent: Boolean) : RoomDetailViewEvents()
|
||||
data class JoinJitsiConference(val widget: Widget, val withVideo: Boolean) : RoomDetailViewEvents()
|
||||
object LeaveJitsiConference : RoomDetailViewEvents()
|
||||
|
||||
|
|
|
@ -51,7 +51,9 @@ import androidx.core.view.isVisible
|
|||
import androidx.core.view.postDelayed
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.TransitionManager
|
||||
|
@ -179,7 +181,6 @@ import im.vector.app.features.home.room.threads.ThreadsManager
|
|||
import im.vector.app.features.home.room.threads.arguments.ThreadTimelineArgs
|
||||
import im.vector.app.features.home.room.typing.TypingHelper
|
||||
import im.vector.app.features.html.EventHtmlRenderer
|
||||
import im.vector.app.features.html.PillsPostProcessor
|
||||
import im.vector.app.features.invite.VectorInviteView
|
||||
import im.vector.app.features.location.LocationSharingMode
|
||||
import im.vector.app.features.location.toLocationData
|
||||
|
@ -271,7 +272,6 @@ class TimelineFragment :
|
|||
@Inject lateinit var matrixItemColorProvider: MatrixItemColorProvider
|
||||
@Inject lateinit var imageContentRenderer: ImageContentRenderer
|
||||
@Inject lateinit var roomDetailPendingActionStore: RoomDetailPendingActionStore
|
||||
@Inject lateinit var pillsPostProcessorFactory: PillsPostProcessor.Factory
|
||||
@Inject lateinit var callManager: WebRtcCallManager
|
||||
@Inject lateinit var audioMessagePlaybackTracker: AudioMessagePlaybackTracker
|
||||
@Inject lateinit var shareIntentHandler: ShareIntentHandler
|
||||
|
@ -806,7 +806,9 @@ class TimelineFragment :
|
|||
private fun navigateToEvent(action: RoomDetailViewEvents.NavigateToEvent) {
|
||||
setInitialForceScrollEnabled(true)
|
||||
scrollOnNewMessageCallback.initialForceScrollEventId = action.eventId
|
||||
val scrollPosition = timelineEventController.searchPositionOfEvent(action.eventId)
|
||||
val scrollPosition = timelineEventController.getPositionOfReadMarker().takeIf { action.isFirstUnreadEvent }
|
||||
?: timelineEventController.searchPositionOfEvent(action.eventId)
|
||||
|
||||
if (scrollPosition == null) {
|
||||
scrollOnHighlightedEventCallback.scheduleScrollTo(action.eventId)
|
||||
} else {
|
||||
|
@ -1385,29 +1387,31 @@ class TimelineFragment :
|
|||
|
||||
private fun updateJumpToReadMarkerViewVisibility() {
|
||||
if (isThreadTimeLine()) return
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
|
||||
val state = timelineViewModel.awaitState()
|
||||
val showJumpToUnreadBanner = when (state.unreadState) {
|
||||
UnreadState.Unknown,
|
||||
UnreadState.HasNoUnread -> false
|
||||
is UnreadState.ReadMarkerNotLoaded -> true
|
||||
is UnreadState.HasUnread -> {
|
||||
if (state.canShowJumpToReadMarker) {
|
||||
val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition()
|
||||
val positionOfReadMarker = withContext(Dispatchers.Default) {
|
||||
timelineEventController.getPositionOfReadMarker()
|
||||
}
|
||||
if (positionOfReadMarker == null) {
|
||||
false
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
val state = timelineViewModel.awaitState()
|
||||
val showJumpToUnreadBanner = when (state.unreadState) {
|
||||
UnreadState.Unknown,
|
||||
UnreadState.HasNoUnread -> false
|
||||
is UnreadState.ReadMarkerNotLoaded -> true
|
||||
is UnreadState.HasUnread -> {
|
||||
if (state.canShowJumpToReadMarker) {
|
||||
val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition()
|
||||
val positionOfReadMarker = withContext(Dispatchers.Default) {
|
||||
timelineEventController.getPositionOfReadMarker()
|
||||
}
|
||||
if (positionOfReadMarker == null) {
|
||||
false
|
||||
} else {
|
||||
positionOfReadMarker > lastVisibleItem
|
||||
}
|
||||
} else {
|
||||
positionOfReadMarker > lastVisibleItem
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
views.jumpToReadMarkerView.isVisible = showJumpToUnreadBanner
|
||||
}
|
||||
views.jumpToReadMarkerView.isVisible = showJumpToUnreadBanner
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1932,14 +1936,16 @@ class TimelineFragment :
|
|||
}
|
||||
|
||||
override fun onRoomCreateLinkClicked(url: String) {
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
|
||||
permalinkHandler
|
||||
.launch(requireActivity(), url, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
permalinkHandler
|
||||
.launch(requireActivity(), url, object : NavigationInterceptor {
|
||||
override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?, rootThreadEventId: String?): Boolean {
|
||||
requireActivity().finish()
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2337,10 +2343,10 @@ class TimelineFragment :
|
|||
|
||||
private fun onJumpToReadMarkerClicked() = withState(timelineViewModel) {
|
||||
if (it.unreadState is UnreadState.HasUnread) {
|
||||
timelineViewModel.handle(RoomDetailAction.NavigateToEvent(it.unreadState.firstUnreadEventId, false))
|
||||
timelineViewModel.handle(RoomDetailAction.NavigateToEvent(it.unreadState.firstUnreadEventId, highlight = false, isFirstUnreadEvent = true))
|
||||
}
|
||||
if (it.unreadState is UnreadState.ReadMarkerNotLoaded) {
|
||||
timelineViewModel.handle(RoomDetailAction.NavigateToEvent(it.unreadState.readMarkerId, false))
|
||||
timelineViewModel.handle(RoomDetailAction.NavigateToEvent(it.unreadState.readMarkerId, highlight = false))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1150,7 +1150,7 @@ class TimelineViewModel @AssistedInject constructor(
|
|||
if (action.highlight) {
|
||||
setState { copy(highlightedEventId = targetEventId) }
|
||||
}
|
||||
_viewEvents.post(RoomDetailViewEvents.NavigateToEvent(targetEventId))
|
||||
_viewEvents.post(RoomDetailViewEvents.NavigateToEvent(targetEventId, action.isFirstUnreadEvent))
|
||||
}
|
||||
|
||||
private fun handleResendEvent(action: RoomDetailAction.ResendMessage) {
|
||||
|
|
|
@ -20,21 +20,30 @@ import android.content.Context
|
|||
import android.text.Spannable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.util.Patterns
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.glide.GlideApp
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.html.PillImageSpan
|
||||
import org.matrix.android.sdk.api.MatrixPatterns
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.getUserOrDefault
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
|
||||
class EventTextRenderer @AssistedInject constructor(
|
||||
@Assisted private val roomId: String?,
|
||||
private val context: Context,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val activeSessionHolder: ActiveSessionHolder,
|
||||
private val sessionHolder: ActiveSessionHolder,
|
||||
) {
|
||||
|
||||
@AssistedFactory
|
||||
|
@ -46,7 +55,8 @@ class EventTextRenderer @AssistedInject constructor(
|
|||
* @param text the text to be rendered
|
||||
*/
|
||||
fun render(text: CharSequence): CharSequence {
|
||||
return renderNotifyEveryone(text)
|
||||
val formattedText = renderPermalinks(text)
|
||||
return renderNotifyEveryone(formattedText)
|
||||
}
|
||||
|
||||
private fun renderNotifyEveryone(text: CharSequence): CharSequence {
|
||||
|
@ -59,8 +69,18 @@ class EventTextRenderer @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun renderPermalinks(text: CharSequence): CharSequence {
|
||||
return if (roomId != null) {
|
||||
SpannableStringBuilder(text).apply {
|
||||
addPermalinksSpans(this)
|
||||
}
|
||||
} else {
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
private fun addNotifyEveryoneSpans(text: Spannable, roomId: String) {
|
||||
val room: RoomSummary? = activeSessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(roomId)
|
||||
val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.roomService()?.getRoomSummary(roomId)
|
||||
val matrixItem = MatrixItem.EveryoneInRoomItem(
|
||||
id = roomId,
|
||||
avatarUrl = room?.avatarUrl,
|
||||
|
@ -76,6 +96,23 @@ class EventTextRenderer @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun addPermalinksSpans(text: Spannable) {
|
||||
for (match in Patterns.WEB_URL.toRegex().findAll(text)) {
|
||||
val url = text.substring(match.range)
|
||||
val matrixItem = if (MatrixPatterns.isPermalink(url)) {
|
||||
when (val permalinkData = PermalinkParser.parse(url)) {
|
||||
is PermalinkData.UserLink -> permalinkData.toMatrixItem()
|
||||
is PermalinkData.RoomLink -> permalinkData.toMatrixItem()
|
||||
else -> null
|
||||
}
|
||||
} else null
|
||||
|
||||
if (matrixItem != null) {
|
||||
addPillSpan(text, createPillImageSpan(matrixItem), match.range.first, match.range.last + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPillImageSpan(matrixItem: MatrixItem) =
|
||||
PillImageSpan(GlideApp.with(context), avatarRenderer, context, matrixItem)
|
||||
|
||||
|
@ -87,4 +124,46 @@ class EventTextRenderer @AssistedInject constructor(
|
|||
) {
|
||||
renderedText.setSpan(pillSpan, startSpan, endSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
|
||||
private fun PermalinkData.UserLink.toMatrixItem(): MatrixItem? =
|
||||
roomId?.let { sessionHolder.getSafeActiveSession()?.roomService()?.getRoomMember(userId, it)?.toMatrixItem() }
|
||||
?: sessionHolder.getSafeActiveSession()?.getUserOrDefault(userId)?.toMatrixItem()
|
||||
|
||||
private fun PermalinkData.RoomLink.toMatrixItem(): MatrixItem =
|
||||
if (eventId.isNullOrEmpty()) {
|
||||
val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(roomIdOrAlias)
|
||||
when {
|
||||
isRoomAlias -> MatrixItem.RoomAliasItem(roomIdOrAlias, room?.displayName, room?.avatarUrl)
|
||||
room == null -> MatrixItem.RoomItem(roomIdOrAlias, context.getString(R.string.pill_message_unknown_room_or_space))
|
||||
room.roomType == RoomType.SPACE -> MatrixItem.SpaceItem(roomIdOrAlias, room.displayName, room.avatarUrl)
|
||||
else -> MatrixItem.RoomItem(roomIdOrAlias, room.displayName, room.avatarUrl)
|
||||
}
|
||||
} else {
|
||||
if (roomIdOrAlias == roomId) {
|
||||
val session = sessionHolder.getSafeActiveSession()
|
||||
val event = session?.eventService()?.getEventFromCache(roomId, eventId!!)
|
||||
val user = event?.senderId?.let { session.roomService().getRoomMember(it, roomId) }
|
||||
val text = user?.let {
|
||||
context.getString(R.string.pill_message_from_user, user.displayName)
|
||||
} ?: context.getString(R.string.pill_message_from_unknown_user)
|
||||
MatrixItem.RoomItem(roomIdOrAlias, text, user?.avatarUrl, user?.displayName)
|
||||
} else {
|
||||
val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(roomIdOrAlias)
|
||||
when {
|
||||
isRoomAlias -> MatrixItem.RoomAliasItem(
|
||||
roomIdOrAlias,
|
||||
context.getString(R.string.pill_message_in_room, room?.displayName ?: roomIdOrAlias),
|
||||
room?.avatarUrl,
|
||||
room?.displayName
|
||||
)
|
||||
room != null -> MatrixItem.RoomItem(
|
||||
roomIdOrAlias,
|
||||
context.getString(R.string.pill_message_in_room, room.displayName),
|
||||
room.avatarUrl,
|
||||
room.displayName
|
||||
)
|
||||
else -> MatrixItem.RoomItem(roomIdOrAlias, context.getString(R.string.pill_message_in_unknown_room))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,12 +44,11 @@ fun CharSequence.findPillsAndProcess(scope: CoroutineScope, processBlock: (PillI
|
|||
}
|
||||
|
||||
fun CharSequence.linkify(callback: TimelineEventController.UrlClickCallback?): CharSequence {
|
||||
val text = this.toString()
|
||||
// SpannableStringBuilder is used to avoid Epoxy throwing ImmutableModelException
|
||||
val spannable = SpannableStringBuilder(this)
|
||||
MatrixLinkify.addLinks(spannable, object : MatrixPermalinkSpan.Callback {
|
||||
override fun onUrlClicked(url: String) {
|
||||
callback?.onUrlClicked(url, text)
|
||||
callback?.onUrlClicked(url, this.toString())
|
||||
}
|
||||
})
|
||||
VectorLinkify.addLinks(spannable, true)
|
||||
|
|
|
@ -22,19 +22,24 @@ import android.content.Context
|
|||
import android.content.res.ColorStateList
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.TextUtils
|
||||
import android.text.style.ReplacementSpan
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.bumptech.glide.request.target.SimpleTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.google.android.material.chip.ChipDrawable
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.isMatrixId
|
||||
import im.vector.app.core.glide.GlideRequests
|
||||
import im.vector.app.features.displayname.getBestName
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import org.matrix.android.sdk.api.extensions.orTrue
|
||||
import org.matrix.android.sdk.api.session.room.send.MatrixItemSpan
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import java.lang.ref.WeakReference
|
||||
|
@ -100,6 +105,15 @@ class PillImageSpan(
|
|||
val transY: Int = y + (fm.descent + fm.ascent - pillDrawable.bounds.bottom) / 2
|
||||
canvas.save()
|
||||
canvas.translate(x, transY.toFloat())
|
||||
|
||||
val rect = Rect()
|
||||
canvas.getClipBounds(rect)
|
||||
val maxWidth = rect.right
|
||||
if (pillDrawable.intrinsicWidth > maxWidth) {
|
||||
pillDrawable.setBounds(0, 0, maxWidth, pillDrawable.intrinsicHeight)
|
||||
pillDrawable.ellipsize = TextUtils.TruncateAt.END
|
||||
}
|
||||
|
||||
pillDrawable.draw(canvas)
|
||||
canvas.restore()
|
||||
}
|
||||
|
@ -113,10 +127,28 @@ class PillImageSpan(
|
|||
|
||||
private fun createChipDrawable(): ChipDrawable {
|
||||
val textPadding = context.resources.getDimension(R.dimen.pill_text_padding)
|
||||
val icon = try {
|
||||
avatarRenderer.getCachedDrawable(glideRequests, matrixItem)
|
||||
} catch (exception: Exception) {
|
||||
avatarRenderer.getPlaceholderDrawable(matrixItem)
|
||||
val icon = when {
|
||||
matrixItem is MatrixItem.RoomAliasItem && matrixItem.avatarUrl.isNullOrEmpty() &&
|
||||
matrixItem.displayName == context.getString(R.string.pill_message_in_room, matrixItem.id) -> {
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_permalink_round)
|
||||
}
|
||||
matrixItem is MatrixItem.RoomItem && matrixItem.avatarUrl.isNullOrEmpty() && (
|
||||
matrixItem.displayName == context.getString(R.string.pill_message_in_unknown_room) ||
|
||||
matrixItem.displayName == context.getString(R.string.pill_message_unknown_room_or_space) ||
|
||||
matrixItem.displayName == context.getString(R.string.pill_message_from_unknown_user)
|
||||
) -> {
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_permalink_round)
|
||||
}
|
||||
matrixItem is MatrixItem.UserItem && matrixItem.avatarUrl.isNullOrEmpty() && matrixItem.displayName?.isMatrixId().orTrue() -> {
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_user_round)
|
||||
}
|
||||
else -> {
|
||||
try {
|
||||
avatarRenderer.getCachedDrawable(glideRequests, matrixItem)
|
||||
} catch (exception: Exception) {
|
||||
avatarRenderer.getPlaceholderDrawable(matrixItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ChipDrawable.createFromResource(context, R.xml.pill_view).apply {
|
||||
|
|
|
@ -28,7 +28,7 @@ import im.vector.app.features.home.AvatarRenderer
|
|||
import io.noties.markwon.core.spans.LinkSpan
|
||||
import io.noties.markwon.image.AsyncDrawableSpan
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.getUserOrDefault
|
||||
import org.matrix.android.sdk.api.session.getUser
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
@ -57,15 +57,15 @@ class PillsPostProcessor @AssistedInject constructor(
|
|||
* ========================================================================================== */
|
||||
|
||||
override fun afterRender(renderedText: Spannable) {
|
||||
addPillSpans(renderedText, roomId)
|
||||
addPillSpans(renderedText)
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
* Helper methods
|
||||
* ========================================================================================== */
|
||||
|
||||
private fun addPillSpans(renderedText: Spannable, roomId: String?) {
|
||||
addLinkSpans(renderedText, roomId)
|
||||
private fun addPillSpans(renderedText: Spannable) {
|
||||
addLinkSpans(renderedText)
|
||||
}
|
||||
|
||||
private fun addPillSpan(
|
||||
|
@ -77,11 +77,11 @@ class PillsPostProcessor @AssistedInject constructor(
|
|||
renderedText.setSpan(pillSpan, startSpan, endSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
|
||||
private fun addLinkSpans(renderedText: Spannable, roomId: String?) {
|
||||
private fun addLinkSpans(renderedText: Spannable) {
|
||||
// We let markdown handle links and then we add PillImageSpan if needed.
|
||||
val linkSpans = renderedText.getSpans(0, renderedText.length, LinkSpan::class.java)
|
||||
linkSpans.forEach { linkSpan ->
|
||||
val pillSpan = linkSpan.createPillSpan(roomId) ?: return@forEach
|
||||
val pillSpan = linkSpan.createPillSpan() ?: return@forEach
|
||||
val startSpan = renderedText.getSpanStart(linkSpan)
|
||||
val endSpan = renderedText.getSpanEnd(linkSpan)
|
||||
// GlideImagesPlugin causes duplicated pills if we have a nested image: https://github.com/SchildiChat/SchildiChat-android/issues/148
|
||||
|
@ -105,21 +105,18 @@ class PillsPostProcessor @AssistedInject constructor(
|
|||
private fun createPillImageSpan(matrixItem: MatrixItem) =
|
||||
PillImageSpan(GlideApp.with(context), avatarRenderer, context, matrixItem)
|
||||
|
||||
private fun LinkSpan.createPillSpan(roomId: String?): PillImageSpan? {
|
||||
private fun LinkSpan.createPillSpan(): PillImageSpan? {
|
||||
val matrixItem = when (val permalinkData = PermalinkParser.parse(url)) {
|
||||
is PermalinkData.UserLink -> permalinkData.toMatrixItem(roomId)
|
||||
is PermalinkData.UserLink -> permalinkData.toMatrixItem()
|
||||
is PermalinkData.RoomLink -> permalinkData.toMatrixItem()
|
||||
else -> null
|
||||
} ?: return null
|
||||
return createPillImageSpan(matrixItem)
|
||||
}
|
||||
|
||||
private fun PermalinkData.UserLink.toMatrixItem(roomId: String?): MatrixItem? =
|
||||
if (roomId == null) {
|
||||
sessionHolder.getSafeActiveSession()?.getUserOrDefault(userId)?.toMatrixItem()
|
||||
} else {
|
||||
sessionHolder.getSafeActiveSession()?.roomService()?.getRoomMember(userId, roomId)?.toMatrixItem()
|
||||
}
|
||||
private fun PermalinkData.UserLink.toMatrixItem(): MatrixItem? =
|
||||
roomId?.let { sessionHolder.getSafeActiveSession()?.roomService()?.getRoomMember(userId, it)?.toMatrixItem() }
|
||||
?: sessionHolder.getSafeActiveSession()?.getUser(userId)?.toMatrixItem()
|
||||
|
||||
private fun PermalinkData.RoomLink.toMatrixItem(): MatrixItem? =
|
||||
if (eventId == null) {
|
||||
|
|
|
@ -26,7 +26,9 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
@ -47,6 +49,7 @@ import im.vector.app.features.location.live.duration.ChooseLiveDurationBottomShe
|
|||
import im.vector.app.features.location.live.tracking.LocationSharingAndroidService
|
||||
import im.vector.app.features.location.option.LocationSharingOption
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
|
@ -97,11 +100,13 @@ class LocationSharingFragment :
|
|||
}.also { views.mapView.addOnDidFailLoadingMapListener(it) }
|
||||
views.mapView.onCreate(savedInstanceState)
|
||||
|
||||
lifecycleScope.launchWhenCreated {
|
||||
views.mapView.initialize(
|
||||
url = urlMapProvider.getMapUrl(),
|
||||
locationTargetChangeListener = this@LocationSharingFragment
|
||||
)
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
views.mapView.initialize(
|
||||
url = urlMapProvider.getMapUrl(),
|
||||
locationTargetChangeListener = this@LocationSharingFragment
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
initLocateButton()
|
||||
|
|
|
@ -22,7 +22,9 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -42,6 +44,7 @@ import im.vector.app.features.location.LocationSharingArgs
|
|||
import im.vector.app.features.location.MapState
|
||||
import im.vector.app.features.location.UrlMapProvider
|
||||
import im.vector.app.features.location.showUserLocationNotAvailableErrorDialog
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -77,8 +80,10 @@ class LocationPreviewFragment :
|
|||
}.also { views.mapView.addOnDidFailLoadingMapListener(it) }
|
||||
views.mapView.onCreate(savedInstanceState)
|
||||
|
||||
lifecycleScope.launchWhenCreated {
|
||||
views.mapView.initialize(urlMapProvider.getMapUrl())
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||
views.mapView.initialize(urlMapProvider.getMapUrl())
|
||||
}
|
||||
}
|
||||
|
||||
observeViewEvents()
|
||||
|
|
|
@ -114,13 +114,8 @@ class PermalinkHandler @Inject constructor(
|
|||
|
||||
val rootThreadEventId = permalinkData.eventId?.let { eventId ->
|
||||
val room = roomId?.let { session?.getRoom(it) }
|
||||
|
||||
val rootThreadEventId = room?.getTimelineEvent(eventId)?.root?.getRootThreadEventId()
|
||||
rootThreadEventId ?: if (room?.getTimelineEvent(eventId)?.isRootThread() == true) {
|
||||
eventId
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val event = room?.getTimelineEvent(eventId)
|
||||
event?.root?.getRootThreadEventId() ?: eventId.takeIf { event?.isRootThread() == true }
|
||||
}
|
||||
openRoom(
|
||||
navigationInterceptor,
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package im.vector.app.features.settings
|
||||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreference
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
@ -129,34 +131,36 @@ class VectorSettingsPinFragment :
|
|||
}
|
||||
|
||||
private fun refreshPinCodeStatus() {
|
||||
lifecycleScope.launchWhenResumed {
|
||||
val hasPinCode = pinCodeStore.hasEncodedPin()
|
||||
usePinCodePref.isChecked = hasPinCode
|
||||
usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
if (hasPinCode) {
|
||||
lifecycleScope.launch {
|
||||
pinCodeStore.deletePinCode()
|
||||
refreshPinCodeStatus()
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
val hasPinCode = pinCodeStore.hasEncodedPin()
|
||||
usePinCodePref.isChecked = hasPinCode
|
||||
usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
if (hasPinCode) {
|
||||
lifecycleScope.launch {
|
||||
pinCodeStore.deletePinCode()
|
||||
refreshPinCodeStatus()
|
||||
}
|
||||
} else {
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.CREATE
|
||||
)
|
||||
}
|
||||
} else {
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.CREATE
|
||||
)
|
||||
true
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
changePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
if (hasPinCode) {
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.MODIFY
|
||||
)
|
||||
changePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
if (hasPinCode) {
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.MODIFY
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,9 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.SwitchPreference
|
||||
|
@ -185,11 +187,11 @@ class VectorSettingsSecurityPrivacyFragment :
|
|||
}
|
||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||
|
||||
lifecycleScope.launchWhenResumed {
|
||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible =
|
||||
rawService
|
||||
.getElementWellknown(session.sessionParams)
|
||||
?.isE2EByDefault() == false
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible =
|
||||
rawService
|
||||
.getElementWellknown(session.sessionParams)
|
||||
?.isE2EByDefault() == false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,16 +418,18 @@ class VectorSettingsSecurityPrivacyFragment :
|
|||
}
|
||||
|
||||
private fun openPinCodePreferenceScreen() {
|
||||
lifecycleScope.launchWhenResumed {
|
||||
val hasPinCode = pinCodeStore.hasEncodedPin()
|
||||
if (hasPinCode) {
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.AUTH
|
||||
)
|
||||
} else {
|
||||
doOpenPinCodePreferenceScreen()
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
val hasPinCode = pinCodeStore.hasEncodedPin()
|
||||
if (hasPinCode) {
|
||||
navigator.openPinCode(
|
||||
requireContext(),
|
||||
pinActivityResultLauncher,
|
||||
PinMode.AUTH
|
||||
)
|
||||
} else {
|
||||
doOpenPinCodePreferenceScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ package im.vector.app.features.settings
|
|||
object VectorSettingsUrls {
|
||||
const val HELP = "https://schildi.chat/android/faq"
|
||||
const val COPYRIGHT = "https://element.io/copyright"
|
||||
const val TAC = "https://element.io/terms-of-service"
|
||||
const val ACCEPTABLE_USE_POLICY = "https://element.io/acceptable-use-policy-terms"
|
||||
const val PRIVACY_POLICY = "https://schildi.chat/android/privacy"
|
||||
const val DISCLAIMER_URL = "https://element.io/previously-riot"
|
||||
const val THIRD_PARTY_LICENSES = "file:///android_asset/open_source_licenses.html"
|
||||
|
|
|
@ -31,7 +31,7 @@ class ElementLegals @Inject constructor(
|
|||
fun getData(): List<ServerPolicy> {
|
||||
return listOf(
|
||||
ServerPolicy(stringProvider.getString(R.string.settings_copyright), VectorSettingsUrls.COPYRIGHT),
|
||||
ServerPolicy(stringProvider.getString(R.string.settings_app_term_conditions), VectorSettingsUrls.TAC),
|
||||
ServerPolicy(stringProvider.getString(R.string.settings_acceptable_use_policy), VectorSettingsUrls.ACCEPTABLE_USE_POLICY),
|
||||
ServerPolicy(stringProvider.getString(R.string.settings_privacy_policy), VectorSettingsUrls.PRIVACY_POLICY)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.ScrollView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -45,6 +47,7 @@ import im.vector.app.features.settings.VectorSettingsActivity
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import reactivecircus.flowbinding.android.widget.textChanges
|
||||
|
@ -174,8 +177,10 @@ class UserListFragment :
|
|||
|
||||
// Scroll to the bottom when adding chips. When removing chips, do not scroll
|
||||
if (newNumberOfChips >= currentNumberOfChips) {
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
|
||||
views.chipGroupScrollView.fullScroll(ScrollView.FOCUS_DOWN)
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
views.chipGroupScrollView.fullScroll(ScrollView.FOCUS_DOWN)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ class WidgetFragment :
|
|||
if (fragmentArgs.kind.isAdmin()) {
|
||||
viewModel.getPostAPIMediator().setWebView(views.widgetWebView)
|
||||
}
|
||||
viewModel.oldObserveViewEvents {
|
||||
viewModel.observeViewEvents {
|
||||
Timber.v("Observed view events: $it")
|
||||
when (it) {
|
||||
is WidgetViewEvents.DisplayTerms -> displayTerms(it)
|
||||
|
@ -218,7 +218,7 @@ class WidgetFragment :
|
|||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
Timber.v("Invalidate state: $state")
|
||||
when (state.formattedURL) {
|
||||
when (val formattedUrl = state.formattedURL) {
|
||||
Uninitialized,
|
||||
is Loading -> {
|
||||
setStateError(null)
|
||||
|
@ -227,6 +227,9 @@ class WidgetFragment :
|
|||
views.widgetProgressBar.isVisible = true
|
||||
}
|
||||
is Success -> {
|
||||
if (views.widgetWebView.url == null) {
|
||||
loadFormattedUrl(formattedUrl())
|
||||
}
|
||||
setStateError(null)
|
||||
when (state.webviewLoadedUrl) {
|
||||
Uninitialized -> {
|
||||
|
@ -253,7 +256,7 @@ class WidgetFragment :
|
|||
// we need to show Error
|
||||
views.widgetWebView.isInvisible = true
|
||||
views.widgetProgressBar.isVisible = false
|
||||
setStateError(state.formattedURL.error.message)
|
||||
setStateError(formattedUrl.error.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,8 +326,12 @@ class WidgetFragment :
|
|||
}
|
||||
|
||||
private fun loadFormattedUrl(event: WidgetViewEvents.OnURLFormatted) {
|
||||
loadFormattedUrl(event.formattedURL)
|
||||
}
|
||||
|
||||
private fun loadFormattedUrl(formattedUrl: String) {
|
||||
views.widgetWebView.clearHistory()
|
||||
views.widgetWebView.loadUrl(event.formattedURL)
|
||||
views.widgetWebView.loadUrl(formattedUrl)
|
||||
}
|
||||
|
||||
private fun setStateError(message: String?) {
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="36dp"
|
||||
android:height="36dp"
|
||||
android:viewportWidth="36"
|
||||
android:viewportHeight="36">
|
||||
<path
|
||||
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
|
||||
android:fillColor="?colorPrimary"/>
|
||||
<path
|
||||
android:pathData="M9.818,18.787L14.705,23.818L26.182,12"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -5,12 +5,12 @@
|
|||
android:viewportHeight="36">
|
||||
<path
|
||||
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
|
||||
android:fillColor="#8bc34a"/>
|
||||
android:fillColor="?colorPrimary"/>
|
||||
<path
|
||||
android:pathData="M9.818,18.787L14.705,23.818L26.182,12"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeColor="?colorOnPrimary"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
|
||||
android:fillColor="@color/element_name_01"/>
|
||||
<path
|
||||
android:pathData="m12.378,8.101 l0.356,-0.356c0.984,-0.984 2.57,-0.994 3.543,-0.021 0.973,0.972 0.963,2.559 -0.021,3.543l-1.693,1.693c-0.984,0.984 -2.57,0.994 -3.543,0.021m0.603,2.919 l-0.356,0.356c-0.984,0.984 -2.57,0.994 -3.543,0.021 -0.973,-0.973 -0.963,-2.559 0.021,-3.543l1.693,-1.693c0.984,-0.984 2.57,-0.994 3.543,-0.021"
|
||||
android:strokeWidth="1.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/palette_white"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -4,15 +4,15 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M17.5911,20.2922C15.9951,21.3704 14.0711,22 12,22C9.7488,22 7.6713,21.2561 6,20.0007C3.5711,18.1763 2,15.2716 2,12C2,6.4771 6.4771,2 12,2C17.5228,2 22,6.4771 22,12C22,15.4518 20.2511,18.4951 17.5911,20.2922ZM12,12.5C13.6569,12.5 15,11.0449 15,9.25C15,7.4551 13.6569,6 12,6C10.3431,6 9,7.4551 9,9.25C9,11.0449 10.3431,12.5 12,12.5ZM12,20C14.162,20 16.1236,19.1424 17.5634,17.7488C16.673,15.5506 14.5176,14 12,14C9.4824,14 7.327,15.5506 6.4366,17.7488C7.8763,19.1424 9.838,20 12,20Z"
|
||||
android:fillColor="#C1C6CD"
|
||||
android:pathData="M18.709,21.951C16.794,23.244 14.485,24 12,24C9.299,24 6.806,23.107 4.8,21.601C1.885,19.412 0,15.926 0,12C0,5.373 5.373,0 12,0C18.627,0 24,5.373 24,12C24,16.142 21.901,19.794 18.709,21.951ZM12,12.6C13.988,12.6 15.6,10.854 15.6,8.7C15.6,6.546 13.988,4.8 12,4.8C10.012,4.8 8.4,6.546 8.4,8.7C8.4,10.854 10.012,12.6 12,12.6ZM12,21.6C14.594,21.6 16.948,20.571 18.676,18.899C17.608,16.261 15.021,14.4 12,14.4C8.979,14.4 6.392,16.261 5.324,18.899C7.052,20.571 9.406,21.6 12,21.6Z"
|
||||
android:fillColor="?vctr_content_secondary"
|
||||
android:fillType="evenOdd"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M17.5911,20.2922C15.9951,21.3704 14.0711,22 12,22C9.7488,22 7.6713,21.2561 6,20.0007C3.5711,18.1763 2,15.2716 2,12C2,6.4771 6.4771,2 12,2C17.5228,2 22,6.4771 22,12C22,15.4518 20.2511,18.4951 17.5911,20.2922ZM12,12.5C13.6569,12.5 15,11.0449 15,9.25C15,7.4551 13.6569,6 12,6C10.3431,6 9,7.4551 9,9.25C9,11.0449 10.3431,12.5 12,12.5ZM12,20C14.162,20 16.1236,19.1424 17.5634,17.7488C16.673,15.5506 14.5176,14 12,14C9.4824,14 7.327,15.5506 6.4366,17.7488C7.8763,19.1424 9.838,20 12,20Z"
|
||||
android:pathData="M18.709,21.951C16.794,23.244 14.485,24 12,24C9.299,24 6.806,23.107 4.8,21.601C1.885,19.412 0,15.926 0,12C0,5.373 5.373,0 12,0C18.627,0 24,5.373 24,12C24,16.142 21.901,19.794 18.709,21.951ZM12,12.6C13.988,12.6 15.6,10.854 15.6,8.7C15.6,6.546 13.988,4.8 12,4.8C10.012,4.8 8.4,6.546 8.4,8.7C8.4,10.854 10.012,12.6 12,12.6ZM12,21.6C14.594,21.6 16.948,20.571 18.676,18.899C17.608,16.261 15.021,14.4 12,14.4C8.979,14.4 6.392,16.261 5.324,18.899C7.052,20.571 9.406,21.6 12,21.6Z"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M17.5911,20.2922L16.4715,18.6349L17.5911,20.2922ZM6,20.0007L4.7989,21.5999L4.7989,21.5999L6,20.0007ZM17.5634,17.7488L18.9544,19.1859L19.9234,18.2479L19.4171,16.998L17.5634,17.7488ZM6.4366,17.7488L4.5829,16.998L4.0766,18.2479L5.0456,19.1859L6.4366,17.7488ZM12,24C14.4825,24 16.7945,23.244 18.7107,21.9494L16.4715,18.6349C15.1957,19.4968 13.6596,20 12,20V24ZM4.7989,21.5999C6.8046,23.1065 9.3008,24 12,24V20C10.1967,20 8.538,19.4058 7.2011,18.4016L4.7989,21.5999ZM0,12C0,15.9273 1.8887,19.414 4.7989,21.5999L7.2011,18.4016C5.2535,16.9387 4,14.616 4,12H0ZM12,0C5.3726,0 0,5.3726 0,12H4C4,7.5817 7.5817,4 12,4V0ZM24,12C24,5.3726 18.6274,0 12,0V4C16.4183,4 20,7.5817 20,12H24ZM18.7107,21.9494C21.8977,19.7963 24,16.144 24,12H20C20,14.7596 18.6045,17.1939 16.4715,18.6349L18.7107,21.9494ZM13,9.25C13,10.0941 12.4046,10.5 12,10.5V14.5C14.9091,14.5 17,11.9958 17,9.25H13ZM12,8C12.4046,8 13,8.4059 13,9.25H17C17,6.5043 14.9091,4 12,4V8ZM11,9.25C11,8.4059 11.5954,8 12,8V4C9.0909,4 7,6.5043 7,9.25H11ZM12,10.5C11.5954,10.5 11,10.0941 11,9.25H7C7,11.9958 9.0909,14.5 12,14.5V10.5ZM16.1724,16.3118C15.0906,17.3588 13.6223,18 12,18V22C14.7017,22 17.1567,20.926 18.9544,19.1859L16.1724,16.3118ZM12,16C13.6752,16 15.1146,17.0305 15.7097,18.4996L19.4171,16.998C18.2314,14.0707 15.3599,12 12,12V16ZM8.2903,18.4996C8.8854,17.0305 10.3248,16 12,16V12C8.6401,12 5.7686,14.0707 4.5829,16.998L8.2903,18.4996ZM12,18C10.3777,18 8.9094,17.3588 7.8276,16.3118L5.0456,19.1859C6.8433,20.926 9.2983,22 12,22V18Z"
|
||||
android:fillColor="#C1C6CD"/>
|
||||
android:pathData="M18.709,21.951L19.564,23.216L18.709,21.951ZM4.8,21.601L3.883,22.822H3.883L4.8,21.601ZM18.676,18.899L19.738,19.996L20.478,19.28L20.092,18.325L18.676,18.899ZM5.324,18.899L3.908,18.325L3.522,19.28L4.262,19.996L5.324,18.899ZM12,25.527C14.8,25.527 17.404,24.675 19.564,23.216L17.854,20.685C16.184,21.814 14.171,22.473 12,22.473V25.527ZM3.883,22.822C6.144,24.52 8.956,25.527 12,25.527V22.473C9.641,22.473 7.467,21.694 5.717,20.38L3.883,22.822ZM-1.527,12C-1.527,16.427 0.601,20.357 3.883,22.822L5.717,20.38C3.17,18.466 1.527,15.425 1.527,12H-1.527ZM12,-1.527C4.529,-1.527 -1.527,4.529 -1.527,12H1.527C1.527,6.216 6.216,1.527 12,1.527V-1.527ZM25.527,12C25.527,4.529 19.471,-1.527 12,-1.527V1.527C17.784,1.527 22.473,6.216 22.473,12H25.527ZM19.564,23.216C23.159,20.788 25.527,16.671 25.527,12H22.473C22.473,15.613 20.644,18.8 17.854,20.685L19.564,23.216ZM14.073,8.7C14.073,10.128 13.032,11.073 12,11.073V14.127C14.944,14.127 17.127,11.58 17.127,8.7H14.073ZM12,6.327C13.032,6.327 14.073,7.272 14.073,8.7H17.127C17.127,5.82 14.944,3.273 12,3.273V6.327ZM9.927,8.7C9.927,7.272 10.968,6.327 12,6.327V3.273C9.055,3.273 6.873,5.82 6.873,8.7H9.927ZM12,11.073C10.968,11.073 9.927,10.128 9.927,8.7H6.873C6.873,11.58 9.055,14.127 12,14.127V11.073ZM17.614,17.801C16.16,19.209 14.182,20.073 12,20.073V23.127C15.007,23.127 17.737,21.933 19.738,19.996L17.614,17.801ZM12,15.927C14.378,15.927 16.417,17.391 17.26,19.472L20.092,18.325C18.798,15.131 15.664,12.873 12,12.873V15.927ZM6.74,19.472C7.582,17.391 9.622,15.927 12,15.927V12.873C8.336,12.873 5.202,15.131 3.908,18.325L6.74,19.472ZM12,20.073C9.818,20.073 7.84,19.209 6.386,17.801L4.262,19.996C6.263,21.933 8.993,23.127 12,23.127V20.073Z"
|
||||
android:fillColor="?vctr_content_secondary"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -80,6 +80,12 @@ class DefaultVectorAnalyticsTest {
|
|||
|
||||
@Test
|
||||
fun `when revoking consent to analytics then updates posthog opt out to true and closes Sentry`() = runTest {
|
||||
// For opt-out to have effect on Posthog, it has to be used first, so it has to be opt-in first
|
||||
fakeAnalyticsStore.givenUserContent(consent = true)
|
||||
fakePostHog.verifyOptOutStatus(optedOut = false)
|
||||
fakeSentryAnalytics.verifySentryInit()
|
||||
|
||||
// Then test opt-out
|
||||
fakeAnalyticsStore.givenUserContent(consent = false)
|
||||
|
||||
fakePostHog.verifyOptOutStatus(optedOut = true)
|
||||
|
|
Loading…
Reference in New Issue