Merge remote-tracking branch 'origin/develop' into feature/eric/msc3773
# Conflicts: # matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
This commit is contained in:
		
						commit
						35be56a44a
					
				
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE/release.yml
									
									
									
									
										vendored
									
									
								
							| @ -20,7 +20,6 @@ body: | ||||
|         - [ ] Check the update of the store descriptions (using Google Translate if necessary) to ensure that the changes are acceptable to be published to the stores. | ||||
|         - [ ] While Weblate is locked, and after the PR from Weblate has been merged, handle all the TODOs in the main `strings.xml` file | ||||
|         - [ ] Run the script `./tools/release/pushPlayStoreMetaData.sh`. You can check in the GooglePlay console the Activity log to check the effect. | ||||
| 
 | ||||
|         - [ ] Ensure all [the required PRs](https://github.com/vector-im/element-android/pulls?q=is%3Aopen+is%3Apr+label%3AZ-NextRelease) have been merged | ||||
| 
 | ||||
|         ### Do the release | ||||
| @ -32,7 +31,6 @@ body: | ||||
|         - [ ] Run the integration test, and especially `UiAllScreensSanityTest.allScreensTest()` | ||||
|         - [ ] Create an account on matrix.org and do some smoke tests that the sanity test does not cover like: 1-1 call, 1-1 video call, Jitsi call for instance | ||||
|         - [ ] Run towncrier: `towncrier build --version v1.2.3 --draft` (remove `--draft` do write the file CHANGES.md) | ||||
|         - [ ] Check that the folder `changelog.d` is empty. It can happen that some remaining files stay here | ||||
|         - [ ] Check the file CHANGES.md consistency. It's possible to reorder items (most important changes first) or change their section if relevant. Also an opportunity to fix some typo, or rewrite things | ||||
|         - [ ] Add file for fastlane under ./fastlane/metadata/android/en-US/changelogs | ||||
|         - [ ] (optional) Push the branch and start a draft PR (will not be merged), to check that the CI is happy with all the changes. | ||||
|  | ||||
							
								
								
									
										8
									
								
								.github/workflows/triage-labelled.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/triage-labelled.yml
									
									
									
									
										vendored
									
									
								
							| @ -48,7 +48,13 @@ jobs: | ||||
|     # Skip in forks | ||||
|     if: > | ||||
|       github.repository == 'vector-im/element-android' && | ||||
|       contains(github.event.issue.labels.*.name, 'X-Needs-Design') | ||||
|       contains(github.event.issue.labels.*.name, 'X-Needs-Design') && | ||||
|       (contains(github.event.issue.labels.*.name, 'S-Critical') && | ||||
|        (contains(github.event.issue.labels.*.name, 'O-Frequent') || | ||||
|         contains(github.event.issue.labels.*.name, 'O-Occasional')) || | ||||
|        (contains(github.event.issue.labels.*.name, 'S-Major') && | ||||
|         contains(github.event.issue.labels.*.name, 'O-Frequent')) || | ||||
|        contains(github.event.issue.labels.*.name, 'A11y')) | ||||
|     steps: | ||||
|       - uses: octokit/graphql-action@v2.x | ||||
|         id: add_to_project | ||||
|  | ||||
							
								
								
									
										61
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								CHANGES.md
									
									
									
									
									
								
							| @ -1,3 +1,64 @@ | ||||
| Changes in Element v1.5.4 (2022-10-19) | ||||
| ====================================== | ||||
| 
 | ||||
| Features ✨ | ||||
| ---------- | ||||
|  - Add WYSIWYG editor, under a lab flag. ([#7288](https://github.com/vector-im/element-android/issues/7288)) | ||||
|  - New Device management, can be enabled in the labs settings. | ||||
|  - Voice broadcast can be enabled in the labs settings (recording is possible only on Android 10 and up). | ||||
| 
 | ||||
| Bugfixes 🐛 | ||||
| ---------- | ||||
|  - Fix wrong mic button direction to cancel on RTL languages ([#5968](https://github.com/vector-im/element-android/issues/5968)) | ||||
|  - Handle properly when getUser returns null - prefer using getUserOrDefault ([#7372](https://github.com/vector-im/element-android/issues/7372)) | ||||
|  - [Device Management] Long session names not handled well ([#7310](https://github.com/vector-im/element-android/issues/7310)) | ||||
|  - Fix editing formatted messages with plain text editor ([#7359](https://github.com/vector-im/element-android/issues/7359)) | ||||
| 
 | ||||
| In development 🚧 | ||||
| ---------------- | ||||
|  - [Device Management] Save "matrix_client_information" events on login/registration ([#7257](https://github.com/vector-im/element-android/issues/7257)) | ||||
|  - [Device management] Add lab flag for the feature ([#7336](https://github.com/vector-im/element-android/issues/7336)) | ||||
|  - [Device management] Add lab flag for matrix client info account data event ([#7344](https://github.com/vector-im/element-android/issues/7344)) | ||||
|  - [Device Management] Redirect to the new screen everywhere when lab flag is on ([#7374](https://github.com/vector-im/element-android/issues/7374)) | ||||
|  - [Device Management] Show correct device type icons ([#7277](https://github.com/vector-im/element-android/issues/7277)) | ||||
|  - [Device Management] Render extended device info ([#7294](https://github.com/vector-im/element-android/issues/7294)) | ||||
|  - [Device management] Improve the parsing for OS of Desktop/Web sessions ([#7321](https://github.com/vector-im/element-android/issues/7321)) | ||||
|  - [Device management] Hide the IP address and last activity date on current session ([#7324](https://github.com/vector-im/element-android/issues/7324)) | ||||
|  - [Device management] Update the unknown verification status icon ([#7327](https://github.com/vector-im/element-android/issues/7327)) | ||||
|  - [Voice Broadcast] Add the "io.element.voice_broadcast_info" state event with a minimalist timeline widget ([#7273](https://github.com/vector-im/element-android/issues/7273)) | ||||
|  - [Voice Broadcast] Aggregate state events in the timeline ([#7283](https://github.com/vector-im/element-android/issues/7283)) | ||||
|  - [Voice Broadcast] Record and send non aggregated voice messages to the room ([#7363](https://github.com/vector-im/element-android/issues/7363)) | ||||
|  - [Voice Broadcast] Start listening to a voice broadcast ([#7387](https://github.com/vector-im/element-android/issues/7387)) | ||||
|  - [Voice Broadcast] Enable the feature (behind a lab flag and only for Android 10 and up) ([#7393](https://github.com/vector-im/element-android/issues/7393)) | ||||
|  - [Voice Broadcast] Add additional data in events ([#7397](https://github.com/vector-im/element-android/issues/7397)) | ||||
|  - Implements MSC3881: Parses `enabled` and `device_id` fields from updated Pusher API ([#7217](https://github.com/vector-im/element-android/issues/7217)) | ||||
|  - Adds pusher toggle setting to device manager v2 ([#7261](https://github.com/vector-im/element-android/issues/7261)) | ||||
|  - Implement QR Code Login UI ([#7338](https://github.com/vector-im/element-android/issues/7338)) | ||||
|  - Implements client-side of local notification settings event ([#7300](https://github.com/vector-im/element-android/issues/7300)) | ||||
|  - Links "Enable Notifications for this session" setting to enabled value in pusher ([#7281](https://github.com/vector-im/element-android/issues/7281)) | ||||
| 
 | ||||
| SDK API changes ⚠️ | ||||
| ------------------ | ||||
|  - Stop using `original_event` field from `/relations` endpoint ([#7282](https://github.com/vector-im/element-android/issues/7282)) | ||||
|  - Add `formattedText` or similar optional parameters in several methods: | ||||
|   * RelationService: | ||||
|   	* editTextMessage | ||||
|   	* editReply | ||||
|   	* replyToMessage | ||||
|   * SendService: | ||||
|   	* sendQuotedTextMessage | ||||
|   This allows us to send any HTML formatted text message without needing to rely on automatic Markdown > HTML translation. All these new parameters have a `null` value by default, so previous calls to these API methods remain compatible. ([#7288](https://github.com/vector-im/element-android/issues/7288)) | ||||
|  - Add support for `m.login.token` auth during QR code based sign in ([#7358](https://github.com/vector-im/element-android/issues/7358)) | ||||
|  - Allow getting the formatted or plain text body of a message for the fun `TimelineEvent.getTextEditableContent()`. ([#7359](https://github.com/vector-im/element-android/issues/7359)) | ||||
| 
 | ||||
| Other changes | ||||
| ------------- | ||||
|  - Refactor TimelineFragment, split it into MessageComposerFragment and VoiceRecorderFragment. ([#7285](https://github.com/vector-im/element-android/issues/7285)) | ||||
|  - Dependency to arrow has been removed. Please use `org.matrix.android.sdk.api.util.Optional` instead. ([#7335](https://github.com/vector-im/element-android/issues/7335)) | ||||
|  - Update WYSIWYG editor designs. ([#7354](https://github.com/vector-im/element-android/issues/7354)) | ||||
|  - Update WYSIWYG library to v0.2.1. ([#7384](https://github.com/vector-im/element-android/issues/7384)) | ||||
| 
 | ||||
| 
 | ||||
| Changes in Element v1.5.2 (2022-10-05) | ||||
| ====================================== | ||||
| 
 | ||||
|  | ||||
| @ -29,7 +29,7 @@ buildscript { | ||||
|         classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513' | ||||
|         classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5' | ||||
|         classpath "com.likethesalad.android:stem-plugin:2.2.3" | ||||
|         classpath 'org.owasp:dependency-check-gradle:7.2.1' | ||||
|         classpath 'org.owasp:dependency-check-gradle:7.3.0' | ||||
|         classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.20" | ||||
|         classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0" | ||||
|         classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3' | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| Fix wrong mic button direction to cancel on RTL languages | ||||
| @ -1 +0,0 @@ | ||||
| Implements MSC3881: Parses `enabled` and `device_id` fields from updated Pusher API | ||||
| @ -1 +0,0 @@ | ||||
| [Device Management] Save "matrix_client_information" events on login/registration | ||||
| @ -1 +0,0 @@ | ||||
| Adds pusher toggle setting to device manager v2 | ||||
| @ -1 +0,0 @@ | ||||
| [Voice Broadcast] Add the "io.element.voice_broadcast_info" state event with a minimalist timeline widget | ||||
| @ -1 +0,0 @@ | ||||
| [Device Management] Show correct device type icons | ||||
| @ -1 +0,0 @@ | ||||
| Links "Enable Notifications for this session" setting to enabled value in pusher | ||||
| @ -1 +0,0 @@ | ||||
| Stop using `original_event` field from `/relations` endpoint | ||||
| @ -1 +0,0 @@ | ||||
| [Voice Broadcast] Aggregate state events in the timeline | ||||
| @ -1 +0,0 @@ | ||||
| Refactor TimelineFragment, split it into MessageComposerFragment and VoiceRecorderFragment. | ||||
| @ -1 +0,0 @@ | ||||
| Add WYSIWYG editor. | ||||
| @ -1,10 +0,0 @@ | ||||
| Add `formattedText` or similar optional parameters in several methods: | ||||
| 
 | ||||
| * RelationService: | ||||
| 	* editTextMessage | ||||
| 	* editReply | ||||
| 	* replyToMessage | ||||
| * SendService: | ||||
| 	* sendQuotedTextMessage | ||||
| 
 | ||||
| This allows us to send any HTML formatted text message without needing to rely on automatic Markdown > HTML translation. All these new parameters have a `null` value by default, so previous calls to these API methods remain compatible. | ||||
| @ -1 +0,0 @@ | ||||
| [Device Management] Render extended device info | ||||
| @ -1 +0,0 @@ | ||||
| Implements client-side of local notification settings event | ||||
| @ -1 +0,0 @@ | ||||
| [Device Management] Long session names not handled well | ||||
| @ -1 +0,0 @@ | ||||
| [Device management] Improve the parsing for OS of Desktop/Web sessions | ||||
| @ -1 +0,0 @@ | ||||
| [Device management] Hide the IP address and last activity date on current session | ||||
| @ -1 +0,0 @@ | ||||
| [Device management] Update the unknown verification status icon | ||||
| @ -1 +0,0 @@ | ||||
| Dependency to arrow has been removed. Please use `org.matrix.android.sdk.api.util.Optional` instead. | ||||
| @ -1 +0,0 @@ | ||||
| [Device management] Add lab flag for the feature | ||||
| @ -1 +0,0 @@ | ||||
| Implement QR Code Login UI | ||||
| @ -1 +0,0 @@ | ||||
| [Device management] Add lab flag for matrix client info account data event | ||||
| @ -1 +0,0 @@ | ||||
| Update WYSIWYG editor designs. | ||||
| @ -1 +0,0 @@ | ||||
| Add support for `m.login.token` auth during QR code based sign in | ||||
| @ -1 +0,0 @@ | ||||
| Fix editing formatted messages with plain text editor | ||||
| @ -1 +0,0 @@ | ||||
| Allow getting the formatted or plain text body of a message for the fun `TimelineEvent.getTextEditableContent()`. | ||||
| @ -1 +0,0 @@ | ||||
| [Voice Broadcast] Record and send not aggregated voice messages to the room | ||||
							
								
								
									
										1
									
								
								changelog.d/7369.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								changelog.d/7369.feature
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Add logic for sign in with QR code | ||||
| @ -1 +0,0 @@ | ||||
| [Device Management] Redirect to the new screen everywhere when lab flag is on | ||||
| @ -1 +0,0 @@ | ||||
| Update WYSIWYG library to v0.2.1. | ||||
							
								
								
									
										1
									
								
								changelog.d/7419.wip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								changelog.d/7419.wip
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| [Voice Broadcast] Live listening support | ||||
							
								
								
									
										1
									
								
								changelog.d/7421.wip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								changelog.d/7421.wip
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| [Voice Broadcast] Improve rendering in the timeline | ||||
							
								
								
									
										1
									
								
								changelog.d/7428.bugfix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								changelog.d/7428.bugfix
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Fix crash by disabling Flipper on Android API 22 and below - only affects debug version of the application. | ||||
| @ -18,7 +18,7 @@ def markwon = "4.6.2" | ||||
| def moshi = "1.14.0" | ||||
| def lifecycle = "2.5.1" | ||||
| def flowBinding = "1.2.0" | ||||
| def flipper = "0.171.0" | ||||
| def flipper = "0.171.1" | ||||
| def epoxy = "5.0.0" | ||||
| def mavericks = "3.0.1" | ||||
| def glide = "4.14.2" | ||||
|  | ||||
							
								
								
									
										2
									
								
								fastlane/metadata/android/en-US/changelogs/40105040.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								fastlane/metadata/android/en-US/changelogs/40105040.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| Main changes in this version: New features under the labs settings: Rich text composer, new device management, voice broadcast. Still under active development! | ||||
| Full changelog: https://github.com/vector-im/element-android/releases | ||||
| @ -1,6 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
| 
 | ||||
|     <string name="notice_room_invite_no_invitee">%s-nin dəvəti</string> | ||||
|     <string name="notice_room_invite">%1$s dəvət etdi %2$s</string> | ||||
|     <string name="notice_room_invite_you">%1$s sizi dəvət etdi</string> | ||||
| @ -27,37 +26,22 @@ | ||||
|     <string name="notice_room_visibility_shared">bütün otaq üzvləri.</string> | ||||
|     <string name="notice_room_visibility_world_readable">hər kəs.</string> | ||||
|     <string name="notice_room_update">%s bu otağı təkmilləşdirdi.</string> | ||||
| 
 | ||||
| 
 | ||||
|     <string name="notice_avatar_changed_too">(avatar da dəyişdirilib)</string> | ||||
|     <string name="notice_room_name_removed">%1$s otaq adını sildi</string> | ||||
|     <string name="notice_room_topic_removed">%1$s otaq mövzusunu sildi</string> | ||||
|     <string name="notice_room_third_party_invite">%1$s otağa qoşulmaq üçün %2$s dəvətnamə göndərdi</string> | ||||
|     <string name="notice_room_third_party_revoked_invite">%1$s otağa qoşulmaq üçün %2$s dəvətini ləğv etdi</string> | ||||
|     <string name="notice_room_third_party_registered_invite">%1$s %2$s üçün dəvəti qəbul etdi</string> | ||||
| 
 | ||||
|     <string name="notice_crypto_unable_to_decrypt">** Şifrəni aça bilmir: %s **</string> | ||||
|     <string name="notice_crypto_error_unknown_inbound_session_id">Göndərənin cihazı bu mesaj üçün açarları bizə göndərməyib.</string> | ||||
| 
 | ||||
|     <string name="unable_to_send_message">Mesaj göndərmək olmur</string> | ||||
| 
 | ||||
| 
 | ||||
|     <string name="matrix_error">Matris xətası</string> | ||||
| 
 | ||||
| 
 | ||||
|     <string name="encrypted_message">Şifrəli mesaj</string> | ||||
| 
 | ||||
|     <string name="medium_email">Elektron poçt ünvanı</string> | ||||
|     <string name="medium_phone_number">Telefon nömrəsi</string> | ||||
| 
 | ||||
|     <string name="room_displayname_room_invite">Otağa dəvət</string> | ||||
| 
 | ||||
|     <string name="room_displayname_two_members">%1$s və %2$s</string> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     <string name="room_displayname_empty_room">Boş otaq</string> | ||||
| 
 | ||||
|     <string name="initial_sync_start_importing_account">İlkin sinxronizasiya: | ||||
| \nHesab idxal olunur…</string> | ||||
|     <string name="initial_sync_start_importing_account_crypto">İlkin sinxronizasiya: | ||||
| @ -72,9 +56,7 @@ | ||||
| \nTərk olunmuş otaqların idxalı</string> | ||||
|     <string name="initial_sync_start_importing_account_data">İlkin sinxronizasiya: | ||||
| \nHesab məlumatlarının idxalı</string> | ||||
| 
 | ||||
|     <string name="event_status_sending_message">Mesaj göndərilir…</string> | ||||
| 
 | ||||
|     <string name="notice_room_invite_no_invitee_with_reason">%1$s-nin dəvəti. Səbəb: %2$s</string> | ||||
|     <string name="notice_room_invite_with_reason">%1$s dəvət olunmuş %2$s. Səbəb: %3$s</string> | ||||
|     <string name="notice_room_invite_you_with_reason">%1$s sizi dəvət etdi. Səbəb: %2$s</string> | ||||
| @ -86,4 +68,5 @@ | ||||
|     <string name="notice_room_ban_with_reason">%1$s blokladı %2$s. Səbəb: %3$s</string> | ||||
|     <string name="notice_room_third_party_registered_invite_with_reason">%1$s %2$s üçün dəvəti qəbul etdi. Səbəb: %3$s</string> | ||||
|     <string name="notice_room_withdraw_with_reason">%1$s %2$s dəvətini geri götürdü. Səbəb: %3$s</string> | ||||
| </resources> | ||||
|     <string name="notice_room_created_by_you">Otağ yaratdınız</string> | ||||
| </resources> | ||||
| @ -1200,7 +1200,7 @@ | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_app_id">ID d\'aplicació:</string> | ||||
|     <string name="alert_push_are_disabled_description">Revisa la configuració per activar les notificacions</string> | ||||
|     <string name="settings_troubleshoot_test_push_notification_content">Estàs veient la notificació! Clica\'m!</string> | ||||
|     <string name="member_banned_by">Vetat per %1$s</string> | ||||
| @ -2742,4 +2742,7 @@ | ||||
|     <string name="settings_security_incognito_keyboard_summary">Sol·licita que no es desi cap dada personalitzada del teclat en funció del que escrius a les converses (per exemple l\'historial d\'escriptura o el diccionari). Tingues en compte que alguns teclats poden no respectar aquesta configuració.</string> | ||||
|     <string name="settings_security_incognito_keyboard_title">Teclat incògnit</string> | ||||
|     <string name="room_settings_global_block_unverified_info_text">🔒 Has activat el xifrat a només en sessions verificades a totes les sales, a Configuració > Seguretat.</string> | ||||
| </resources> | ||||
|     <string name="device_manager_verification_status_unknown">Estat de verificació desconegut</string> | ||||
|     <string name="login_scan_qr_code">Escaneja codi QR</string> | ||||
|     <string name="push_gateway_item_device_id">ID de sessió:</string> | ||||
| </resources> | ||||
| @ -962,10 +962,10 @@ | ||||
|     <string name="settings_push_rules">Push pravidla</string> | ||||
|     <string name="settings_push_rules_no_rules">Žádná push pravidla nejsou definována</string> | ||||
|     <string name="settings_push_gateway_no_pushers">Žádné push brány nejsou registrovány</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_id">ID aplikace:</string> | ||||
|     <string name="push_gateway_item_push_key">Klíč push:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Zobrazovaný název aplikace:</string> | ||||
|     <string name="push_gateway_item_device_name">Název relace:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_format">Formát:</string> | ||||
|     <string name="preference_voice_and_video">Hlas a video</string> | ||||
| @ -1136,7 +1136,7 @@ | ||||
| \n | ||||
| \nZastavit proces změny hesla\?</string> | ||||
|     <string name="login_set_email_title">Nastavit emailovou adresu</string> | ||||
|     <string name="login_set_email_notice">Nastavte emailovou adresu pro obnovu svého účtu. Později můžete volitelně dovolit lidem, které znáte, aby Vás podle emailu nalezli.</string> | ||||
|     <string name="login_set_email_notice">Nastavte e-mailovou adresu pro obnovení účtu. Později můžete volitelně povolit svým známým, aby vás podle této adresy nalezli.</string> | ||||
|     <string name="login_set_email_mandatory_hint">Email</string> | ||||
|     <string name="login_set_email_optional_hint">Email (volitelné)</string> | ||||
|     <string name="login_set_email_submit">Dále</string> | ||||
| @ -1305,7 +1305,7 @@ | ||||
| \nKlíče nejsou důvěryhodné</string> | ||||
|     <string name="encryption_information_dg_xsigning_disabled">Křížové podpisování není zapnuto</string> | ||||
|     <string name="settings_active_sessions_list">Aktivní relace</string> | ||||
|     <string name="settings_active_sessions_show_all">Ukázat všechny relace</string> | ||||
|     <string name="settings_active_sessions_show_all">Zobrazit všechny relace</string> | ||||
|     <string name="settings_active_sessions_manage">Správa relací</string> | ||||
|     <string name="settings_active_sessions_signout_device">Odhlásit se z této relace</string> | ||||
|     <string name="settings_failed_to_get_crypto_device_info">Žádná kryptografická informace není k dispozici</string> | ||||
| @ -2796,4 +2796,67 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ V této místnosti jsou neověřená zařízení, která nebudou schopna dešifrovat odeslané zprávy.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Nikdy neodesílat šifrované zprávy do neověřených relací v této místnosti.</string> | ||||
|     <string name="action_got_it">Rozumím</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_underline">Použít podtržení</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Použít přeškrtnutí</string> | ||||
|     <string name="rich_text_editor_format_bold">Použít tučný text</string> | ||||
|     <string name="rich_text_editor_format_italic">Použít kurzívu</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Zaznamenávat název, verzi a url pro snadnější rozpoznání relací ve správci relací.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Povolit záznamenávání informací o klientu</string> | ||||
|     <string name="labs_enable_session_manager_summary">Získejte lepší přehled a kontrolu nad všemi relacemi.</string> | ||||
|     <string name="labs_enable_session_manager_title">Použít nový správce relací</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Operační systém</string> | ||||
|     <string name="device_manager_session_details_device_model">Model</string> | ||||
|     <string name="device_manager_session_details_device_browser">Prohlížeč</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Verze</string> | ||||
|     <string name="device_manager_session_details_application_name">Název</string> | ||||
|     <string name="device_manager_session_details_application">Aplikace</string> | ||||
|     <string name="device_manager_push_notifications_description">Přijímat push oznámení v této relaci.</string> | ||||
|     <string name="device_manager_push_notifications_title">Push oznámení</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Ověřením aktuální relace zjistíte stav ověření této relace.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Neznámý stav ověření</string> | ||||
|     <string name="push_gateway_item_enabled">Zapnuto:</string> | ||||
|     <string name="push_gateway_item_device_id">ID relace:</string> | ||||
|     <string name="error_check_network">Něco se pokazilo. Zkontrolujte prosím síťové připojení a zkuste to znovu.</string> | ||||
|     <string name="grant_permission">Udělit oprávnění</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} potřebuje oprávnění k zobrazování oznámení. | ||||
| \nUdělte prosím toto oprávnění.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} potřebuje oprávnění k zobrazování oznámení. Oznámení mohou zobrazovat vaše zprávy, pozvánky atd. | ||||
| \n | ||||
| \nPro zobrazování oznámení povolte přístup na dalších vyskakovacích oknech.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Vyzkoušejte rozšířený textový editor (textový režim již brzy)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Povolit rozšířený textový editor</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Ujistěte se, že znáte původ tohoto kódu. Propojením zařízení poskytnete někomu plný přístup ke svému účtu.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Potvrdit</string> | ||||
|     <string name="qr_code_login_try_again">Zkuste to znovu</string> | ||||
|     <string name="qr_code_login_status_no_match">Neshoduje se\?</string> | ||||
|     <string name="qr_code_login_signing_in">Probíhá přihlašování</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Připojování k zařízení</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">Naskenujte QR kód</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Přihlašování na mobilním zařízením\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">Zobrazit QR kód na tomto zařízení</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Vyberte možnost \"Naskenovat QR kód\"</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Začněte na přihlašovací obrazovce</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Vyberte možnost \"Přihlásit se pomocí QR kódu\"</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Začněte na přihlašovací obrazovce</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Vyberte možnost \"Zobrazit QR kód na tomto zařízení\"</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Přejděte do Nastavení -> Zabezpečení a soukromí -> Zobrazit všechny relace</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Otevřete ${app_name} na vašem druhém zařízení</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">Žádost byla na druhém zařízení zamítnuta.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Propojení nebylo dokončeno v požadovaném čase.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Propojení s tímto zařízením není podporováno.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Neúspěšné připojení</string> | ||||
|     <string name="qr_code_login_header_connected_description">Zkontrolujte vaše přihlášené zařízení, měl by se zobrazit níže uvedený kód. Zkontrolujte, zda níže uvedený kód odpovídá danému zařízení:</string> | ||||
|     <string name="qr_code_login_header_connected_title">Zabezpečené připojení navázáno</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Pomocí odhlášeného zařízení naskenujte níže uvedený QR kód.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Pomocí přihlášeného zařízení naskenujte níže uvedený QR kód:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Přihlásit se pomocí QR kódu</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Pomocí fotoaparátu na tomto zařízení naskenujte QR kód zobrazený na druhém zařízení:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">Naskenovat QR kód</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Pomocí tohoto zařízení se můžete přihlásit do mobilního nebo webového zařízení pomocí QR kódu. Můžete to provést dvěma způsoby:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Přihlásit se pomocí QR kódu</string> | ||||
|     <string name="login_scan_qr_code">Naskenovat QR kód</string> | ||||
| </resources> | ||||
| @ -708,10 +708,10 @@ | ||||
|     <string name="unexpected_error">Unerwarteter Fehler</string> | ||||
|     <string name="keys_backup_setup_skip_title">Bist du sicher\?</string> | ||||
|     <string name="keys_backup_restore_key_enter_hint">Wiederherstellungsschlüssel eingeben</string> | ||||
|     <string name="keys_backup_restoring_waiting_message">Stelle Backup wieder her:</string> | ||||
|     <string name="keys_backup_restoring_waiting_message">Stelle Sicherung wieder her:</string> | ||||
|     <string name="keys_backup_unlock_button">Historie entschlüsseln</string> | ||||
|     <string name="keys_backup_settings_restore_backup_button">Von Sicherung wiederherstellen</string> | ||||
|     <string name="keys_backup_settings_delete_backup_button">Sicherung löschen</string> | ||||
|     <string name="keys_backup_settings_delete_backup_button">Lösche Sicherung</string> | ||||
|     <string name="keys_backup_settings_deleting_backup">Lösche Sicherung …</string> | ||||
|     <string name="keys_backup_settings_delete_confirm_title">Lösche Sicherung</string> | ||||
|     <string name="settings_notification_by_event">Präferenz der Benachrichtigungen nach Ereignis</string> | ||||
| @ -722,7 +722,7 @@ | ||||
|     <string name="settings_troubleshoot_test_fcm_failed_account_missing">[%1$s] | ||||
| \nDieser Fehler ist außerhalb von ${app_name} passiert. Es gibt kein Google-Konto auf dem Gerät. Bitte füge ein Google-Konto hinzu.</string> | ||||
|     <string name="settings_cryptography_manage_keys">Verwaltung der Kryptoschlüssel</string> | ||||
|     <string name="encryption_settings_manage_message_recovery_summary">Schlüssel-Sicherung verwalten</string> | ||||
|     <string name="encryption_settings_manage_message_recovery_summary">Schlüsselsicherung verwalten</string> | ||||
|     <string name="keys_backup_setup_step1_description">Nachrichten in verschlüsselten Räumen sind mit Ende-zu-Ende-Verschlüsselung gesichert. Nur du und der Empfänger haben die Schlüssel um diese Nachrichten zu lesen. | ||||
| \n | ||||
| \nSichere deine Schlüssel, um sie nicht zu verlieren.</string> | ||||
| @ -763,7 +763,7 @@ | ||||
|     <string name="sign_out_bottom_sheet_warning_backup_not_active">Schlüsselsicherung sollte bei allen Sitzungen aktiviert sein, um den Verlust verschlüsselter Nachrichten zu verhindern.</string> | ||||
|     <string name="sign_out_bottom_sheet_dont_want_secure_messages">Ich möchte meine verschlüsselten Nachrichten nicht</string> | ||||
|     <string name="sign_out_bottom_sheet_backing_up_keys">Sichere Schlüssel …</string> | ||||
|     <string name="are_you_sure">Sicher\?</string> | ||||
|     <string name="are_you_sure">Bist du sicher\?</string> | ||||
|     <string name="backup">Sicherung</string> | ||||
|     <string name="sign_out_bottom_sheet_will_lose_secure_messages">Alle verschlüsselten Nachrichten gehen verloren, wenn Du dich abmeldest ohne die Schlüssel gesichert zu haben.</string> | ||||
|     <string name="action_sign_out_confirmation_simple">Bist du sicher, dass du dich abmelden möchtest\?</string> | ||||
| @ -783,7 +783,7 @@ | ||||
|     <string name="keys_backup_setup_step3_text_line1">Deine Schlüssel wurden gesichert.</string> | ||||
|     <string name="keys_backup_setup_step3_text_line2">Dein Wiederherstellungsschlüssel ist ein Sicherungsnetz - du kannst es benutzen um den Zugriff auf deine verschlüsselten Nachrichten wiederherzustellen, falls du deine Passphrase vergisst. | ||||
| \nVerwahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie einem Passwortmanager (oder Safe)</string> | ||||
|     <string name="keys_backup_setup_step3_text_line2_no_passphrase">Bewahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort auf, wie z.B. einem Passwortmanager (oder Tresor) auf</string> | ||||
|     <string name="keys_backup_setup_step3_text_line2_no_passphrase">Bewahre deinen Wiederherstellungsschlüssel an einem sehr sicheren Ort wie einem Passwortmanager (oder Safe) auf</string> | ||||
|     <string name="keys_backup_setup_step3_button_title_no_passphrase">Ich habe eine Kopie angefertigt</string> | ||||
|     <string name="keys_backup_setup_step3_share_recovery_file">Teilen</string> | ||||
|     <string name="keys_backup_banner_recover_line1">Verliere nie wieder verschlüsselte Nachrichten</string> | ||||
| @ -1495,11 +1495,11 @@ | ||||
|     <string name="room_participants_ban_reason">Grund für den Bann</string> | ||||
|     <string name="room_participants_unban_title">Bann des Benutzers aufheben</string> | ||||
|     <string name="room_participants_unban_prompt_msg">Das Aufheben des Bannes wird dem Benutzer erlauben dem Raum wieder beizutreten.</string> | ||||
|     <string name="settings_secure_backup_section_title">Sicheres Backup</string> | ||||
|     <string name="settings_secure_backup_setup">Backup einrichten</string> | ||||
|     <string name="settings_secure_backup_reset">Backup zurücksetzen</string> | ||||
|     <string name="settings_secure_backup_section_title">Verschlüsselte Sicherung</string> | ||||
|     <string name="settings_secure_backup_setup">Sicherung einrichten</string> | ||||
|     <string name="settings_secure_backup_reset">Sicherung zurücksetzen</string> | ||||
|     <string name="settings_secure_backup_enter_to_setup">Auf diesem Gerät einrichten</string> | ||||
|     <string name="settings_secure_backup_section_info">Verlust verschlüsselter Nachrichten und Daten verhindern, indem die Schlüssel für die Entschlüsselung auf dem Server gesichert werden.</string> | ||||
|     <string name="settings_secure_backup_section_info">Verhindere, den Zugriff auf verschlüsselte Nachrichten und Daten zu verlieren, indem du die Verschlüsselungs-Schlüssel auf deinem Server sicherst.</string> | ||||
|     <string name="reset_secure_backup_title">Generiere einen neuen Sicherheitsschlüssel oder setze eine neue Sicherheitspassphrase für dein existierendes Backup.</string> | ||||
|     <string name="reset_secure_backup_warning">Dieses wird deinen aktuellen Schlüssel oder deine aktuelle Phrase ersetzen.</string> | ||||
|     <string name="disabled_integration_dialog_title">Integrationen sind deaktiviert</string> | ||||
| @ -1512,9 +1512,9 @@ | ||||
|     <string name="active_widget_view_action">ANSICHT</string> | ||||
|     <string name="active_widgets_title">Aktive Widgets</string> | ||||
|     <string name="recovery_key_export_saved">Der Sicherheitsschlüssel ist gespeichert worden.</string> | ||||
|     <string name="secure_backup_banner_setup_line1">Backup</string> | ||||
|     <string name="secure_backup_banner_setup_line1">Verschlüsselte Sicherung</string> | ||||
|     <string name="secure_backup_banner_setup_line2">Absicherung gegen den Verlust verschlüsselter Nachrichten</string> | ||||
|     <string name="secure_backup_setup">Richte Backup ein</string> | ||||
|     <string name="secure_backup_setup">Sicherung einrichten</string> | ||||
|     <string name="event_redacted">Nachricht entfernt</string> | ||||
|     <string name="settings_show_redacted">Gelöschte Nachrichten zeigen</string> | ||||
|     <string name="settings_show_redacted_summary">Zeigt einen Platzhalter für gelöschte Nachrichten an</string> | ||||
| @ -1534,7 +1534,7 @@ | ||||
|     <string name="login_server_url_form_common_notice">Gib die Adresse des Servers ein, den du benutzen möchtest</string> | ||||
|     <string name="login_connect_using_matrix_id_submit">Einloggen mit Matrix-ID</string> | ||||
|     <string name="login_signin_matrix_id_title">Einloggen mit Matrix-ID</string> | ||||
|     <string name="login_signin_matrix_id_notice">Wenn du einen Account auf einem Homeserver eingerichtet hast, benutze deine Matrix-ID (z.B. @benutzer:domain.com) und Passwort.</string> | ||||
|     <string name="login_signin_matrix_id_notice">Falls du ein Konto auf einem Heim-Server eingerichtet hast, verwende nachstehend deine Matrix-ID (z. B. @benutzer:domain.com) und dein Passwort.</string> | ||||
|     <string name="login_signin_matrix_id_hint">Matrix-ID</string> | ||||
|     <string name="login_signin_matrix_id_password_notice">Wenn du dein Passwort nicht weißt, gehe zurück um es zurücksetzen zu lassen.</string> | ||||
|     <string name="login_signin_matrix_id_error_invalid_matrix_id">Dies ist keine gültige Benutzerkennung. Erwartetes Format: \'@benutzer:homeserver.org\'</string> | ||||
| @ -1547,7 +1547,7 @@ | ||||
|     <string name="bootstrap_info_text_2">Gib eine Sicherheitsphrase ein, die nur du kennst. Diese wird benutzt um deine Daten auf dem Server geheim zu halten.</string> | ||||
|     <string name="bootstrap_cancel_text">Wenn du jetzt abbrichst und den Zugriff zu deinen Sitzungen verlierst, kannst du verschlüsselte Nachrichten und Daten verlieren. | ||||
| \n | ||||
| \nDu kannst auch ein Backup einrichten und deine Schlüssel in den Einstellungen verwalten.</string> | ||||
| \nDu kannst auch eine Sicherung einrichten und deine Schlüssel in den Einstellungen verwalten.</string> | ||||
|     <string name="room_created_summary_item_by_you">Du hast den Raum erstellt und konfiguriert.</string> | ||||
|     <string name="auth_invalid_login_deactivated_account">Dieser Account ist deaktiviert worden.</string> | ||||
|     <string name="error_saving_media_file">Konnte Mediendatei nicht speichern</string> | ||||
| @ -1575,14 +1575,14 @@ | ||||
|     <string name="a11y_unmute_microphone">Aktiviere Mikrophon</string> | ||||
|     <string name="a11y_stop_camera">Stoppe Kamera</string> | ||||
|     <string name="a11y_start_camera">Starte Kamera</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_title">Backup</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_subtitle">Verlust verschlüsselter Nachrichten und Daten verhindern, indem die Schlüssel für die Entschlüsselung am Server gesichert werden.</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_title">Verschlüsselte Sicherung</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_subtitle">Verhindere, den Zugriff auf verschlüsselte Nachrichten und Daten zu verlieren, indem du die Verschlüsselungs-Schlüssel auf deinem Server sicherst.</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_key_title">Sicherheitsschlüssel benutzen</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_key_subtitle">Generiere einen Sicherheitsschlüssel, welcher z.B. in einem Passwortmanager oder in einem Tresor sicher aufbewahrt werden sollte.</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_key_subtitle">Generiere einen Sicherheitsschlüssel, den du in einem Passwort-Manager oder Tresor sicher aufbewahren solltest.</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_phrase_title">Eine Sicherheitsphrase benutzen</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_phrase_subtitle">Gib eine geheime Phrase ein, die nur du kennst und generiere einen Schlüssel als Backup.</string> | ||||
|     <string name="bottom_sheet_save_your_recovery_key_title">Speichere deinen Sicherheitsschlüssel</string> | ||||
|     <string name="bottom_sheet_save_your_recovery_key_content">Bewahre deinen Sicherheitsschlüssel irgendwo sicher auf, wie z.B. in einem Passwortmanager oder in einem Tresor.</string> | ||||
|     <string name="bottom_sheet_save_your_recovery_key_content">Bewahre deinen Sicherheitsschlüssel in einem Passwort-Manager oder Tresor sicher auf.</string> | ||||
|     <string name="set_a_security_phrase_title">Sicherheitsphrase setzen</string> | ||||
|     <string name="set_a_security_phrase_notice">Gib eine Sicherheitsphrase ein, welche nur du kennst und deine Daten auf dem Server geheim halten soll.</string> | ||||
|     <string name="set_a_security_phrase_hint">Sicherheitsphrase</string> | ||||
| @ -1810,7 +1810,7 @@ | ||||
|     <string name="room_alias_local_address_empty">Dieser Raum hat keine lokalen Adressen</string> | ||||
|     <string name="room_alias_local_address_subtitle">Füge Adressen für diesen Raum hinzu, damit andere Nutzer ihn auf %1$s finden können</string> | ||||
|     <string name="room_alias_local_address_title">Lokale Adresse</string> | ||||
|     <string name="room_alias_address_hint">Neue öffentliche Adresse (z.B. #alias:server)</string> | ||||
|     <string name="room_alias_address_hint">Neue öffentliche Adresse (z. B. #alias:server)</string> | ||||
|     <string name="room_alias_address_empty">Noch keine weiteren öffentlichen Adressen vorhanden.</string> | ||||
|     <string name="room_alias_address_empty_can_add">Noch keine weiteren öffentlichen Adressen vorhanden, füge unten eine hinzu.</string> | ||||
|     <string name="room_alias_delete_confirmation">Die Adresse \"%1$s\" löschen\?</string> | ||||
| @ -2741,4 +2741,67 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ Es befinden sich nicht verifizierte Geräte in diesem Raum. Sie werden deine Nachrichten nicht entschlüsseln können.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Niemals verschlüsselte Nachrichten zu unverifizierten Sitzungen in diesem Raum senden.</string> | ||||
|     <string name="action_got_it">Verstanden</string> | ||||
| </resources> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Probiere den Rich-Text-Editor aus (bald auch mit Plain-Text-Modus)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Aktiviere Rich-Text-Editor</string> | ||||
|     <string name="device_manager_session_details_device_browser">Browser</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Durchgestrichen formatieren</string> | ||||
|     <string name="rich_text_editor_format_italic">Kursiv formatieren</string> | ||||
|     <string name="rich_text_editor_format_bold">Fett formatieren</string> | ||||
|     <string name="rich_text_editor_format_underline">Unterstrichen formatieren</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} benötigt die Berechtigung zur Anzeige von Benachrichtigungen. | ||||
| \nBitte gewähre diese Berechtigung.</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Bezeichnung, Version und URL der Anwendung registrieren, damit diese Sitzung in der Sitzungsverwaltung besser erkennbar ist.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Anwendungsinformationen erfassen</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="labs_enable_session_manager_summary">Bessere Übersicht und Kontrolle über all deine Sitzungen.</string> | ||||
|     <string name="labs_enable_session_manager_title">Aktiviere neue Sitzungsverwaltung</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Betriebssystem</string> | ||||
|     <string name="device_manager_session_details_device_model">Modell</string> | ||||
|     <string name="device_manager_session_details_application_version">Version</string> | ||||
|     <string name="device_manager_session_details_application_name">Name</string> | ||||
|     <string name="device_manager_session_details_application">Anwendung</string> | ||||
|     <string name="device_manager_push_notifications_description">Erhalte Push-Benachrichtigungen in dieser Sitzung.</string> | ||||
|     <string name="device_manager_push_notifications_title">Push-Benachrichtigungen</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Verifiziere deine aktuelle Sitzung, um den Verifizierungsstatus dieser Sitzung anzuzeigen.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Unbekannter Verifizierungsstatus</string> | ||||
|     <string name="push_gateway_item_device_id">Sitzungs-ID:</string> | ||||
|     <string name="push_gateway_item_enabled">Aktiviert:</string> | ||||
|     <string name="error_check_network">Etwas ist schiefgelaufen. Bitte überprüfe deine Internetverbindung und versuche es erneut.</string> | ||||
|     <string name="grant_permission">Berechtigung geben</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} braucht die Berechtigung, um Benachrichtigungen anzuzeigen. Benachrichtigungen können deine Nachrichten, Einladungen etc. anzeigen. | ||||
| \n | ||||
| \nBitte erlaube den Zugriff im nächsten Dialog, damit Benachrichtigungen angezeigt werden können.</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Bitte vergewissere dich, dass du den Ursprung dieses Codes kennst. Durch Verbindung neuer Geräte gewährst du vollen Zugriff auf dein Konto.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Bestätigen</string> | ||||
|     <string name="qr_code_login_try_again">Erneut versuchen</string> | ||||
|     <string name="qr_code_login_status_no_match">Keine Übereinstimmung\?</string> | ||||
|     <string name="qr_code_login_signing_in">Du wirst angemeldet</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Verbinde mit Gerät</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">QR-Code einlesen</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Mobiles Gerät anmelden\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">QR-Code auf diesem Gerät anzeigen</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Wähle „QR-Code einlesen“</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Beginne auf dem Anmeldebildschirm</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Wähle „Mit QR-Code anmelden“</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Beginne auf dem Anmeldebildschirm</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Wähle \'QR-Code auf diesem Gerät anzeigen\'</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Gehe zu Einstellungen -> Sicherheit und Privatsphäre -> Alle Sitzungen anzeigen</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Öffne ${app_name} auf deinem anderen Gerät</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">Die Anfrage wurde auf dem anderen Gerät abgelehnt.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Die Verbindung konnte nicht in der erforderlichen Zeit hergestellt werden.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Verbindung mit diesem Gerät nicht unterstützt.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Verbindung fehlgeschlagen</string> | ||||
|     <string name="qr_code_login_header_connected_description">Überprüfe dein angemeldetes Gerät. Der unten gezeigte Code sollte angezeigt werden. Bestätige, dass beide Codes übereinstimmen:</string> | ||||
|     <string name="qr_code_login_header_connected_title">Sichere Verbindung hergestellt</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Lese den unten angezeigten QR-Code mit deinem nicht angemeldeten Gerät ein.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Benutze dein angemeldetes Gerät um den unten angezeigten QR-Code einzulesen:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Mit QR-Code anmelden</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Benutze die Kamera auf diesem Gerät um den vom anderen Gerät angezeigten QR-Code zu scannen:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">QR-Code scannen</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Du kannst dieses Gerät benutzen um ein anderes Gerät per QR-Code anzumelden. Dafür gibt es zwei Wege:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Mit QR-Code anmelden</string> | ||||
|     <string name="login_scan_qr_code">QR-Code scannen</string> | ||||
| </resources> | ||||
| @ -1158,10 +1158,10 @@ | ||||
|     <string name="settings_push_rules">Tõuketeavituste reeglid</string> | ||||
|     <string name="settings_push_rules_no_rules">Tõuketeavituste reegleid pole kirjeldatud</string> | ||||
|     <string name="settings_push_gateway_no_pushers">Tõuketeavituste võrguväravaid pole registreeritud</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_id">Rakenduse ID:</string> | ||||
|     <string name="push_gateway_item_push_key">Tõuketeenuse võti:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Rakenduse kuvatav nimi:</string> | ||||
|     <string name="push_gateway_item_device_name">Sessiooni nimi:</string> | ||||
|     <string name="push_gateway_item_url">URL:</string> | ||||
|     <string name="push_gateway_item_format">Vorming:</string> | ||||
|     <string name="preference_voice_and_video">Heli ja video</string> | ||||
| @ -2733,4 +2733,67 @@ | ||||
|     <string name="command_description_devtools">Ava arendaja töövahendite vaade</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Ära iialgi saada selles jututoas krüptitud sõnumeid verifitseerimata sessioonidesse.</string> | ||||
|     <string name="action_got_it">Selge lugu</string> | ||||
| </resources> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Proovi vormindatud teksti alusel töötavat tekstitoimetit (varsti lisandub ka vormindamata teksti režiim)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Võta kasutusele vormindatud teksti pruukiv tekstitoimeti</string> | ||||
|     <string name="qr_code_login_header_connected_description">Vaata seadet, kus sa oled Matrix\'i võtku loginud - seal peaks nüüd kuvatama QR-koodi. Kinnita, et allpool toodud QR-kood on sama kui tolles seadmes kuvatav kood:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Sa võid seda seadet kasutada nutiseadme või veebirakenduse sisselogimiseks QR-koodi alusel. Sa saad seda teha kahel moel:</string> | ||||
|     <string name="rich_text_editor_format_underline">Kasuta allajoonitud kirja</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Kasuta läbijoonitud kirja</string> | ||||
|     <string name="rich_text_editor_format_italic">Kasuta kaldkirja</string> | ||||
|     <string name="rich_text_editor_format_bold">Kasuta paksu kirja</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Palun vaata, et sa kindlasti tead, kust see QR-kood kuvatakse. Sellisel viisil seadmete sidumisel sa annad oma kasutajakontole täiemahulise ligipääsu.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Kinnita</string> | ||||
|     <string name="qr_code_login_try_again">Proovi uuesti</string> | ||||
|     <string name="qr_code_login_status_no_match">Ei klapi\?</string> | ||||
|     <string name="qr_code_login_signing_in">Logime sind võrku</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Loon ühendust seadmega</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">Loe QR-koodi</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Kas logid sisse nutiseadmest\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">Näita selles seadmes QR-koodi</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Vali „Loe QR-koodi“</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Alusta sisselogimisvaatest</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Vali „Logi võrku QR-koodi abil“</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Alusta sisselogimisvaatest</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Vali „Näita selles seadmes QR-koodi“</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Ava Seadistused -> Turvalisus ja privaatsus -> Näita kõiki sessioone</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Ava ${app_name} oma teises seades</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">Teine seade lükkas päringu tagasi.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Sidumine ei lõppenud etteantud aja jooksul.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Sidumine selle seadmega ei ole toetatud.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Seoste loomine ei õnnestunud</string> | ||||
|     <string name="qr_code_login_header_connected_title">Turvaline ühendus on olemas</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Loe QR-koodi seadmega, kus sa oled Matrix\'i võrgust välja loginud.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Järgneva QR-koodi skaneerimiseks kasuta seadet, kus sa oled Matrix\'i võrku loginud:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Logi sisse QR-koodi abil</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Kasuta selle seadme kaamerat ja logi sisse teises seadmes kuvatud QR-koodi alusel:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">Loe QR-koodi</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Sessioonide paremaks tuvastamiseks saad nüüd sessioonihalduris salvestada klientrakenduse nime, versiooni ja aadressi.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Luba klientrakenduse teabe salvestamine</string> | ||||
|     <string name="labs_enable_session_manager_summary">Sellega saad parema ülevaate oma sessioonidest ja võimaluse neid mugavasti hallata.</string> | ||||
|     <string name="labs_enable_session_manager_title">Kasuta uut sessioonihaldurit</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Logi sisse QR-koodi abil</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Operatsioonisüsteem</string> | ||||
|     <string name="device_manager_session_details_device_model">Mudel</string> | ||||
|     <string name="device_manager_session_details_device_browser">Brauser</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Versioon</string> | ||||
|     <string name="device_manager_session_details_application_name">Nimi</string> | ||||
|     <string name="device_manager_session_details_application">Rakendus</string> | ||||
|     <string name="device_manager_push_notifications_description">Luba selles sessioonis tõuketeavitused.</string> | ||||
|     <string name="device_manager_push_notifications_title">Tõuketeavitused</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Selle sessiooni olekut ei saa tuvastada enne kui oled ta verifitseerinud.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Verifitseerimise olek on määratlemata</string> | ||||
|     <string name="login_scan_qr_code">Loe QR-koodi</string> | ||||
|     <string name="push_gateway_item_enabled">Kasutusel:</string> | ||||
|     <string name="push_gateway_item_device_id">Sessiooni tunnus:</string> | ||||
|     <string name="error_check_network">Midagi läks nüüd sassi. Palun kontrolli oma seadme võrguühendust ja proovi uuesti.</string> | ||||
|     <string name="grant_permission">Anna õigused</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} vajab teavituste näitamiseks õigusi. | ||||
| \nPalun luba vastavad õigused.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} vajab teavituste näitamiseks õigusi. Teavituste sisuks võivad olla sulle saadetud sõnumid, kutsed ja muud olulist. | ||||
| \n | ||||
| \nJärgmistes vaadetes palun anna sellele rakendusele teavituste kuvamiseks vajalikud õigused.</string> | ||||
| </resources> | ||||
| @ -1492,10 +1492,10 @@ | ||||
|     <string name="settings_troubleshoot_test_token_registration_quick_fix">ثبت ژتون</string> | ||||
|     <string name="push_gateway_item_format">فرمت:</string> | ||||
|     <string name="push_gateway_item_url">آدرس:</string> | ||||
|     <string name="push_gateway_item_device_name">نام نشست:</string> | ||||
|     <string name="push_gateway_item_app_display_name">نام برنامه:</string> | ||||
|     <string name="push_gateway_item_push_key">کلید push:</string> | ||||
|     <string name="push_gateway_item_app_id">شناسه برنامه:</string> | ||||
|     <string name="push_gateway_item_device_name">نام نمایشی نشست:</string> | ||||
|     <string name="push_gateway_item_app_display_name">نام نمایشی کاره:</string> | ||||
|     <string name="push_gateway_item_push_key">کلید ارسال:</string> | ||||
|     <string name="push_gateway_item_app_id">شناسهٔ کاره:</string> | ||||
|     <string name="settings_push_gateway_no_pushers">هیچ push gatewayای ثبت نشده است</string> | ||||
|     <string name="settings_push_rules_no_rules">هیچ قانونی برای push تعریف نشده است</string> | ||||
|     <string name="navigate_to_room_when_already_in_the_room">شما در حال مشاهده این اتاق هستید!</string> | ||||
| @ -2720,4 +2720,10 @@ | ||||
|     <string name="command_description_devtools">گشودن صفحهٔ ابزارهای توسعهدهنده</string> | ||||
|     <string name="labs_enable_deferred_dm_title">به کار انداختن پیامهای مستقیم تعویقی</string> | ||||
|     <string name="action_got_it">گرفتم</string> | ||||
| </resources> | ||||
|     <string name="tooltip_attachment_voice_broadcast">آغاز یک پخش همگانی صوتی</string> | ||||
|     <string name="command_description_table_flip">(╯°□°)╯︵ ┻━┻ را به ابتدای پیام متنی خام میافزاید</string> | ||||
|     <string name="attachment_type_voice_broadcast">پخش همگانی صدا</string> | ||||
|     <string name="grant_permission">اعطای دسترسی</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">ویرایشگر متن غنی را بیازمایید (حالت متن خام به زودی)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">به کار انداختن ویرایشگر متن غنی</string> | ||||
| </resources> | ||||
| @ -869,10 +869,10 @@ | ||||
|     <string name="settings_push_rules">Règles de notification</string> | ||||
|     <string name="settings_push_rules_no_rules">Aucune règle de notification définie</string> | ||||
|     <string name="settings_push_gateway_no_pushers">Aucune passerelle de notification enregistrée</string> | ||||
|     <string name="push_gateway_item_app_id">app_id :</string> | ||||
|     <string name="push_gateway_item_push_key">push_key :</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name :</string> | ||||
|     <string name="push_gateway_item_device_name">session_name :</string> | ||||
|     <string name="push_gateway_item_app_id">App ID :</string> | ||||
|     <string name="push_gateway_item_push_key">Clé Push :</string> | ||||
|     <string name="push_gateway_item_app_display_name">Nom d’affichage de l’application :</string> | ||||
|     <string name="push_gateway_item_device_name">Nom d’affichage de la session :</string> | ||||
|     <string name="push_gateway_item_url">URL :</string> | ||||
|     <string name="push_gateway_item_format">Format :</string> | ||||
|     <string name="preference_voice_and_video">Voix et vidéo</string> | ||||
| @ -2742,4 +2742,34 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ Il y a des appareils non vérifiés dans ce salon, ils ne pourront pas déchiffrer vos messages envoyés.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Ne jamais envoyer de messages chiffrés aux sessions non vérifiées dans ce salon.</string> | ||||
|     <string name="action_got_it">Compris</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_underline">Souligner le texte</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Barrer le texte</string> | ||||
|     <string name="rich_text_editor_format_italic">Mettre en italique</string> | ||||
|     <string name="rich_text_editor_format_bold">Mettre en gras</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Enregistre le nom du client, sa version, et son URL pour retrouvez vos sessions plus facilement dans le gestionnaire de sessions.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Activer l’enregistrement des informations du client</string> | ||||
|     <string name="labs_enable_session_manager_summary">Ayez une meilleur visibilité et plus de contrôle sur toutes vos sessions.</string> | ||||
|     <string name="labs_enable_session_manager_title">Activer le nouveau gestionnaire de session</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Système d’exploitation</string> | ||||
|     <string name="device_manager_session_details_device_model">Modèle</string> | ||||
|     <string name="device_manager_session_details_device_browser">Navigateur</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Version</string> | ||||
|     <string name="device_manager_session_details_application_name">Nom</string> | ||||
|     <string name="device_manager_session_details_application">Application</string> | ||||
|     <string name="device_manager_push_notifications_description">Recevoir les notifications push sur cette session.</string> | ||||
|     <string name="device_manager_push_notifications_title">Notifications push</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Vérifiez votre session actuelle pour découvrir le statut de vérification de cette session.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Status de vérification inconnu</string> | ||||
|     <string name="push_gateway_item_enabled">Activer :</string> | ||||
|     <string name="push_gateway_item_device_id">Identifiant de session :</string> | ||||
|     <string name="error_check_network">Quelque chose s’est mal passé. Vérifiez votre connexion réseau et réessayez.</string> | ||||
|     <string name="grant_permission">Accorder la permission</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} a besoin d’une permission pour afficher les notifications. | ||||
| \nVeuillez accorder la permission.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} a besoin de la permission pour afficher les notifications. Les notifications peuvent afficher vos messages, vos invitations, etc. | ||||
| \n | ||||
| \nVeuillez autoriser l’accès sur la prochaine fenêtre pour pouvoir voir des notifications.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Essayer l’éditeur de texte formaté (le mode texte brut arrive bientôt)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Activer l’éditeur de texte formaté</string> | ||||
| </resources> | ||||
| @ -569,7 +569,7 @@ Matrixban az üzenetek láthatósága hasonlít az e-mailre. Az üzenet törlés | ||||
|     <string name="settings_troubleshoot_diagnostic_success_status">Alapszintű diagnosztika nem talált hibát. Ha még mindig nem kapsz értesítéseket, kérlek küldj egy hiba jegyet amivel segítheted a hibakeresésünket.</string> | ||||
|     <string name="settings_troubleshoot_diagnostic_failure_status_with_quickfix">Egy vagy több teszt is sikertelen volt, próbáld ki a javasolt javítást, javításokat.</string> | ||||
|     <string name="settings_troubleshoot_diagnostic_failure_status_no_quickfix">Egy vagy több teszt sikertelenül végződött, kérlek küldj egy hibabejelentést ami segít nekünk a problémát kivizsgálni.</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_title">Rendszer beállítások.</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_title">Rendszerbeállítások.</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_success">Az értesítések engedélyezve vannak a rendszerbeállításokban.</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_failed">Az értesítések tiltva vannak a rendszerbeállításokban. | ||||
| Kérlek ellenőrizd a rendszerbeállításokat.</string> | ||||
| @ -582,7 +582,7 @@ Kérlek ellenőrizd a fiókbeállításokat.</string> | ||||
|     <string name="settings_troubleshoot_test_device_settings_title">Munkamenet beállítások.</string> | ||||
|     <string name="settings_troubleshoot_test_device_settings_success">Az értesítések engedélyezve vannak ezen az munkameneten.</string> | ||||
|     <string name="settings_troubleshoot_test_device_settings_failed">Az értesítések tiltva vannak ezen a munkameneten. Kérlek ellenőrizd a ${app_name} beállításokat.</string> | ||||
|     <string name="settings_troubleshoot_test_device_settings_quickfix">Engedélyez</string> | ||||
|     <string name="settings_troubleshoot_test_device_settings_quickfix">Engedélyezés</string> | ||||
|     <string name="settings_troubleshoot_test_play_services_title">Play Szolgáltatások ellenőrzése</string> | ||||
|     <string name="settings_troubleshoot_test_play_services_success">Google Play Services APK elérhető és a legújabb verziójú.</string> | ||||
|     <string name="settings_troubleshoot_test_play_services_failed">"${app_name} a Google Play Services-t használja  a „push” értesítések fogadásához, de úgy tűnik az nincs megfelelően beállítva: | ||||
| @ -824,18 +824,18 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze | ||||
|     <string name="navigate_to_room_when_already_in_the_room">Már nézed ezt a szobát!</string> | ||||
|     <string name="settings_general_title">Általános</string> | ||||
|     <string name="settings_preferences">Beállítások</string> | ||||
|     <string name="settings_security_and_privacy">Biztonság & Adatvédelem</string> | ||||
|     <string name="settings_security_and_privacy">Biztonság és adatvédelem</string> | ||||
|     <string name="settings_push_rules">„Push” szabályok</string> | ||||
|     <string name="settings_push_rules_no_rules">„Push” szabályok nincsenek</string> | ||||
|     <string name="settings_push_gateway_no_pushers">„Push” átjárók nincsenek regisztrálva</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_id">Alk azon:</string> | ||||
|     <string name="push_gateway_item_push_key">Push kulcs:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Alk. képernyő név:</string> | ||||
|     <string name="push_gateway_item_device_name">Munkamenet képernyő név:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_format">Formátum:</string> | ||||
|     <string name="preference_voice_and_video">Hang & Videó</string> | ||||
|     <string name="preference_root_help_about">Segítség & Névjegy</string> | ||||
|     <string name="preference_voice_and_video">Hang és videó</string> | ||||
|     <string name="preference_root_help_about">Súgó és névjegy</string> | ||||
|     <string name="settings_troubleshoot_test_token_registration_quick_fix">Token regisztrálása</string> | ||||
|     <string name="send_suggestion">Javaslat tétel</string> | ||||
|     <string name="send_suggestion_content">A javaslatodat kérlek ír le alulra.</string> | ||||
| @ -897,7 +897,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze | ||||
|     <string name="settings_discovery_no_msisdn">Amint hozzáadtál egy telefonszámot megjelenik a felderítési beállítási lehetőség.</string> | ||||
|     <string name="settings_discovery_disconnect_identity_server_info">Az azonosítási szerverről való lecsatlakozással nem leszel mások által megtalálható és másokat sem tudsz meghívni e-mail címmel vagy telefonszámmal.</string> | ||||
|     <string name="settings_discovery_msisdn_title">Felderíthető telefonszámok</string> | ||||
|     <string name="settings_discovery_confirm_mail">Megerősítő levelet küldtünk ide: %s, ellenőrizd az e-mailedet és kattints a megerősítő hivatkozásra</string> | ||||
|     <string name="settings_discovery_confirm_mail">E-mailt küldtünk ide: %s, ellenőrizd és kattints a megerősítő hivatkozásra</string> | ||||
|     <string name="settings_discovery_enter_identity_server">Add meg az azonosítási szerver URL-jét</string> | ||||
|     <string name="settings_discovery_bad_identity_server">Az azonosítási szerverhez nem lehet csatlakozni</string> | ||||
|     <string name="settings_discovery_please_enter_server">Kérlek add meg az azonosítási szerver url-jét</string> | ||||
| @ -1391,7 +1391,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze | ||||
|     <string name="invite_users_to_room_failure">Felhasználókat nem tudtuk meghívni. Ellenőrizd azokat a felhasználókat akiket meg szeretnél hívni és próbáld újra.</string> | ||||
|     <string name="event_redacted">Üzenet eltávolítva</string> | ||||
|     <string name="settings_show_redacted_summary">Helykitöltő mutatása a törölt szövegek helyett</string> | ||||
|     <string name="settings_discovery_confirm_mail_not_clicked">Megerősítő levelet küldtünk ide: %s, először ellenőrizd az e-mailedet és kattints a megerősítő hivatkozásra</string> | ||||
|     <string name="settings_discovery_confirm_mail_not_clicked">E-mailt küldtünk ide: %s, először ellenőrizd és kattints a megerősítő hivatkozásra</string> | ||||
|     <string name="uploads_media_title">MÉDIA</string> | ||||
|     <string name="uploads_files_title">FÁJLOK</string> | ||||
|     <string name="uploads_files_subtitle">%1$s itt: %2$s</string> | ||||
| @ -2709,4 +2709,100 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze | ||||
|     <string name="labs_enable_deferred_dm_title">Késleltetett közvetlen üzenetek engedélyezése</string> | ||||
|     <string name="labs_enable_new_app_layout_summary">Egyszerűsített Element opcionálisan lapokkal</string> | ||||
|     <string name="labs_enable_new_app_layout_title">Új kinézet engedélyezése</string> | ||||
| </resources> | ||||
|     <string name="device_manager_learn_more_session_rename">Más felhasználók akikkel közvetlenül vagy szobában beszélgetsz látják a teljes listát a munkameneteidről. | ||||
| \n | ||||
| \nEzzel ők biztosak lehetnek abban, hogy ténylegesen veled beszélgetnek. Ez azt is jelenti, hogy látják a munkamenet nevét amit itt megadsz.</string> | ||||
|     <string name="device_manager_learn_more_sessions_verified">Ellenőrzött munkamenetbe a neveddel és jelszavaddal léptek be és ellenőrizve lett vagy a biztonsági jelmondattal vagy másik munkamenetből. | ||||
| \n | ||||
| \nEz azt jelenti, hogy tartalmazzák a titkosítási kulcsokat az régi üzenetekhez, és biztosítja a többieket a kommunikációban, hogy ezt a munkamenetet tényleg te használod.</string> | ||||
|     <string name="rich_text_editor_format_underline">Aláhúzott</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Áthúzott</string> | ||||
|     <string name="rich_text_editor_format_italic">Dőlt</string> | ||||
|     <string name="rich_text_editor_format_bold">Félkövér</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Kliens neve, verziója és url felvétele a munkamenet könnyebb azonosításához a munkamenet kezelőben.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Kliens információ felvételének engedélyezése</string> | ||||
|     <string name="labs_enable_session_manager_summary">Jobb áttekintés és felügyelet a munkamenetek felett.</string> | ||||
|     <string name="labs_enable_session_manager_title">Új munkamenet kezelő engedélyezése</string> | ||||
|     <string name="device_manager_learn_more_session_rename_title">Munkamenet átnevezése</string> | ||||
|     <string name="device_manager_learn_more_sessions_verified_title">Hitelesített munkamenetek</string> | ||||
|     <string name="device_manager_learn_more_sessions_unverified">Az ellenőrizetlen munkamenetek azok amikre a felhasználói neveddel és jelszavaddal léptek be de nem lett ellenőrizve. | ||||
| \n | ||||
| \nMindenképpen győződj meg arról, hogy felismered ezeket a munkameneteket mert lehet, hogy illetéktelenül használják a fiókodat.</string> | ||||
|     <string name="device_manager_learn_more_sessions_unverified_title">Ellenőrizetlen munkamenetek</string> | ||||
|     <string name="device_manager_learn_more_sessions_inactive">Az inaktív munkamenetek azok amiket egy ideje nem használtál, de továbbra is megkapják a titkosítási kulcsokat. | ||||
| \n | ||||
| \nA nem aktív munkamenetek törlésével növelhető a biztonság és a sebesség valamint könnyebb lesz felismerni a gyanús munkameneteket.</string> | ||||
|     <string name="device_manager_learn_more_sessions_inactive_title">Nem aktív munkamenetek</string> | ||||
|     <string name="device_manager_session_rename_warning">Fontos, hogy a munkamenet neve a kommunikációban résztvevők számára látható.</string> | ||||
|     <string name="device_manager_session_rename_description">Az egyedi munkamenet név segíthet az eszköz könnyebb felismerésében.</string> | ||||
|     <string name="device_manager_session_rename_edit_hint">Munkamenet neve</string> | ||||
|     <string name="device_manager_session_rename">Munkamenet átnevezése</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Operációs rendszer</string> | ||||
|     <string name="device_manager_session_details_device_model">Modell</string> | ||||
|     <string name="device_manager_session_details_device_browser">Böngésző</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Verzió</string> | ||||
|     <string name="device_manager_session_details_application_name">Név</string> | ||||
|     <string name="device_manager_session_details_application">Alkalmazás</string> | ||||
|     <string name="device_manager_push_notifications_description">Push értesítések fogadása ebben a munkamenetben.</string> | ||||
|     <string name="device_manager_push_notifications_title">Push értesítések</string> | ||||
|     <string name="device_manager_session_overview_signout">Kijelentkezés ebből a munkamenetből</string> | ||||
|     <string name="device_manager_other_sessions_description_unverified_current_session">Ellenőrizetlen · A jelenlegi munkameneted</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Ellenőrizd a jelenlegi munkamenetedet, hogy ismert állapotba kerüljön.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Ismeretlen ellenőrzési státusz</string> | ||||
|     <string name="tooltip_attachment_voice_broadcast">Hang közvetítés indítása</string> | ||||
|     <string name="key_authenticity_not_guaranteed">A titkosított üzenetek valódiságát ezen az eszközön nem lehet garantálni.</string> | ||||
|     <string name="settings_security_incognito_keyboard_summary">Utasítja a billentyűzetet, hogy ne mentsen személyre szabott adatokat, mint előzmények vagy szótár abból amit a beszélgetésekben írsz. Vedd figyelembe, hogy nem minden billentyűzet veszi ezt figyelembe.</string> | ||||
|     <string name="settings_security_incognito_keyboard_title">Inkognitó billentyűzet</string> | ||||
|     <string name="command_description_table_flip">(╯°□°)╯︵ ┻━┻ -t tesz a szöveg elejére</string> | ||||
|     <string name="attachment_type_voice_broadcast">Hang közvetítés</string> | ||||
|     <string name="push_gateway_item_enabled">Engedélyezve:</string> | ||||
|     <string name="push_gateway_item_device_id">Munkamenet azon.:</string> | ||||
|     <string name="error_check_network">Valami nem sikerült. Kérlek ellenőrizd a hálózati kapcsolatot és próbáld újra.</string> | ||||
|     <string name="command_description_devtools">A fejlesztői eszközök képernyő megnyitása</string> | ||||
|     <string name="room_settings_global_block_unverified_info_text">🔒 Bekapcsoltad a Biztonsági beállításoknál, hogy csak ellenőrzött munkamenetek számára legyen titkosítva az üzenet bármely szobában.</string> | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ Ellenőrizetlen eszközök vannak a szobában, ezek nem fogják tudni visszafejteni az általad küldött üzeneteket.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Sose küldj titkosított üzenetet ellenőrizetlen munkamenetbe ebből a munkamenetből ebben a szobában.</string> | ||||
|     <string name="grant_permission">Engedély megadása</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} alkalmazásnak értesítések megjelenítéséhez engedélyre van szüksége. | ||||
| \nKérjük, adj rá engedélyt.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} alkalmazásnak szüksége van engedélyre az értesítések megjelenítéséhez. Az értesítés megjelenítheti az üzenetet, meghívót, stb. | ||||
| \n | ||||
| \nA következő felugró ablakban adj rá engedélyt, hogy az értesítések megjelenhessenek.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Próbálja ki az új szövegbevitelt (hamarosan érkezik a sima szöveges üzemmód)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Vizuális szerkesztő engedélyezése</string> | ||||
|     <string name="action_got_it">Értem</string> | ||||
|     <string name="qr_code_login_status_no_match">Nem egyezik\?</string> | ||||
|     <string name="qr_code_login_signing_in">Bejelentkeztetés</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Mobil eszközzel jelentkezel be\?</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Kezd a bejelentkező képernyőn</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Kezd a bejelentkező képernyőn</string> | ||||
|     <string name="qr_code_login_header_connected_description">Nézd meg a már bejelentkezett eszközödet, az alábbi kódot kell megjelenítenie. Erősítsd meg, hogy az alábbi kód megegyezik a másik eszközön láthatóval:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Használd a már belépett eszközt az alábbi QR kód beolvasásához:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Ezzel az eszközzel, QR kód segítségével, bejelentkezhetsz mobil és webes munkamenetbe. Két lehetőséged is van:</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Győződj meg a kód eredetéről. Az eszközök összekötésével esetleg valakinek teljes hozzáférést adhatsz a fiókodhoz.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Megerősítés</string> | ||||
|     <string name="qr_code_login_try_again">Próbáld újra</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Csatlakozás az eszközhöz</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">QR kód beolvasása</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">QR kód megjelenítése ezen az eszközön</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Válaszd ezt: „QR kód beolvasása”</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Válaszd ezt: „Belépés QR kóddal”</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Válaszd ezt: „QR kód megjelenítése ezen az eszközön”</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Menj a Beállítások -> Biztonság és Adatvédelem -> Minden munkamenet megjelenítése menübe</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Nyisd meg a(z) ${app_name} alkalmazást a másik eszközön</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">A kérést elutasították a másik eszközön.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Az összekötés az elvárt időn belül nem fejeződött be.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Összekötés ezzel az eszközzel nem támogatott.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Kapcsolat sikertelen</string> | ||||
|     <string name="qr_code_login_header_connected_title">Biztonságos kapcsolat beállítva</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">A kijelentkezett eszközzel olvasd be a QR kódot alább.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Belépés QR kóddal</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Használd a kamerát ezen az eszközön a másik eszközödön megjelenő QR kód beolvasására:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">QR kód beolvasása</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Belépés QR kóddal</string> | ||||
|     <string name="login_scan_qr_code">QR kód beolvasása</string> | ||||
| </resources> | ||||
| @ -1240,10 +1240,10 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string> | ||||
|     <string name="preference_voice_and_video">Suara & Video</string> | ||||
|     <string name="push_gateway_item_format">Format:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_device_name">Nama Tampilan Sesi:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Nama Tampilan Aplikasi:</string> | ||||
|     <string name="push_gateway_item_push_key">Kunci Dorongan:</string> | ||||
|     <string name="push_gateway_item_app_id">ID Aplikasi:</string> | ||||
|     <string name="settings_push_gateway_no_pushers">Tidak ada gateway dorong terdaftar</string> | ||||
|     <string name="settings_push_rules_no_rules">Tidak ada aturan push yang ditentukan</string> | ||||
|     <string name="settings_push_rules">Aturan Push</string> | ||||
| @ -1632,7 +1632,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string> | ||||
|     <string name="login_set_email_submit">Lanjut</string> | ||||
|     <string name="login_set_email_optional_hint">Email (opsional)</string> | ||||
|     <string name="login_set_email_mandatory_hint">Email</string> | ||||
|     <string name="login_set_email_notice">Atur sebuah alamat email untuk memulihkan akun Anda. Nantinya, Anda dapat mengizinkan orang yang Anda tahu untuk menemukan Anda dari email secara opsional.</string> | ||||
|     <string name="login_set_email_notice">Atur sebuah alamat email untuk memulihkan akun Anda. Nantinya, Anda dapat mengizinkan orang yang Anda tahu untuk menemukan Anda dari email ini secara opsional.</string> | ||||
|     <string name="login_set_email_title">Atur alamat email</string> | ||||
|     <string name="login_reset_password_cancel_confirmation_content">Kata sandi Anda belum diubah. | ||||
| \n | ||||
| @ -2690,4 +2690,67 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string> | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ Ada perangkat yang belum diverifikasi di ruangan ini, mereka tidak akan mendekripsikan pesan yang Anda kirim.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Jangan kirim pesan terenkripsi ke sesi yang belum diverifikasi di ruangan ini.</string> | ||||
|     <string name="action_got_it">Saya mengerti</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_underline">Terapkan format garis bawah</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Terapkan format coret</string> | ||||
|     <string name="rich_text_editor_format_italic">Terapkan format miring</string> | ||||
|     <string name="rich_text_editor_format_bold">Terapkan format tebal</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Rekam nama klien, versi, dan URL untuk lebih mudah mengenal sesi di pengelola sesi.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Aktifkan perekaman info klien</string> | ||||
|     <string name="labs_enable_session_manager_summary">Miliki keterlihatan dan kendali yang lebih baik pada semua sesi Anda.</string> | ||||
|     <string name="labs_enable_session_manager_title">Aktifkan pengelola sesi baru</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Sistem operasi</string> | ||||
|     <string name="device_manager_session_details_device_model">Model</string> | ||||
|     <string name="device_manager_session_details_device_browser">Peramban</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Versi</string> | ||||
|     <string name="device_manager_session_details_application_name">Nama</string> | ||||
|     <string name="device_manager_session_details_application">Aplikasi</string> | ||||
|     <string name="device_manager_push_notifications_description">Terima notifikasi dorongan di sesi ini.</string> | ||||
|     <string name="device_manager_push_notifications_title">Notifikasi dorongan</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Verifikasi sesi Anda saat ini untuk menampilkan status verifikasi sesi ini.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Status verifikasi tidak diketahui</string> | ||||
|     <string name="push_gateway_item_enabled">Diaktifkan:</string> | ||||
|     <string name="push_gateway_item_device_id">ID Sesi:</string> | ||||
|     <string name="error_check_network">Ada sesuatu yang salah. Mohon periksa koneksi jaringan Anda dan coba lagi.</string> | ||||
|     <string name="grant_permission">Berikan Izin</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} membutuhkan izin untuk menampilkan notifikasi. | ||||
| \nMohon berikan izin itu.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} membutuhkan izin untuk menampilkan notifikasi. Notifikasi dapat menampilkan pesan Anda, undangan Anda, dll. | ||||
| \n | ||||
| \nMohon perbolehkan akses di munculan berikutnya untuk dapat melihat notifikasi.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Coba editor teks kaya (mode teks biasa akan datang)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Aktifkan editor teks kaya</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Pastikan Anda tahu asal kode ini. Dengan menautkan perangkat, Anda akan memberikan seseorang akses penuh ke akun Anda.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Konfirmasi</string> | ||||
|     <string name="qr_code_login_try_again">Coba lagi</string> | ||||
|     <string name="qr_code_login_status_no_match">Tidak cocok\?</string> | ||||
|     <string name="qr_code_login_signing_in">Memasukkan Anda</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Menghubungkan ke perangkat</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">Pindai kode QR</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Ingin masuk di perangkat ponsel\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">Tampilkan kode QR di perangkat ini</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Pilih \'Pindai dengan kode QR\'</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Mulai dari layar masuk</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Pilih \'Masuk dengan kode QR\'</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Mulai dari layar masuk</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Pilih \'Tampilkan kode QR di perangkat ini\'</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Pergi ke Pengaturan → Keamanan & Privasi → Tampilkan Semua Sesi</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Buka ${app_name} di perangkat Anda yang lain</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">Permintaan ditolak di perangkat lain.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Penautan tidak selesai dalam waktu yang dibutuhkan.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Penautan dengan perangkat ini tidak didukung.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Koneksi tidak berhasil</string> | ||||
|     <string name="qr_code_login_header_connected_description">Periksa perangkat yang masuk, kode di bawah seharusnya ditampilkan. Konfirmasi bahwa kode di bawah cocok dengan perangkat itu:</string> | ||||
|     <string name="qr_code_login_header_connected_title">Koneksi aman dibuat</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Pindai kode QR di bawah dengan perangkat Anda yang telah keluar dari akun.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Gunakan perangkat yang sudah masuk untuk memindai kode QR di bawah:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Masuk dengan kode QR</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Gunakan kamera pada perangkat ini untuk memindai kode QR yang ditampilkan pada perangkat Anda yang lain:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">Pindai kode QR</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Anda dapat menggunakan perangkat ini untuk masuk ke perangkat ponsel atau web dengan sebuah kode QR. Ada dua cara untuk melalukan ini:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Masuk dengan Kode QR</string> | ||||
|     <string name="login_scan_qr_code">Pindai kode QR</string> | ||||
| </resources> | ||||
| @ -889,10 +889,10 @@ | ||||
|     <string name="settings_push_rules">Regole di push</string> | ||||
|     <string name="settings_push_rules_no_rules">Nessuna regola di push definita</string> | ||||
|     <string name="settings_push_gateway_no_pushers">Nessun gateway di push registrato</string> | ||||
|     <string name="push_gateway_item_app_id">id_app:</string> | ||||
|     <string name="push_gateway_item_push_key">chiave_push:</string> | ||||
|     <string name="push_gateway_item_app_display_name">nome_visualizzato_app:</string> | ||||
|     <string name="push_gateway_item_device_name">nome_sessione:</string> | ||||
|     <string name="push_gateway_item_app_id">ID app:</string> | ||||
|     <string name="push_gateway_item_push_key">Chiave push:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Nome mostrato app:</string> | ||||
|     <string name="push_gateway_item_device_name">Nome mostrato sessione:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_format">Formato:</string> | ||||
|     <string name="preference_voice_and_video">Audio e Video</string> | ||||
| @ -2733,4 +2733,67 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ Ci sono dispositivi non verificati in questa stanza, non potranno decifrare i messaggi che invii.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Non inviare mai messaggi cifrati a sessioni non verificate in questa stanza.</string> | ||||
|     <string name="action_got_it">Capito</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_underline">Applica formato sottolineato</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Applica formato sbarrato</string> | ||||
|     <string name="rich_text_editor_format_italic">Applica formato corsivo</string> | ||||
|     <string name="rich_text_editor_format_bold">Applica formato grassetto</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Registra il nome, la versione e l\'url del client per riconoscere le sessioni più facilmente nel gestore di sessioni.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Attiva registrazione info client</string> | ||||
|     <string name="labs_enable_session_manager_summary">Maggiore visibilità e controllo su tutte le tue sessioni.</string> | ||||
|     <string name="labs_enable_session_manager_title">Attiva il nuovo gestore di sessioni</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Sistema operativo</string> | ||||
|     <string name="device_manager_session_details_device_model">Modello</string> | ||||
|     <string name="device_manager_session_details_device_browser">Browser</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Versione</string> | ||||
|     <string name="device_manager_session_details_application_name">Nome</string> | ||||
|     <string name="device_manager_session_details_application">Applicazione</string> | ||||
|     <string name="device_manager_push_notifications_description">Ricevi notifiche push in questa sessione.</string> | ||||
|     <string name="device_manager_push_notifications_title">Notifiche push</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Verifica l\'attuale sessione per rivelare lo stato di verifica di questa sessione.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Stato di verifica sconosciuto</string> | ||||
|     <string name="push_gateway_item_enabled">Attivato:</string> | ||||
|     <string name="push_gateway_item_device_id">ID sessione:</string> | ||||
|     <string name="error_check_network">Qualcosa è andato storto. Controlla la tua connessione di rete e riprova.</string> | ||||
|     <string name="grant_permission">Concedi l\'autorizzazione</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} chiede l\'autorizzazione per mostrare notifiche. | ||||
| \nConcedi l\'autorizzazione.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} chiede l\'autorizzazione per mostrare notifiche. Le notifiche possono mostrare i messaggi, gli inviti, ecc. | ||||
| \n | ||||
| \nConsenti l\'accesso nelle prossime schermate per potere vedere la notifica.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Prova l\'editor in rich text (il testo semplice è in arrivo)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Attiva editor in rich text</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Assicurati di conoscere l\'origine di questo codice. Collegando i dispositivi, fornirai a qualcuno l\'accesso totale al tuo account.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Conferma</string> | ||||
|     <string name="qr_code_login_try_again">Riprova</string> | ||||
|     <string name="qr_code_login_status_no_match">Non corrisponde\?</string> | ||||
|     <string name="qr_code_login_signing_in">Accesso in corso</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Connessione al dispositivo</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">Scansiona codice QR</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Effettuare l\'accesso in un dispositivo mobile\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">Mostra codice QR in questo dispositivo</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Seleziona \'Scansiona codice QR\'</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Inizia nella schermata di accesso</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Seleziona ‘Accedi con codice QR’</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Inizia nella schermata di accesso</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Seleziona ‘Mostra codice QR in questo dispositivo’</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Vai in Impostazioni -> Sicurezza e privacy -> Mostra tutte le sessioni</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Apri ${app_name} sull\'altro dispositivo</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">La richiesta è stata negata sull\'altro dispositivo.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Il collegamento non è stato completato nel tempo previsto.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Il collegamento con questo dispositivo non è supportato.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Connessione non riuscita</string> | ||||
|     <string name="qr_code_login_header_connected_description">Controlla il dispositivo che ha l\'accesso, dovresti vedere il codice sotto. Conferma che il codice corrisponda con quel dispositivo:</string> | ||||
|     <string name="qr_code_login_header_connected_title">Connessione sicura stabilita</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Scansiona il codice QR sottostante con il dispositivo che è disconnesso.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Usa il dispositivo che ha l\'accesso per scansionare il codice QR sotto:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Accedi con codice QR</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Usa la fotocamera di questo dispositivo per scansionare il codice QR mostrato nell\'altro dispositivo:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">Scansiona codice QR</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Puoi usare questo dispositivo per accedere in un dispositivo mobile o web con un codice QR. Ci sono due modi:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Accedi con codice QR</string> | ||||
|     <string name="login_scan_qr_code">Scansiona codice QR</string> | ||||
| </resources> | ||||
| @ -861,9 +861,7 @@ | ||||
|     <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">חשבונך טרם נוצר. | ||||
| \n | ||||
| \nלהפסיק את תהליך ההרשמה\?</string> | ||||
|     <string name="login_signup_cancel_confirmation_content">חשבונך טרם נוצר. להפסיק את תהליך ההרשמה\?</string> | ||||
|     <string name="login_signup_cancel_confirmation_title">אזהרה</string> | ||||
|     <string name="login_signup_error_user_in_use">שם המשתמש הזה תפוס</string> | ||||
|     <string name="login_signup_submit">הבא</string> | ||||
| @ -2304,7 +2302,7 @@ | ||||
|     <string name="ftue_auth_use_case_option_three">קהילות</string> | ||||
|     <string name="ftue_auth_use_case_option_two">צוותים</string> | ||||
|     <string name="ftue_auth_use_case_option_one">חברים ומשפחה</string> | ||||
|     <string name="ftue_auth_use_case_subtitle">נעזור לך להתחבר.</string> | ||||
|     <string name="ftue_auth_use_case_subtitle">נעזור לך להתחבר</string> | ||||
|     <string name="ftue_auth_use_case_title">עם מי תדברו הכי הרבה\?</string> | ||||
|     <string name="ftue_auth_carousel_encrypted_body">מוצפן מקצה לקצה ואין צורך במספר טלפון. ללא פרסומות או עיבוד נתונים.</string> | ||||
|     <string name="ftue_auth_carousel_control_body">בחר היכן השיחות שלך נשמרות, נותן לך שליטה ועצמאות. מחובר דרך Matrix.</string> | ||||
| @ -2508,4 +2506,4 @@ | ||||
| \nזה יהיה מעבר חד פעמי שכן שרשורים הם כעת חלק ממפרט Matrix.</string> | ||||
|     <string name="screen_sharing_notification_title">שיתוף מסך של ${app_name}</string> | ||||
|     <string name="screen_sharing_notification_description">המסך משותף כרגע</string> | ||||
| </resources> | ||||
| </resources> | ||||
| @ -987,7 +987,7 @@ | ||||
|     <string name="settings_troubleshoot_test_push_loop_title">プッシュ通知のテスト</string> | ||||
|     <string name="settings_troubleshoot_test_token_registration_failed">FCMトークンのホームサーバーへの登録に失敗しました: | ||||
| \n%1$s</string> | ||||
|     <string name="settings_troubleshoot_test_token_registration_success">FCMトークンのホームサーバーへの登録が成功しました。</string> | ||||
|     <string name="settings_troubleshoot_test_token_registration_success">FCMトークンがホームサーバーに登録されました。</string> | ||||
|     <string name="settings_troubleshoot_test_token_registration_title">トークンの登録</string> | ||||
|     <string name="settings_troubleshoot_test_fcm_failed_account_missing_quick_fix">アカウントを追加</string> | ||||
|     <string name="settings_troubleshoot_test_fcm_failed_account_missing">[%1$s] | ||||
| @ -1233,7 +1233,7 @@ | ||||
|     <string name="login_terms_title">続行するには利用規約を承認してください</string> | ||||
|     <string name="error_terms_not_accepted">ホームサーバーの利用規約を承認したら、再試行してください。</string> | ||||
|     <string name="login_signup_submit">次に</string> | ||||
|     <string name="login_msisdn_confirm_submit">次に</string> | ||||
|     <string name="login_msisdn_confirm_submit">次へ</string> | ||||
|     <string name="login_set_msisdn_submit">次に</string> | ||||
|     <string name="login_set_email_submit">次に</string> | ||||
|     <string name="login_reset_password_submit">次に</string> | ||||
| @ -1282,9 +1282,9 @@ | ||||
|     <string name="send_suggestion_failed">提案の送信に失敗しました(%s)</string> | ||||
|     <string name="send_suggestion_sent">ありがとうございます、提案は正常に送信されました</string> | ||||
|     <string name="settings_troubleshoot_test_token_registration_quick_fix">トークンの登録</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">アプリケーションの表示名:</string> | ||||
|     <string name="push_gateway_item_app_id">App ID:</string> | ||||
|     <string name="push_gateway_item_push_key">Push Key:</string> | ||||
|     <string name="settings_push_gateway_no_pushers">登録されたプッシュゲートウェイはありません</string> | ||||
|     <string name="settings_push_rules_no_rules">プッシュ通知に関するルールが定義されていません</string> | ||||
|     <string name="settings_push_rules">プッシュ通知に関するルール</string> | ||||
| @ -1383,8 +1383,8 @@ | ||||
|     <string name="settings_discovery_consent_action_revoke">同意を撤回</string> | ||||
|     <string name="settings_discovery_consent_notice_on">あなたの連絡先から他のユーザーを発見するために、メールアドレスや電話番号をこのIDサーバーに送信することに同意しています。</string> | ||||
|     <string name="settings_discovery_consent_title">メールと電話番号を送信</string> | ||||
|     <string name="settings_discovery_confirm_mail_not_clicked">%sに確認メールを送りました。まず、メールを確認してリンクをクリックしてください</string> | ||||
|     <string name="settings_discovery_confirm_mail">%sに確認のためのメールを送りました。メールにて確認リンクをクリックしてください</string> | ||||
|     <string name="settings_discovery_confirm_mail_not_clicked">%sにメールを送りました。メールを確認してリンクをクリックしてください</string> | ||||
|     <string name="settings_discovery_confirm_mail">%sにメールを送りました。メールの確認リンクをクリックしてください</string> | ||||
|     <string name="settings_discovery_msisdn_title">発見可能な電話番号</string> | ||||
|     <string name="settings_discovery_disconnect_identity_server_info">IDサーバーとの接続を解除すると、他のユーザーによって発見されなくなり、また、メールアドレスや電話で他のユーザーを招待することができなくなります。</string> | ||||
|     <string name="settings_discovery_no_msisdn">電話番号を追加すると、発見可能に設定する電話番号を選択できるようになります。</string> | ||||
| @ -1412,7 +1412,7 @@ | ||||
|     <string name="send_suggestion">提案する</string> | ||||
|     <string name="push_gateway_item_format">フォーマット:</string> | ||||
|     <string name="push_gateway_item_url">URL:</string> | ||||
|     <string name="push_gateway_item_device_name">セッション名:</string> | ||||
|     <string name="push_gateway_item_device_name">セッションの表示名:</string> | ||||
|     <string name="verify_not_me_self_verification">以下のうちいずれかが流出、あるいはハッキングされた恐れがあります。 | ||||
| \n | ||||
| \n- あなたのパスワード | ||||
| @ -1696,7 +1696,7 @@ | ||||
|     <string name="room_message_placeholder">メッセージを送る…</string> | ||||
|     <string name="error_file_too_big_simple">このファイルは大きすぎてアップロードできません。</string> | ||||
|     <string name="identity_server_consent_dialog_content_question">この情報の送信に同意しますか?</string> | ||||
|     <string name="identity_server_consent_dialog_content_3">連絡先を発見するには、連絡先のデータ(電話番号や電子メール)をあなたのIDサーバーに送信する必要があります。プライバシーの保護のため、データは送信前にハッシュ化されます。</string> | ||||
|     <string name="identity_server_consent_dialog_content_3">連絡先を発見するには、連絡先のデータ(メールアドレスと電話番号)をあなたのIDサーバーに送信する必要があります。プライバシーの保護のため、データは送信前にハッシュ化されます。</string> | ||||
|     <string name="identity_server_consent_dialog_title_2">メールアドレスと電話番号を%sに送信</string> | ||||
|     <string name="settings_discovery_no_policy_provided">このIDサーバーは運営方針を提供していません</string> | ||||
|     <string name="settings_discovery_hide_identity_server_policy_title">IDサーバーの運営方針を隠す</string> | ||||
| @ -2359,4 +2359,104 @@ | ||||
|     <string name="beta_title_bottom_sheet_action">ベータ版</string> | ||||
|     <string name="beta">ベータ版</string> | ||||
|     <string name="action_try_it_out">試す</string> | ||||
| </resources> | ||||
|     <string name="settings_presence_user_always_appears_offline">オフラインモード</string> | ||||
|     <string name="invites_empty_title">新着はありません。</string> | ||||
|     <string name="initial_sync_request_reason_unignored_users">- ユーザーの無視が解除されました</string> | ||||
|     <string name="onboarding_new_app_layout_button_try">試してみる</string> | ||||
|     <string name="onboarding_new_app_layout_feedback_message">右上をタップするとフィードバックを送信するオプションが表示されます。</string> | ||||
|     <string name="onboarding_new_app_layout_feedback_title">フィードバックを送信</string> | ||||
|     <string name="onboarding_new_app_layout_spaces_message">右下からスペースにより早く簡単にアクセスできます。</string> | ||||
|     <string name="onboarding_new_app_layout_spaces_title">スペースにアクセス</string> | ||||
|     <string name="onboarding_new_app_layout_welcome_message">${app_name}をシンプルにするために、タブはオプションになりました。右上のメニューから管理できます。</string> | ||||
|     <string name="onboarding_new_app_layout_welcome_title">新しいレイアウトにようこそ!</string> | ||||
|     <string name="settings_autoplay_animated_images_title">アニメーション画像を自動再生</string> | ||||
|     <string name="settings_troubleshoot_test_endpoint_registration_failed">エンドポイントのホームサーバーへの登録に失敗しました: | ||||
| \n%1$s</string> | ||||
|     <string name="settings_troubleshoot_test_endpoint_registration_success">エンドポイントがホームサーバーに登録されました。</string> | ||||
|     <string name="settings_troubleshoot_test_endpoint_registration_title">エンドポイントの登録</string> | ||||
|     <string name="grant_permission">権限を与える</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name}は通知の表示に権限が必要です。 | ||||
| \n権限を与えてください。</string> | ||||
|     <plurals name="search_space_multiple_parents"> | ||||
|         <item quantity="other">%1$sと他%2$d名</item> | ||||
|     </plurals> | ||||
|     <string name="search_space_two_parents">%1$sと%2$s</string> | ||||
|     <string name="threads_labs_enable_notice_message">ホームサーバーがサポートしていないため、スレッド機能は不安定かもしれません。スレッドのメッセージは安定して表示されないおそれがあります。%sスレッド機能を有効にしてよろしいですか?</string> | ||||
|     <string name="threads_labs_enable_notice_title">スレッド(ベータ版)</string> | ||||
|     <string name="threads_beta_enable_notice_message">スレッドを用いると、会話のテーマを保ったり、会話を追跡したりするのが容易になります。%sスレッドを有効にするとアプリケーションが再起動します。再起動には時間がかかる可能性があります。</string> | ||||
|     <string name="threads_beta_enable_notice_title">スレッド(ベータ版)</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name}は通知を表示するために許可を必要としています。通知にはメッセージや招待などが表示されます。 | ||||
| \n | ||||
| \n通知を表示するには、次のポップアップでアクセスを許可してください。</string> | ||||
|     <string name="auth_reset_password_error_unverified">メールアドレスが認証されていません。メールボックスを確認してください</string> | ||||
|     <string name="call_stop_screen_sharing">画面共有を停止</string> | ||||
|     <string name="call_start_screen_sharing">画面を共有</string> | ||||
|     <string name="invites_title">招待</string> | ||||
|     <string name="device_manager_push_notifications_title">プッシュ通知</string> | ||||
|     <string name="device_manager_session_rename_edit_hint">セッション名</string> | ||||
|     <string name="device_manager_session_rename">セッションを改名</string> | ||||
|     <string name="device_manager_session_details_device_ip_address">IPアドレス</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">オペレーティングシステム</string> | ||||
|     <string name="device_manager_session_details_device_model">形式</string> | ||||
|     <string name="device_manager_session_details_device_browser">ブラウザー</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">バージョン</string> | ||||
|     <string name="device_manager_session_details_application_name">名称</string> | ||||
|     <string name="device_manager_session_details_application">アプリケーション</string> | ||||
|     <string name="ftue_personalize_skip_this_step">このステップをスキップ</string> | ||||
|     <string name="ftue_personalize_complete_title">問題ありません!</string> | ||||
|     <string name="ftue_personalize_lets_go">進みましょう</string> | ||||
|     <string name="ftue_auth_login_username_entry">ユーザー名 / メールアドレス / 電話番号</string> | ||||
|     <string name="ftue_auth_captcha_title">あなたは人間ですか?</string> | ||||
|     <string name="ftue_auth_password_reset_email_confirmation_subtitle">%sに送信された手順に従ってください</string> | ||||
|     <string name="ftue_auth_password_reset_confirmation">パスワードを再設定</string> | ||||
|     <string name="ftue_auth_forgot_password">パスワードを忘れた場合</string> | ||||
|     <string name="ftue_auth_email_resend_email">電子メールを再送信</string> | ||||
|     <string name="ftue_auth_email_verification_footer">電子メールが届いていませんか?</string> | ||||
|     <string name="ftue_auth_email_verification_subtitle">%sに送信された手順に従ってください</string> | ||||
|     <string name="ftue_auth_email_verification_title">メールアドレスを認証</string> | ||||
|     <string name="ftue_auth_phone_confirmation_resend_code">コードを再送信</string> | ||||
|     <string name="ftue_auth_phone_confirmation_subtitle">コードが%sに送信されました</string> | ||||
|     <string name="ftue_auth_phone_confirmation_title">電話番号を確認してください</string> | ||||
|     <string name="ftue_auth_sign_out_all_devices">全ての端末からサインアウト</string> | ||||
|     <string name="ftue_auth_reset_password">パスワードを再設定</string> | ||||
|     <string name="ftue_auth_new_password_subtitle">パスワードは8文字以上に設定してください。</string> | ||||
|     <string name="ftue_auth_new_password_title">パスワードを選択</string> | ||||
|     <string name="ftue_auth_new_password_entry_title">新しいパスワード</string> | ||||
|     <string name="ftue_auth_reset_password_breaker_title">電子メールを確認してください。</string> | ||||
|     <string name="ftue_auth_reset_password_email_subtitle">%sは認証リンクを送信します</string> | ||||
|     <string name="ftue_auth_phone_confirmation_entry_title">確認コード</string> | ||||
|     <string name="ftue_auth_phone_entry_title">電話番号</string> | ||||
|     <string name="ftue_auth_phone_subtitle">%sはアカウントの認証が必要です</string> | ||||
|     <string name="ftue_auth_phone_title">電話番号を入力してください</string> | ||||
|     <string name="ftue_auth_email_entry_title">メールアドレス</string> | ||||
|     <string name="ftue_auth_email_subtitle">%sはアカウントの認証が必要です</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">リッチテキストエディターを有効にする</string> | ||||
|     <string name="labs_enable_deferred_dm_summary">最初のメッセージを送信する際にダイレクトメッセージを作成</string> | ||||
|     <string name="labs_enable_deferred_dm_title">遅延DMを有効にする</string> | ||||
|     <string name="space_list_empty_title">スペースがありません。</string> | ||||
|     <string name="labs_enable_new_app_layout_title">新しいレイアウトを有効にする</string> | ||||
|     <string name="home_layout_preferences_sort_activity">アクティビティー順</string> | ||||
|     <string name="home_layout_preferences_sort_name">アルファベット順</string> | ||||
|     <string name="home_layout_preferences_sort_by">並び替え</string> | ||||
|     <string name="home_layout_preferences_filters">フィルターを表示</string> | ||||
|     <string name="home_layout_preferences">レイアウトの設定</string> | ||||
|     <string name="action_got_it">了解</string> | ||||
|     <string name="action_next">次へ</string> | ||||
|     <string name="action_learn_more">詳しく知る</string> | ||||
|     <string name="time_unit_second_short">秒</string> | ||||
|     <string name="time_unit_minute_short">分</string> | ||||
|     <string name="time_unit_hour_short">時</string> | ||||
|     <string name="initial_sync_request_content">${app_name}は以下の理由で、キャッシュを消去して最新の状態にする必要があります。 | ||||
| \n%s | ||||
| \n | ||||
| \nアプリケーションが再起動します。再起動には時間がかかる可能性があります。</string> | ||||
|     <string name="initial_sync_request_title">初期同期のリクエスト</string> | ||||
|     <string name="a11y_collapse_space_children">%sの子スペースを折りたたむ</string> | ||||
|     <string name="a11y_expand_space_children">%sの子スペースを展開</string> | ||||
|     <string name="explore_rooms">ルームを探索</string> | ||||
|     <string name="change_space">スペースを変更</string> | ||||
|     <string name="create_room">ルームを作成</string> | ||||
|     <string name="start_chat">チャットを開始</string> | ||||
|     <string name="all_chats">全ての会話</string> | ||||
| </resources> | ||||
| @ -1007,10 +1007,10 @@ | ||||
|     <string name="settings_push_rules">Regras de Push</string> | ||||
|     <string name="settings_push_rules_no_rules">Nenhuma regra de push definida</string> | ||||
|     <string name="settings_push_gateway_no_pushers">Nenhum gateway de push registrado</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_id">ID do App:</string> | ||||
|     <string name="push_gateway_item_push_key">Chave Push:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Nome de Exibição do App:</string> | ||||
|     <string name="push_gateway_item_device_name">Nome de Exibição da Sessão:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_format">Formato:</string> | ||||
|     <string name="preference_voice_and_video">Voz & Vídeo</string> | ||||
| @ -2742,4 +2742,67 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ Existem dispositivos não-verificados nesta sala, eles não vão ser capazes de decriptar mensagens que você enviar.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Nunca enviar mensagens encriptadas a sessões não-verificadas nesta sala.</string> | ||||
|     <string name="action_got_it">Entendido</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_strikethrough">Aplicar formato tachar</string> | ||||
|     <string name="rich_text_editor_format_underline">Aplicar formato sublinhar</string> | ||||
|     <string name="rich_text_editor_format_italic">Aplicar formato itálico</string> | ||||
|     <string name="rich_text_editor_format_bold">Aplicar formato negrito</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Gravar o nome de cliente, versão, e url para reconhecer sessões mais facilmente em gerenciador de sessão.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Habilitar gravação de info de cliente</string> | ||||
|     <string name="labs_enable_session_manager_summary">Tenha visibilidade e controle maiores sobre todas suas sessões.</string> | ||||
|     <string name="labs_enable_session_manager_title">Habilitar novo gerenciador de sessão</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Sistema operativo</string> | ||||
|     <string name="device_manager_session_details_device_model">Modelo</string> | ||||
|     <string name="device_manager_session_details_device_browser">Browser</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Versão</string> | ||||
|     <string name="device_manager_session_details_application_name">Nome</string> | ||||
|     <string name="device_manager_session_details_application">Aplicativo</string> | ||||
|     <string name="device_manager_push_notifications_description">Receber notificações push nesta sessão.</string> | ||||
|     <string name="device_manager_push_notifications_title">Notificações push</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Verifique sua sessão atual para revelar o status de verificação desta sessão.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Status de verificação desconhecido</string> | ||||
|     <string name="push_gateway_item_enabled">Habilitado:</string> | ||||
|     <string name="push_gateway_item_device_id">ID da Sessão:</string> | ||||
|     <string name="error_check_network">Algo deu errado. Por favor cheque sua conexão de rede e tente de novo.</string> | ||||
|     <string name="grant_permission">Conceder Permissão</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} precisa de permissão para mostrar notificações. | ||||
| \nPor favor conceda a permissão.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} precisa de permissão para exibir notificações. Notificações podem exibir suas mensagens, seus convites, etc. | ||||
| \n | ||||
| \nPor favor permita acesso nos próximos pop-ups para ser capaz de visualizar notificação.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Experimente o editor de texto rico (modo de texto puro vindo em breve)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Habilitar editor de texto rico</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Por favor assegure que você sabe a origem deste código. Ao linkar dispositivos, você vai prover alguém com acesso completo a sua conta.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Confirmar</string> | ||||
|     <string name="qr_code_login_try_again">Tentar de novo</string> | ||||
|     <string name="qr_code_login_status_no_match">Nenhuma correspondência\?</string> | ||||
|     <string name="qr_code_login_signing_in">Fazendo-lhe signin</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Conectando a dispositivo</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">Scannar QR code</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Fazendo signin com um dispositivo móvel\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">Mostrar QR code neste dispositivo</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Selecione \'Scannar QR code\'</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Comece na tela de signin</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Selecione \'Fazer signin com QR code\'</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Comece na tela de signin</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Selecione \'Mostrar QR code neste dispositivo\'</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Vá para Configurações -> Segurança & Privacidade -> Mostrar Todas as Sessões</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Obra ${app_name} em seu outro dispositivo</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">A requisição foi negada no outro dispositivo.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">A linkagem não foi completada no tempo requerido.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Linkagem com este dispositivo não é suportado.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Conexão malsucedida</string> | ||||
|     <string name="qr_code_login_header_connected_description">Cheque seu dispositivo feito signin, o código abaixo deveria ser exibido. Confirme que o código abaixo corresponde com esse dispositivo:</string> | ||||
|     <string name="qr_code_login_header_connected_title">Conexão segura estabelecida</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Scanne o QR code abaixo com seu dispositivo que está feito signout.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Use seu dispositivo feito signin para scannar o QR code abaixo:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Fazer signin com QR code</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Use a câmera neste dispositivo para scannar o QR code mostrado em seu outro dispositivo:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">Scannar QR code</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Você pode usar este dispositivo para fazer signin com um dispositivo móvel ou web com um QR code. Existem duas maneiras de fazer isto:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Fazer signin com QR Code</string> | ||||
|     <string name="login_scan_qr_code">Scannar QR code</string> | ||||
| </resources> | ||||
| @ -398,8 +398,8 @@ | ||||
|     <string name="settings_pin_missed_notifications">Прикрепить комнаты с отключенными уведомлениями</string> | ||||
|     <string name="settings_pin_unread_messages">Прикрепить комнаты с непрочитанными сообщениями</string> | ||||
|     <string name="devices_details_id_title">ID</string> | ||||
|     <string name="devices_details_name_title">Публичное имя</string> | ||||
|     <string name="devices_details_device_name">Обновить публичное имя</string> | ||||
|     <string name="devices_details_name_title">Публичное название</string> | ||||
|     <string name="devices_details_device_name">Обновить публичное название</string> | ||||
|     <string name="devices_details_last_seen_title">Недавно</string> | ||||
|     <string name="devices_details_last_seen_format">%1$s @ %2$s</string> | ||||
|     <string name="devices_delete_dialog_title">Аутентификация</string> | ||||
| @ -431,7 +431,7 @@ | ||||
|     <string name="room_settings_set_main_address">Установить как основной адрес</string> | ||||
|     <string name="room_settings_unset_main_address">Сбросить основной адрес</string> | ||||
|     <string name="encryption_information_decryption_error">Ошибка дешифровки</string> | ||||
|     <string name="encryption_information_device_name">Публичное имя</string> | ||||
|     <string name="encryption_information_device_name">Публичное название</string> | ||||
|     <string name="device_manager_session_details_session_id">ID сессии</string> | ||||
|     <string name="encryption_information_device_key">Ключ сессии</string> | ||||
|     <string name="encryption_export_e2e_room_keys">Экспорт E2E ключей комнаты</string> | ||||
| @ -727,21 +727,21 @@ | ||||
|     <string name="notification_silent">Беззвучный</string> | ||||
|     <string name="passphrase_empty_error_message">Пожалуйста, введите мнемоническую фразу</string> | ||||
|     <string name="passphrase_passphrase_too_weak">Парольная фраза слишком простая</string> | ||||
|     <string name="keys_backup_passphrase_not_empty_error_message">Пожалуйста, удалите мнемоническую фразу, если хотите, чтобы ${app_name} сгенерировал ключ восстановления.</string> | ||||
|     <string name="keys_backup_passphrase_not_empty_error_message">Пожалуйста, удалите мнемоническую фразу, если хотите, чтобы ${app_name} сгенерировал бумажный ключ.</string> | ||||
|     <string name="keys_backup_setup_step1_title">Никогда не теряйте зашифрованных сообщений</string> | ||||
|     <string name="keys_backup_setup_step1_description">Сообщения в зашифрованных комнатах защищены сквозным шифрованием. Ключи для прочтения этих сообщений есть только у вас и получателя(ей). | ||||
| \n | ||||
| \nНадёжно сохраните резервную копию ключей, чтобы не потерять их.</string> | ||||
|     <string name="keys_backup_setup_step2_button_title">Установите парольную фразу</string> | ||||
|     <string name="keys_backup_setup_step3_copy_button_title">Сохраните ключ восстановления</string> | ||||
|     <string name="keys_backup_setup_step3_copy_button_title">Сохранить бумажный ключ</string> | ||||
|     <string name="keys_backup_setup_step3_button_title">Готово</string> | ||||
|     <string name="keys_backup_setup_step3_save_button_title">Сохранить как файл</string> | ||||
|     <string name="keys_backup_setup_step3_please_make_copy">Пожалуйста, сделайте копию</string> | ||||
|     <string name="keys_backup_setup_step3_share_intent_chooser_title">Поделиться ключом восстановления с…</string> | ||||
|     <string name="recovery_key">Ключ для восстановления</string> | ||||
|     <string name="keys_backup_setup_step3_share_intent_chooser_title">Поделиться бумажным ключом с…</string> | ||||
|     <string name="recovery_key">Бумажный ключ</string> | ||||
|     <string name="unexpected_error">Непредвиденная ошибка</string> | ||||
|     <string name="keys_backup_setup_skip_title">Уверены?</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_deleting_backup">Удаление резервной копии…</string> | ||||
|     <string name="keys_backup_settings_untrusted_backup">Чтобы использовать резервную копию ключа в этой сессии, восстановите его с помощью своей парольной фразы или ключа восстановления.</string> | ||||
| @ -755,17 +755,17 @@ | ||||
|     <string name="keys_backup_settings_status_ok">Резервное копирование ключей успешно настроено для этой сессии.</string> | ||||
|     <string name="keys_backup_settings_delete_backup_button">Удалить резервную копию</string> | ||||
|     <string name="keys_backup_settings_restore_backup_button">Восстановить из резервной копии</string> | ||||
|     <string name="keys_backup_recovery_code_empty_error_message">Пожалуйста, введите ключ восстановления</string> | ||||
|     <string name="keys_backup_recovery_code_empty_error_message">Пожалуйста, введите бумажный ключ</string> | ||||
|     <string name="keys_backup_unlock_button">Разблокировать историю</string> | ||||
|     <string name="keys_backup_restoring_waiting_message">Восстановление резервной копии:</string> | ||||
|     <string name="keys_backup_restore_key_enter_hint">Введите ключ восстановления</string> | ||||
|     <string name="keys_backup_restore_with_recovery_key">Используйте ключ восстановления для разблокировки истории зашифрованных сообщений</string> | ||||
|     <string name="keys_backup_restore_with_passphrase_helper_with_link">Если вы не знаете вашу парольную фразу для восстановления, вы можете %s.</string> | ||||
|     <string name="keys_backup_restore_use_recovery_key">используйте ключ восстановления</string> | ||||
|     <string name="keys_backup_restore_key_enter_hint">Введите бумажный ключ</string> | ||||
|     <string name="keys_backup_restore_with_recovery_key">Используйте бумажный ключ для разблокировки зашифрованных сообщений</string> | ||||
|     <string name="keys_backup_restore_with_passphrase_helper_with_link">Если забыли свою мнемоническую фразу, вы можете %s.</string> | ||||
|     <string name="keys_backup_restore_use_recovery_key">используйте бумажный ключ</string> | ||||
|     <string name="keys_backup_setup_skip_msg">Вы можете потерять доступ к сообщениям, если выйдете из системы или потеряете это устройство.</string> | ||||
|     <string name="keys_backup_restore_is_getting_backup_version">Получение версии резервной копии…</string> | ||||
|     <string name="keys_backup_restore_with_passphrase">Используйте парольную фразу для разблокировки истории зашифрованных сообщений</string> | ||||
|     <string name="keys_backup_restore_with_key_helper">Потеряли ключ восстановления? В настройках вы можете создать новый.</string> | ||||
|     <string name="keys_backup_restore_with_passphrase">Используйте мнемоническую фразу для разблокировки зашифрованных сообщений</string> | ||||
|     <string name="keys_backup_restore_with_key_helper">Потеряли бумажный ключ\? В настройках вы можете создать новый.</string> | ||||
|     <string name="keys_backup_restore_success_title">Резервная копия восстановлена %s !</string> | ||||
|     <string name="keys_backup_settings_invalid_signature_from_unverified_device">Резервная копия имеет недействительную подпись из неподтвержденной сессии %s</string> | ||||
|     <string name="keys_backup_get_version_error">Не удалось получить последнюю версию ключей восстановления (%s).</string> | ||||
| @ -780,9 +780,9 @@ | ||||
|         <item quantity="few">Восстановлены резервные копии с %d ключами.</item> | ||||
|         <item quantity="many">Восстановлены резервные копии с %d ключами.</item> | ||||
|     </plurals> | ||||
|     <string name="keys_backup_recovery_code_error_decrypt">Невозможно расшифровать резервную копию с помощью этого ключа восстановления: убедитесь, что вы ввели правильный ключ.</string> | ||||
|     <string name="keys_backup_passphrase_error_decrypt">Невозможно расшифровать резервную копию с помощью этого пароля: убедитесь, что вы ввели правильный пароль.</string> | ||||
|     <string name="keys_backup_setup_step3_generating_key_status">Генерация ключей восстановления с использованием парольной фразы может занять несколько секунд.</string> | ||||
|     <string name="keys_backup_recovery_code_error_decrypt">Невозможно расшифровать резервную копию с помощью этого бумажного ключа: пожалуйста, убедитесь, что вы ввели правильный бумажный ключ.</string> | ||||
|     <string name="keys_backup_passphrase_error_decrypt">Невозможно расшифровать резервную копию с помощью этой мнемонической фразы: пожалуйста, убедитесь, что вы ввели правильную мнемоническую фразу.</string> | ||||
|     <string name="keys_backup_setup_step3_generating_key_status">Генерация бумажного ключа с использованием мнемонической фразы может занять несколько секунд.</string> | ||||
|     <string name="settings_troubleshoot_test_fcm_failed_account_missing">[%1$s] | ||||
| \nЭта ошибка вне контроля ${app_name}. На телефоне нет учетной записи Google. Пожалуйста, добавьте аккаунт Google.</string> | ||||
|     <string name="settings_troubleshoot_test_fcm_failed_service_not_available">[%1$s] | ||||
| @ -816,7 +816,7 @@ | ||||
|     <string name="keys_backup_banner_recover_line1">Никогда не теряйте зашифрованные сообщения</string> | ||||
|     <string name="keys_backup_setup_step3_share_recovery_file">Поделиться</string> | ||||
|     <string name="keys_backup_setup_step3_button_title_no_passphrase">Я сделал(а) копию</string> | ||||
|     <string name="keys_backup_setup_step3_text_line2_no_passphrase">Храните ключ восстановления в надежном месте, например, в диспетчере паролей (или в сейфе)</string> | ||||
|     <string name="keys_backup_setup_step3_text_line2_no_passphrase">Храните бумажный ключ в очень надёжном месте, например, в менеджере паролей (или в сейфе)</string> | ||||
|     <string name="keys_backup_setup_step2_text_title">Защитите резервную копию мнемонической фразой.</string> | ||||
|     <string name="encryption_message_recovery">Восстановление зашифрованных сообщений</string> | ||||
|     <string name="keys_backup_setup">Начать использовать резервное копирование ключей</string> | ||||
| @ -825,16 +825,16 @@ | ||||
|     <string name="keys_backup_banner_update_line1">Новые ключи зашифрованных сообщений</string> | ||||
|     <string name="keys_backup_setup_step3_text_line1">Ваши ключи копируются.</string> | ||||
|     <string name="keys_backup_setup_step2_skip_button_title">(Дополнительно) Настройка с ключом восстановления</string> | ||||
|     <string name="keys_backup_setup_step1_recovery_key_alternative">Или защитите резервную копию с помощью ключа восстановления, сохранив его в безопасном месте.</string> | ||||
|     <string name="keys_backup_setup_step1_recovery_key_alternative">Или защитите резервную копию бумажным ключом, сохранив его в надёжном месте.</string> | ||||
|     <string name="sign_out_bottom_sheet_warning_backup_not_active">Безопасная резервная копия ключей должна быть активирована на всех ваших сессиях, чтобы не потерять доступ к зашифрованным сообщениям.</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_step3_text_line2">Ключ восстановления — это страховка, вы можете использовать его для восстановления доступа к вашим зашифрованным сообщениям, если забудете вашу парольную фразу.  | ||||
| \nХраните ключ восстановления в надёжном месте, например, в диспетчере паролей (или в сейфе)</string> | ||||
|     <string name="keys_backup_restoring_importing_keys_waiting_message">Импортирование ключей…</string> | ||||
|     <string name="keys_backup_restoring_downloading_backup_waiting_message">Скачивание ключей…</string> | ||||
|     <string name="keys_backup_restoring_computing_key_waiting_message">Вычисление ключа восстановления…</string> | ||||
|     <string name="keys_backup_restoring_computing_key_waiting_message">Вычисление бумажного ключа…</string> | ||||
|     <string name="action_ignore">Игнорировать</string> | ||||
|     <string name="action_mark_room_read">Отметить как прочитанное</string> | ||||
|     <string name="auth_login_sso">Войти с помощью единого входа</string> | ||||
| @ -929,10 +929,10 @@ | ||||
|     <string name="settings_preferences">Предпочтения</string> | ||||
|     <string name="settings_security_and_privacy">Безопасность</string> | ||||
|     <string name="settings_push_rules">Правила push-уведомлений</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_app_id">ID приложения:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Отображаемое название приложения:</string> | ||||
|     <string name="push_gateway_item_device_name">Отображаемое название сессии:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_format">Формат:</string> | ||||
|     <string name="preference_voice_and_video">Голос и видео</string> | ||||
| @ -1219,10 +1219,10 @@ | ||||
|     <string name="room_profile_section_more">Ещё</string> | ||||
|     <string name="a11y_qr_code_for_verification">QR-код</string> | ||||
|     <string name="no_connectivity_to_the_server_indicator">Соединение с сервером потеряно</string> | ||||
|     <string name="verification_cannot_access_other_session">Используйте пароль восстановления или ключ</string> | ||||
|     <string name="verification_cannot_access_other_session">Используйте мнемоническую фразу или бумажный ключ</string> | ||||
|     <string name="e2e_use_keybackup">Разблокировать историю зашифрованных сообщений</string> | ||||
|     <string name="verify_cancelled_notice">Проверка была отменена. Вы можете начать проверку снова.</string> | ||||
|     <string name="recovery_passphrase">Мнемоническая фраза для восстановления</string> | ||||
|     <string name="recovery_passphrase">Мнемоническая фраза</string> | ||||
|     <string name="enter_account_password">Введите %s, чтобы продолжить.</string> | ||||
|     <string name="bootstrap_dont_reuse_pwd">Не переиспользуйте пароль учётной записи.</string> | ||||
|     <string name="bootstrap_loading_text">Это может занять несколько секунд, пожалуйста, наберитесь терпения.</string> | ||||
| @ -1314,7 +1314,7 @@ | ||||
|     <string name="settings_secure_backup_reset">Сброс безопасного резервного копирования</string> | ||||
|     <string name="settings_secure_backup_enter_to_setup">Настроить на этом устройстве</string> | ||||
|     <string name="settings_secure_backup_section_info">Защитите себя от потери доступа к зашифрованным сообщениям и данным, создав резервные копии ключей шифрования на вашем сервере.</string> | ||||
|     <string name="reset_secure_backup_title">Создайте новый ключ безопасности или задайте новую секретную фразу для существующей резервной копии.</string> | ||||
|     <string name="reset_secure_backup_title">Создайте новый бумажный ключ или задайте новую мнемоническую фразу для существующей резервной копии.</string> | ||||
|     <string name="reset_secure_backup_warning">Это заменит ваш текущий ключ или фразу.</string> | ||||
|     <string name="disabled_integration_dialog_title">Интеграции отключены</string> | ||||
|     <string name="disabled_integration_dialog_content">Включите «Управление интеграциями» в настройках, чтобы сделать это.</string> | ||||
| @ -1326,7 +1326,7 @@ | ||||
|     <string name="encryption_exported_successfully">Ключи успешно экспортированы</string> | ||||
|     <string name="active_widget_view_action">ОБЗОР</string> | ||||
|     <string name="active_widgets_title">Активные виджеты</string> | ||||
|     <string name="recovery_key_export_saved">Ключ восстановления был сохранён.</string> | ||||
|     <string name="recovery_key_export_saved">Бумажный ключ сохранён.</string> | ||||
|     <string name="secure_backup_banner_setup_line1">Безопасное резервное копирование</string> | ||||
|     <string name="secure_backup_banner_setup_line2">Защита от потери доступа к зашифрованным сообщениям и данным</string> | ||||
|     <string name="secure_backup_setup">Настроить безопасное резервное копирование</string> | ||||
| @ -1553,12 +1553,12 @@ | ||||
|     <string name="auth_invalid_login_deactivated_account">Эта учётная запись была деактивирована.</string> | ||||
|     <string name="bootstrap_enter_recovery">Введите %s, чтобы продолжить</string> | ||||
|     <string name="use_file">Использовать файл</string> | ||||
|     <string name="bootstrap_invalid_recovery_key">Это недействительный ключ восстановления</string> | ||||
|     <string name="recovery_key_empty_error_message">Пожалуйста, введите ключ восстановления</string> | ||||
|     <string name="bootstrap_invalid_recovery_key">Этот бумажный ключ недействителен</string> | ||||
|     <string name="recovery_key_empty_error_message">Пожалуйста, введите бумажный ключ</string> | ||||
|     <string name="bootstrap_progress_checking_backup">Проверка ключа резервного копирования</string> | ||||
|     <string name="bootstrap_progress_checking_backup_with_info">Проверка ключа резервного копирования (%s)</string> | ||||
|     <string name="bootstrap_progress_compute_curve_key">Получение кривой ключа</string> | ||||
|     <string name="bootstrap_progress_generating_ssss_recovery">Генерация ключа SSSS из ключа восстановления</string> | ||||
|     <string name="bootstrap_progress_generating_ssss_recovery">Генерация ключа SSSS из бумажного ключа</string> | ||||
|     <string name="bootstrap_progress_storing_in_sss">Сохранение резервной копии ключа в SSSS</string> | ||||
|     <string name="bootstrap_migration_use_recovery_key">используйте ваш ключ восстановления ключа резервной копии</string> | ||||
|     <string name="bootstrap_migration_backup_recovery_key">Ключ восстановления ключа резервной копии</string> | ||||
| @ -1571,7 +1571,7 @@ | ||||
| \n${app_name} для Android</string> | ||||
|     <string name="or_other_mx_capable_client">или другой клиент Matrix поддерживающий перекрестную подпись</string> | ||||
|     <string name="command_description_discard_session">Принудительно отбрасывает текущую групповую сессию для отправки сообщений в зашифрованную комнату</string> | ||||
|     <string name="enter_secret_storage_passphrase_or_key">Чтобы продолжить, используйте ваш %1$s или используйте ваш %2$s.</string> | ||||
|     <string name="enter_secret_storage_passphrase_or_key">Чтобы продолжить, используйте %1$s или %2$s.</string> | ||||
|     <string name="use_recovery_key">Используйте ключ восстановления</string> | ||||
|     <string name="enter_secret_storage_input_key">Выберите ключ восстановления или введите его вручную, введя или вставив из буфера обмена</string> | ||||
|     <string name="failed_to_access_secure_storage">Не удалось получить доступ к защищенному хранилищу данных</string> | ||||
| @ -1624,13 +1624,13 @@ | ||||
|     <string name="bottom_sheet_setup_secure_backup_submit">Настроить</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_key_title">Используйте ключ безопасности</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_key_subtitle">Создайте ключ безопасности для хранения в надежном месте, например в менеджере паролей или сейфе.</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_phrase_title">Использовать секретную фразу</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_phrase_title">Использовать мнемоническую фразу</string> | ||||
|     <string name="bottom_sheet_setup_secure_backup_security_phrase_subtitle">Введите секретную фразу, известную только вам, и создайте ключ для резервного копирования.</string> | ||||
|     <string name="bottom_sheet_save_your_recovery_key_title">Сохраните свой ключ безопасности</string> | ||||
|     <string name="bottom_sheet_save_your_recovery_key_content">Храните ключ безопасности в надежном месте, например в менеджере паролей или сейфе.</string> | ||||
|     <string name="bottom_sheet_save_your_recovery_key_content">Храните бумажный ключ в надёжном месте, например, в менеджере паролей или в сейфе.</string> | ||||
|     <string name="set_a_security_phrase_title">Задайте секретную фразу</string> | ||||
|     <string name="set_a_security_phrase_notice">Введите секретную фразу, известную только вам, для защиты данных на вашем сервере.</string> | ||||
|     <string name="set_a_security_phrase_hint">Секретная фраза</string> | ||||
|     <string name="set_a_security_phrase_hint">Мнемоническая фраза</string> | ||||
|     <string name="set_a_security_phrase_again_notice">Для подтверждения введите вашу секретную фразу ещё раз.</string> | ||||
|     <string name="room_settings_name_hint">Название комнаты</string> | ||||
|     <string name="room_settings_topic_hint">Тема</string> | ||||
| @ -1646,7 +1646,7 @@ | ||||
|     <string name="disclaimer_content">Мы рады сообщить, что сменили имя! Ваше приложение обновлено, и вы вошли в свою учетную запись.</string> | ||||
|     <string name="disclaimer_negative_button">ПОНЯТНО</string> | ||||
|     <string name="disclaimer_positive_button">УЗНАТЬ БОЛЬШЕ</string> | ||||
|     <string name="save_recovery_key_chooser_hint">Сохранить ключ восстановления в</string> | ||||
|     <string name="save_recovery_key_chooser_hint">Сохранить бумажный ключ в</string> | ||||
|     <string name="loading_contact_book">Получаем ваши контакты…</string> | ||||
|     <string name="empty_contact_book">Ваша контактная книга пуста</string> | ||||
|     <string name="contacts_book_title">Книга контактов</string> | ||||
| @ -1701,12 +1701,12 @@ | ||||
|     <string name="auth_msisdn_already_defined">Этот номер телефона уже используется.</string> | ||||
|     <string name="settings_phone_number_empty">В ваш аккаунт не добавлен номер телефона</string> | ||||
|     <string name="settings_emails">Адрес электронной почты</string> | ||||
|     <string name="settings_emails_empty">В ваш аккаунт не добавлен адрес электронной почты</string> | ||||
|     <string name="settings_emails_empty">В вашу учётную запись не добавлен адрес электронной почты</string> | ||||
|     <string name="settings_phone_numbers">Телефонные номера</string> | ||||
|     <string name="settings_remove_three_pid_confirmation_content">Удалить %s\?</string> | ||||
|     <string name="error_threepid_auth_failed">Убедитесь, что вы перешли по ссылке в электронном письме, которое мы вам отправили.</string> | ||||
|     <string name="settings_emails_and_phone_numbers_title">Электронная почта и номера телефонов</string> | ||||
|     <string name="settings_emails_and_phone_numbers_summary">Управляйте электронной почтой и номерами телефонов, привязанными к вашей учетной записи Matrix</string> | ||||
|     <string name="settings_emails_and_phone_numbers_summary">Управляйте адресами электронной почты и номерами телефонов, привязанными к вашей учётной записи Matrix</string> | ||||
|     <string name="settings_text_message_sent_hint">Код</string> | ||||
|     <string name="login_msisdn_notice">Используйте международный формат (номер телефона должен начинаться с \'+\')</string> | ||||
|     <string name="confirm_your_identity_quad_s">Подтвердите свою личность, проверив этот логин, предоставив ему доступ к зашифрованным сообщениям.</string> | ||||
| @ -2633,7 +2633,7 @@ | ||||
|     <string name="ftue_auth_sign_in_choose_server_header">Где хранятся ваши переписки</string> | ||||
|     <string name="ftue_auth_create_account_choose_server_header">Где будут храниться ваши переписки</string> | ||||
|     <string name="ftue_auth_create_account_password_entry_footer">Должно быть 8 или более символов</string> | ||||
|     <string name="crosssigning_cannot_verify_this_session">Не удалось подтвердить это устройство</string> | ||||
|     <string name="crosssigning_cannot_verify_this_session">Не удалось подтвердить эту сессию</string> | ||||
|     <string name="permalink_unsupported_groups">Невозможно открыть эту ссылку: сообщества были заменены пространствами</string> | ||||
|     <string name="ftue_auth_login_username_entry">Имя пользователя / Почта / Телефон</string> | ||||
|     <string name="ftue_auth_password_reset_email_confirmation_subtitle">Следуйте инструкциям, отправленным на %s</string> | ||||
| @ -2758,11 +2758,38 @@ | ||||
|     <string name="action_got_it">Понятно</string> | ||||
|     <string name="room_settings_global_block_unverified_info_text">🔒 В настройках безопасности вы включили шифрование только для заверенных сессий во всех комнатах.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Не отправлять зашифрованные сообщения незаверенным сессиям в этой комнате.</string> | ||||
|     <string name="device_manager_learn_more_sessions_inactive">Неактивные сессии — это сессии, которыми вы не пользовались определенное время, но они продолжают получать ключи шифрования. | ||||
|     <string name="device_manager_learn_more_sessions_inactive">Неактивные сессии — это сессии, которыми вы не пользовались определённое время, но они продолжают получать ключи шифрования. | ||||
| \n | ||||
| \nУдаление неактивных сессий повышает безопасность и производительность, а также облегчает выявление подозрительных новых сессий.</string> | ||||
|     <string name="device_manager_learn_more_session_rename_title">Переименование сессий</string> | ||||
|     <string name="device_manager_learn_more_session_rename">Другие пользователи в личных сообщениях и комнатах, к которым вы присоединились, могут просматривать весь список ваших сессий. | ||||
| \n | ||||
| \nЭто даёт им уверенность в том, что они действительно общаются с вами, но это также означает, что они могут видеть название сессии, которое вы ввели здесь.</string> | ||||
| </resources> | ||||
|     <string name="labs_enable_rich_text_editor_title">Визуальный редактор текста</string> | ||||
|     <string name="push_gateway_item_device_id">ID сессии:</string> | ||||
|     <string name="device_manager_push_notifications_title">Уведомления</string> | ||||
|     <string name="device_manager_push_notifications_description">Получать push-уведомления в этой сессии.</string> | ||||
|     <string name="device_manager_session_details_application_url">URL-адрес</string> | ||||
|     <string name="device_manager_session_details_application">Приложение</string> | ||||
|     <string name="device_manager_session_details_application_name">Название</string> | ||||
|     <string name="device_manager_session_details_application_version">Версия</string> | ||||
|     <string name="device_manager_session_details_device_browser">Веб-браузер</string> | ||||
|     <string name="device_manager_session_details_device_model">Модель</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Операционная система</string> | ||||
|     <string name="labs_enable_session_manager_title">Новый менеджер сессий</string> | ||||
|     <plurals name="device_manager_other_sessions_recommendation_description_inactive"> | ||||
|         <item quantity="one">Рассмотрите возможность выхода из старых сессий (%1$d день или дольше), которые вы более не используете.</item> | ||||
|         <item quantity="few">Рассмотрите возможность выхода из старых сессий (%1$d дня или дольше), которые вы более не используете.</item> | ||||
|         <item quantity="many">Рассмотрите возможность выхода из старых сессий (%1$d дней или дольше), которые вы более не используете.</item> | ||||
|         <item quantity="other">Рассмотрите возможность выхода из старых сессий (%1$d дней или дольше), которые вы более не используете.</item> | ||||
|     </plurals> | ||||
|     <string name="poll_undisclosed_not_ended">Результаты будут видны после завершения опроса</string> | ||||
|     <string name="onboarding_new_app_layout_spaces_message">Доступ к пространствам (внизу справа) быстрее и проще, чем когда-либо прежде.</string> | ||||
|     <string name="onboarding_new_app_layout_spaces_title">Доступ к пространствам</string> | ||||
|     <plurals name="device_manager_inactive_sessions_description"> | ||||
|         <item quantity="one">Рассмотрите возможность выхода из старых сессий (%1$d день или дольше), которые вы более не используете.</item> | ||||
|         <item quantity="few">Рассмотрите возможность выхода из старых сессий (%1$d дня или дольше), которые вы более не используете.</item> | ||||
|         <item quantity="many">Рассмотрите возможность выхода из старых сессий (%1$d дней или дольше), которые вы более не используете.</item> | ||||
|         <item quantity="other">Рассмотрите возможность выхода из старых сессий (%1$d дней или дольше), которые вы более не используете.</item> | ||||
|     </plurals> | ||||
| </resources> | ||||
| @ -1700,7 +1700,7 @@ | ||||
|     <string name="login_set_msisdn_notice2">Prosím, použite medzinárodný formát.</string> | ||||
|     <string name="login_set_msisdn_notice">Nastavte si telefónne číslo, aby ste voliteľne umožnili ľuďom, ktorých poznáte, aby vás objavili.</string> | ||||
|     <string name="does_not_look_like_valid_email">Toto nevyzerá ako platná e-mailová adresa</string> | ||||
|     <string name="login_set_email_notice">Nastavte si e-mail na obnovenie konta. Neskôr môžete voliteľne povoliť známym, aby vás objavili podľa vášho e-mailu.</string> | ||||
|     <string name="login_set_email_notice">Nastavte si e-mail na obnovenie konta. Neskôr môžete voliteľne povoliť svojim známym, aby vás objavili podľa tohto e-mailu.</string> | ||||
|     <string name="login_set_email_title">Nastaviť e-mailovú adresu</string> | ||||
|     <string name="login_reset_password_success_submit">Späť na prihlásenie</string> | ||||
|     <string name="login_reset_password_success_notice">Vaše heslo bolo obnovené.</string> | ||||
| @ -2796,4 +2796,67 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ V tejto miestnosti sa nachádzajú neoverené zariadenia, ktoré nebudú schopné dešifrovať odoslané správy.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Nikdy neposielať šifrované správy do neoverených relácií v tejto miestnosti.</string> | ||||
|     <string name="action_got_it">Rozumiem</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_underline">Použiť formát podčiarknutia</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Použiť formát prečiarknutia</string> | ||||
|     <string name="rich_text_editor_format_italic">Použiť formát kurzívou</string> | ||||
|     <string name="rich_text_editor_format_bold">Použiť tučný formát</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Zaznamenať názov klienta, verziu a url, aby bolo možné ľahšie rozpoznať relácie v správcovi relácií.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Povoliť zaznamenanie informácií o klientovi</string> | ||||
|     <string name="labs_enable_session_manager_summary">Majte lepší prehľad a kontrolu nad všetkými reláciami.</string> | ||||
|     <string name="labs_enable_session_manager_title">Použiť nového správcu relácií</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Operačný systém</string> | ||||
|     <string name="device_manager_session_details_device_model">Model</string> | ||||
|     <string name="device_manager_session_details_device_browser">Prehliadač</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Verzia</string> | ||||
|     <string name="device_manager_session_details_application_name">Názov</string> | ||||
|     <string name="device_manager_session_details_application">Aplikácia</string> | ||||
|     <string name="device_manager_push_notifications_description">Prijímať push oznámenia v tejto relácii.</string> | ||||
|     <string name="device_manager_push_notifications_title">Push oznámenia</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Overením aktuálnej relácie zistíte stav overenia tejto relácie.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Neznámy stav overenia</string> | ||||
|     <string name="push_gateway_item_enabled">Zapnuté:</string> | ||||
|     <string name="push_gateway_item_device_id">ID relácie:</string> | ||||
|     <string name="error_check_network">Niečo sa pokazilo. Skontrolujte, prosím, svoje sieťové pripojenie a skúste to znova.</string> | ||||
|     <string name="grant_permission">Udeliť oprávnenie</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} potrebuje povolenie na zobrazovanie oznámení. | ||||
| \nProsím, udeľte toto povolenie.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} potrebuje povolenie na zobrazovanie oznámení. Oznámenia môžu zobrazovať vaše správy, pozvánky atď. | ||||
| \n | ||||
| \nPovoľte prístup na ďalších vyskakovacích oknách, aby ste mohli zobrazovať oznámenia.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Vyskúšajte rozšírený textový editor (čistý textový režim sa objaví čoskoro)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Povoliť rozšírený textový editor</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Uistite sa prosím, že poznáte pôvod tohto kódu. Prepojením zariadení poskytnete niekomu plný prístup k svojmu účtu.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Potvrdiť</string> | ||||
|     <string name="qr_code_login_try_again">Skúste to znova</string> | ||||
|     <string name="qr_code_login_status_no_match">Nezhoduje sa\?</string> | ||||
|     <string name="qr_code_login_signing_in">Prebieha prihlasovanie</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Pripájanie k zariadeniu</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">Skenovať QR kód</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Prihlasovanie do mobilného zariadenia\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">Zobraziť QR kód na tomto zariadení</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Vyberte možnosť \"Skenovať QR kód\"</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Začnite na prihlasovacej obrazovke</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Vyberte možnosť \"Prihlásiť sa pomocou QR kódu\"</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Začnite na prihlasovacej obrazovke</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Vyberte možnosť \"Zobraziť QR kód na tomto zariadení\"</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Prejdite do Nastavenia -> Zabezpečenie a súkromie -> Zobraziť všetky relácie</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Otvorte ${app_name} na vašom druhom zariadení</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">Žiadosť bola na druhom zariadení zamietnutá.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Prepojenie nebolo dokončené v požadovanom čase.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Prepojenie s týmto zariadením nie je podporované.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Neúspešné pripojenie</string> | ||||
|     <string name="qr_code_login_header_connected_description">Skontrolujte svoje prihlásené zariadenie, mal by sa zobraziť nasledujúci kód. Skontrolujte, či sa nižšie uvedený kód zhoduje s daným zariadením:</string> | ||||
|     <string name="qr_code_login_header_connected_title">Zabezpečené pripojenie bolo vytvorené</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Naskenujte nižšie uvedený QR kód pomocou zariadenia, ktoré je odhlásené.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Pomocou prihláseného zariadenia naskenujte nižšie uvedený QR kód:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Prihlásiť sa pomocou QR kódu</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Pomocou fotoaparátu na tomto zariadení naskenujte QR kód zobrazený na vašom druhom zariadení:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">Skenovať QR kód</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">Pomocou tohto zariadenia sa môžete prihlásiť do mobilného alebo webového zariadenia pomocou QR kódu. Môžete to urobiť dvoma spôsobmi:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Prihlásiť sa pomocou QR kódu</string> | ||||
|     <string name="login_scan_qr_code">Skenovať QR kód</string> | ||||
| </resources> | ||||
| @ -615,7 +615,7 @@ | ||||
|     <string name="login_reset_password_mail_confirmation_submit">Jag har verifierat min e-postadress</string> | ||||
|     <string name="login_reset_password_success_notice_2">Du har blivit utloggad ur alla sessioner och kommer inte längre motta pushnotiser. För att återaktivera pushnotiser, logga in igen på varje enhet.</string> | ||||
|     <string name="login_set_email_title">Sätt e-postadress</string> | ||||
|     <string name="login_set_email_notice">Sätt en e-postadress för att kunna återförva ditt konto. Senare kan du valfritt låta personer du känner upptäcka dig med din e-postadress.</string> | ||||
|     <string name="login_set_email_notice">Sätt en e-postadress för att kunna återförvärva ditt konto. Senare kan du valfritt låta personer du känner upptäcka dig med den här e-postadressen.</string> | ||||
|     <string name="login_set_email_mandatory_hint">E-post</string> | ||||
|     <string name="login_set_email_optional_hint">E-post (valfritt)</string> | ||||
|     <string name="login_set_msisdn_notice">Sätt ett telefonnummer som valfritt kan användas för att vara upptäckbar av folk som känner dig.</string> | ||||
| @ -1312,10 +1312,10 @@ | ||||
|     <string name="keys_backup_unable_to_get_keys_backup_data">Ett fel inträffade vid hämtning av nyckelsäkerhetskopia</string> | ||||
|     <string name="navigate_to_room_when_already_in_the_room">Du tittar redan på det här rummet!</string> | ||||
|     <string name="settings_push_gateway_no_pushers">Inga registrerade pushgateways</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_id">App-ID:</string> | ||||
|     <string name="push_gateway_item_push_key">Pushnyckel:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Appens visningsnamn:</string> | ||||
|     <string name="push_gateway_item_device_name">Sessionens visningsnamn:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_format">Format:</string> | ||||
|     <string name="settings_troubleshoot_test_token_registration_quick_fix">Registrera token</string> | ||||
| @ -2651,4 +2651,71 @@ | ||||
|     <string name="room_list_filter_favourites">Favoriter</string> | ||||
|     <string name="room_list_filter_unreads">Olästa</string> | ||||
|     <string name="room_list_filter_all">Alla</string> | ||||
| </resources> | ||||
|     <string name="device_manager_push_notifications_title">Pushnotiser</string> | ||||
|     <string name="device_manager_session_details_description">Applikations-, enhets- och aktivitetsinformation.</string> | ||||
|     <string name="device_manager_session_details_title">Sessionsdetaljer</string> | ||||
|     <string name="device_manager_session_overview_signout">Logga ut ur den här sessionen</string> | ||||
|     <string name="device_manager_other_sessions_clear_filter">Rensa filter</string> | ||||
|     <string name="device_manager_other_sessions_no_inactive_sessions_found">Inga inaktiva sessioner hittade.</string> | ||||
|     <string name="device_manager_other_sessions_no_unverified_sessions_found">Inga overifierade sessioner hittade.</string> | ||||
|     <string name="device_manager_other_sessions_no_verified_sessions_found">Inga verifierade sessioner hittade.</string> | ||||
|     <plurals name="device_manager_other_sessions_recommendation_description_inactive"> | ||||
|         <item quantity="one">Överväg att logga ut ur gamla sessioner (%1$d dag eller längre) du inte använder längre.</item> | ||||
|         <item quantity="other">Överväg att logga ut ur gamla sessioner (%1$d dagar eller längre) du inte använder längre.</item> | ||||
|     </plurals> | ||||
|     <string name="device_manager_other_sessions_recommendation_title_inactive">Inaktiv</string> | ||||
|     <string name="device_manager_other_sessions_recommendation_description_unverified">Verifiera dina sessioner för förbättrad säker meddelandehantering eller logga ut ur de du inte känner igen eller använder längre.</string> | ||||
|     <string name="device_manager_other_sessions_recommendation_title_unverified">Overifierad</string> | ||||
|     <string name="device_manager_other_sessions_recommendation_description_verified">För bäst säkerhet, logga ut från sessioner du inte känner igen eller använder längre.</string> | ||||
|     <string name="device_manager_other_sessions_recommendation_title_verified">Verifierad</string> | ||||
|     <string name="a11y_device_manager_filter">Filter</string> | ||||
|     <plurals name="device_manager_inactive_sessions_description"> | ||||
|         <item quantity="one">Överväg att logga ut ur gamla sessioner (%1$d dag eller längre) som du inte använder längre.</item> | ||||
|         <item quantity="other">Överväg att logga ut ur gamla sessioner (%1$d dagar eller längre) som du inte använder längre.</item> | ||||
|     </plurals> | ||||
|     <plurals name="device_manager_filter_option_inactive_description"> | ||||
|         <item quantity="one">Inaktiv %1$d dag eller längre</item> | ||||
|         <item quantity="other">Inaktiv %1$d dagar eller längre</item> | ||||
|     </plurals> | ||||
|     <string name="device_manager_filter_option_inactive">Inaktiv</string> | ||||
|     <string name="device_manager_filter_option_unverified_description">Inte redo för säkra meddelanden</string> | ||||
|     <string name="device_manager_filter_option_unverified">Overifierad</string> | ||||
|     <string name="device_manager_filter_option_verified_description">Redo för säkra meddelanden</string> | ||||
|     <string name="device_manager_filter_option_verified">Verifierade</string> | ||||
|     <string name="device_manager_filter_option_all_sessions">Alla sessioner</string> | ||||
|     <string name="device_manager_filter_bottom_sheet_title">Filter</string> | ||||
|     <string name="device_manager_session_last_activity">Senast aktiv %1$s</string> | ||||
|     <string name="device_manager_device_title">Enhet</string> | ||||
|     <string name="device_manager_session_title">Session</string> | ||||
|     <string name="device_manager_current_session_title">Nuvarande session</string> | ||||
|     <string name="device_manager_inactive_sessions_title">Inaktiva sessioner</string> | ||||
|     <string name="device_manager_unverified_sessions_description">Verifiera eller logga ut ur overifierade sessioner.</string> | ||||
|     <string name="device_manager_unverified_sessions_title">Overifierade sessioner</string> | ||||
|     <string name="device_manager_header_section_security_recommendations_description">Förbättra din kontosäkerhet genom att följa dessa rekommendationer.</string> | ||||
|     <string name="device_manager_header_section_security_recommendations_title">Säkerhetsrekommendationer</string> | ||||
|     <plurals name="device_manager_other_sessions_description_inactive"> | ||||
|         <item quantity="one">Inaktiv %1$d+ dag (%2$s)</item> | ||||
|         <item quantity="other">Inaktiv %1$d+ dagar (%2$s)</item> | ||||
|     </plurals> | ||||
|     <string name="device_manager_other_sessions_description_unverified_current_session">Overifierad · Din nuvarande session</string> | ||||
|     <string name="device_manager_other_sessions_description_unverified">Overifierad · Senast aktiv %1$s</string> | ||||
|     <string name="device_manager_other_sessions_description_verified">Verifierad · Senast aktiv %1$s</string> | ||||
|     <string name="device_manager_other_sessions_view_all">Visa alla (%1$d)</string> | ||||
|     <string name="device_manager_view_details">Visa detaljer</string> | ||||
|     <string name="device_manager_verify_session">Verifiera session</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Verifiera din nuvarande session för att visa den här sessionens verifieringsstatus.</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unverified">Verifiera eller logga ut från den här sessionen för bäst säkerhet och pålitlighet.</string> | ||||
|     <string name="device_manager_verification_status_detail_current_session_unverified">Verifiera din nuvarande session för förbättrad säker meddelandehantering.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Okänd verifieringsstatus</string> | ||||
|     <string name="push_gateway_item_enabled">Aktiverad:</string> | ||||
|     <string name="push_gateway_item_device_id">Sessions-ID:</string> | ||||
|     <string name="error_check_network">Nåt gick fel. Kolla din nätverksanslutning och pröva igen.</string> | ||||
|     <string name="grant_permission">Ge åtkomst</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} behöver behörighet att visa aviseringar. | ||||
| \nVänligen ge åtkomst.</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} behöver behörighet att visa aviseringar. Aviseringar kan visa dina meddelanden, dina inbjudningar, o.s.v. | ||||
| \n | ||||
| \nVänligen ge åtkomst på nästa pop-uper för att kunna se aviseringar.</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Aktivera rik-text-redigerare</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Testa den nya rik-text-redigeraren</string> | ||||
| </resources> | ||||
| @ -1740,10 +1740,10 @@ | ||||
|     <string name="feedback">Відгук</string> | ||||
|     <string name="push_gateway_item_format">Формат:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_device_name">Показувана назва сеансу:</string> | ||||
|     <string name="push_gateway_item_app_display_name">Показувана назва застосунку:</string> | ||||
|     <string name="push_gateway_item_push_key">Ключ Push:</string> | ||||
|     <string name="push_gateway_item_app_id">ID застосунку:</string> | ||||
|     <string name="settings_sdk_version">Версія Matrix SDK</string> | ||||
|     <string name="create_room_federation_error">Кімнату створено, але деякі запрошення не надіслано з такої причини: | ||||
| \n | ||||
| @ -2850,4 +2850,67 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ У цій кімнаті є неперевірені пристрої, вони не зможуть розшифрувати повідомлення, які ви надсилаєте.</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">Ніколи не надсилати зашифровані повідомлення на неперевірені сеанси в цій кімнаті.</string> | ||||
|     <string name="action_got_it">Зрозуміло</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_underline">Застосувати форматування підкресленим</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">Застосувати форматування перекресленим</string> | ||||
|     <string name="rich_text_editor_format_italic">Застосувати форматування курсивом</string> | ||||
|     <string name="rich_text_editor_format_bold">Застосувати форматування жирним</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Записуйте назву клієнта, версію та URL-адресу, щоб легше розпізнавати сеанси в менеджері сеансів.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Увімкнути запис відомостей про клієнт</string> | ||||
|     <string name="labs_enable_session_manager_summary">Отримайте кращу видимість і контроль над усіма вашими сеансами.</string> | ||||
|     <string name="labs_enable_session_manager_title">Увімкнути новий менеджер сеансів</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">Операційна система</string> | ||||
|     <string name="device_manager_session_details_device_model">Модель</string> | ||||
|     <string name="device_manager_session_details_device_browser">Браузер</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">Версія</string> | ||||
|     <string name="device_manager_session_details_application_name">Назва</string> | ||||
|     <string name="device_manager_session_details_application">Застосунок</string> | ||||
|     <string name="device_manager_push_notifications_description">Отримувати push-сповіщення про цей сеанс.</string> | ||||
|     <string name="device_manager_push_notifications_title">Push-сповіщення</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">Звірте свій поточний сеанс, щоб побачити стан перевірки цього сеансу.</string> | ||||
|     <string name="device_manager_verification_status_unknown">Невідомий стан перевірки</string> | ||||
|     <string name="push_gateway_item_enabled">Увімкнено:</string> | ||||
|     <string name="push_gateway_item_device_id">ID сеансу:</string> | ||||
|     <string name="error_check_network">Щось пішло не так. Будь ласка, перевірте мережеве з\'єднання та спробуйте ще раз.</string> | ||||
|     <string name="grant_permission">Надати дозвіл</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} потребує дозволу на показ сповіщень. | ||||
| \nНадайте дозвіл.</string> | ||||
|     <string name="permissions_rationale_msg_notification">Для показу сповіщень ${app_name} потрібен дозвіл. Сповіщення можуть показувати ваші повідомлення, запрошення тощо. | ||||
| \n | ||||
| \nДозвольте доступ до наступних спливних вікон, щоб мати змогу переглядати сповіщення.</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">Спробуйте розширений текстовий редактор (незабаром з\'явиться режим звичайного тексту)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">Увімкнути розширений текстовий редактор</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">Переконайтеся, що ви знаєте походження цього коду. Пов\'язавши пристрої, ви надасте будь-кому повний доступ до свого облікового запису.</string> | ||||
|     <string name="qr_code_login_confirm_security_code">Підтвердити</string> | ||||
|     <string name="qr_code_login_try_again">Повторити спробу</string> | ||||
|     <string name="qr_code_login_status_no_match">Не збігається\?</string> | ||||
|     <string name="qr_code_login_signing_in">Вхід</string> | ||||
|     <string name="qr_code_login_connecting_to_device">Під\'єднання до пристрою</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">Входите на мобільному пристрої\?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">Показати QR-код на цьому пристрої</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">Виберіть «Сканувати QR-код»</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Виберіть «Увійти за допомогою QR-коду»</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Почніть з екрана входу</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Почніть з екрана входу</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Виберіть «Показати QR-код на цьому пристрої»</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Перейдіть до Налаштування -> Безпека й приватність -> Показати всі сеанси</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Відкрийте ${app_name} на іншому своєму пристрої</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">Запит на іншому пристрої було відхилено.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">Пов\'язування не було завершено у встановлені терміни.</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Пов\'язування з цим пристроєм не підтримується.</string> | ||||
|     <string name="qr_code_login_header_failed_title">Невдале з\'єднання</string> | ||||
|     <string name="qr_code_login_header_connected_description">Перевірте свій пристрій, на якому ви ввійшли. На екрані повинен з\'явитися код, наведений нижче. Переконайтеся, що наведений код збігається з кодом на вашому пристрої:</string> | ||||
|     <string name="qr_code_login_header_connected_title">Безпечне з\'єднання встановлено</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">Зіскануйте QR-код нижче своїм пристроєм, з якого ви вийшли.</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">Скануйте QR-код нижче за допомогою свого пристрою для входу:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">Увійти за допомогою QR-коду</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">Використовуйте камеру цього пристрою, щоб зісканувати QR-код, показаний на іншому пристрої:</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">За допомогою цього пристрою ви можете ввійти на мобільному або вебпристрої за допомогою QR-коду. Зробити це можна двома способами:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">Увійти за допомогою QR-коду</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">Сканувати QR-код</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">Сканувати QR-код</string> | ||||
|     <string name="login_scan_qr_code">Сканувати QR-код</string> | ||||
| </resources> | ||||
| @ -2623,4 +2623,6 @@ | ||||
|     <string name="labs_enable_deferred_dm_summary">仅在首条消息创建私聊消息</string> | ||||
|     <string name="labs_enable_deferred_dm_title">启用延迟的私聊消息</string> | ||||
|     <string name="labs_enable_new_app_layout_summary">简化的Element,带有可选的标签</string> | ||||
| </resources> | ||||
|     <string name="settings_security_incognito_keyboard_title">无痕键盘</string> | ||||
|     <string name="settings_security_incognito_keyboard_summary">要求键盘不要基于你在对话中的输入更新任何个性化数据,如输入历史和字典。请注意,某些键盘可能不会遵守此设置。</string> | ||||
| </resources> | ||||
| @ -873,10 +873,10 @@ | ||||
|     <string name="settings_push_rules">推送規則</string> | ||||
|     <string name="settings_push_rules_no_rules">未定義通送規則</string> | ||||
|     <string name="settings_push_gateway_no_pushers">沒有已註冊的推送閘道</string> | ||||
|     <string name="push_gateway_item_app_id">app_id:</string> | ||||
|     <string name="push_gateway_item_push_key">push_key:</string> | ||||
|     <string name="push_gateway_item_app_display_name">app_display_name:</string> | ||||
|     <string name="push_gateway_item_device_name">session_name:</string> | ||||
|     <string name="push_gateway_item_app_id">App ID:</string> | ||||
|     <string name="push_gateway_item_push_key">推送金鑰:</string> | ||||
|     <string name="push_gateway_item_app_display_name">應用程式顯示名稱:</string> | ||||
|     <string name="push_gateway_item_device_name">工作階段顯示名稱:</string> | ||||
|     <string name="push_gateway_item_url">Url:</string> | ||||
|     <string name="push_gateway_item_format">格式:</string> | ||||
|     <string name="preference_voice_and_video">音訊與視訊</string> | ||||
| @ -1092,7 +1092,7 @@ | ||||
| \n | ||||
| \n停止密碼變更流程?</string> | ||||
|     <string name="login_set_email_title">設定電子郵件地址</string> | ||||
|     <string name="login_set_email_notice">設定電子郵件地址以復原您的帳號。之後您也可以選擇性地讓您認識的人透過您的這個地址找到您。</string> | ||||
|     <string name="login_set_email_notice">設定電子郵件地址以復原您的帳號。之後您也可以選擇性地讓您認識的人透過此地址找到您。</string> | ||||
|     <string name="login_set_email_mandatory_hint">電子郵件</string> | ||||
|     <string name="login_set_email_optional_hint">電子郵件(選擇性)</string> | ||||
|     <string name="login_set_email_submit">下一個</string> | ||||
| @ -2688,4 +2688,67 @@ | ||||
|     <string name="some_devices_will_not_be_able_to_decrypt">⚠ 此聊天室中有未驗證的裝置,它們將無法解密您傳送的訊息。</string> | ||||
|     <string name="encryption_never_send_to_unverified_devices_in_room">切莫向此聊天室中未經驗證的工作階段傳送加密訊息。</string> | ||||
|     <string name="action_got_it">知道了</string> | ||||
| </resources> | ||||
|     <string name="rich_text_editor_format_underline">套用底線格式</string> | ||||
|     <string name="rich_text_editor_format_strikethrough">套用刪除線格式</string> | ||||
|     <string name="rich_text_editor_format_italic">套用義式斜體格式</string> | ||||
|     <string name="rich_text_editor_format_bold">套用粗體格式</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">記錄客戶端名稱、版本與 URL,以便在工作階段管理程式中可以更簡單地辨認工作階段。</string> | ||||
|     <string name="labs_enable_client_info_recording_title">啟用客戶端資訊記錄</string> | ||||
|     <string name="labs_enable_session_manager_summary">對所有工作階段有更大的能見度與控制。</string> | ||||
|     <string name="labs_enable_session_manager_title">啟用新的工作階段管理程式</string> | ||||
|     <string name="device_manager_session_details_device_operating_system">作業系統</string> | ||||
|     <string name="device_manager_session_details_device_model">模型</string> | ||||
|     <string name="device_manager_session_details_device_browser">瀏覽器</string> | ||||
|     <string name="device_manager_session_details_application_url">URL</string> | ||||
|     <string name="device_manager_session_details_application_version">版本</string> | ||||
|     <string name="device_manager_session_details_application_name">名稱</string> | ||||
|     <string name="device_manager_session_details_application">應用程式</string> | ||||
|     <string name="device_manager_push_notifications_description">接收關於此工作階段的推播通知。</string> | ||||
|     <string name="device_manager_push_notifications_title">推播通知</string> | ||||
|     <string name="device_manager_verification_status_detail_other_session_unknown">驗證您目前的工作階段以顯示此工作階段的驗證狀態。</string> | ||||
|     <string name="device_manager_verification_status_unknown">未知的驗證狀態</string> | ||||
|     <string name="push_gateway_item_enabled">已啟用:</string> | ||||
|     <string name="push_gateway_item_device_id">工作階段 ID:</string> | ||||
|     <string name="error_check_network">發生了一些問題。請檢查您的網路連線並再試一次。</string> | ||||
|     <string name="grant_permission">授予權限</string> | ||||
|     <string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} 需要權限以顯示通知。 | ||||
| \n請授予權限。</string> | ||||
|     <string name="permissions_rationale_msg_notification">${app_name} 需要權限才能顯示通知。通知可以顯示您的訊息、您的邀請等等。 | ||||
| \n | ||||
| \n請在下一個彈出式視窗允許存取以檢視通知。</string> | ||||
|     <string name="labs_enable_rich_text_editor_summary">試用格式化文字編輯器(純文字模式即將推出)</string> | ||||
|     <string name="labs_enable_rich_text_editor_title">啟用格式化文字編輯器</string> | ||||
|     <string name="qr_code_login_confirm_security_code_description">請確保您知道此驗證碼的來源。透過連結裝置,您將為某人提供對您帳號的完整存取權限。</string> | ||||
|     <string name="qr_code_login_confirm_security_code">確認</string> | ||||
|     <string name="qr_code_login_try_again">再試一次</string> | ||||
|     <string name="qr_code_login_status_no_match">不相符?</string> | ||||
|     <string name="qr_code_login_signing_in">登入</string> | ||||
|     <string name="qr_code_login_connecting_to_device">連線至裝置</string> | ||||
|     <string name="qr_code_login_scan_qr_code_button">掃描 QR code</string> | ||||
|     <string name="qr_code_login_signing_in_a_mobile_device">正在使用行動裝置登入?</string> | ||||
|     <string name="qr_code_login_show_qr_code_button">在此裝置顯示 QR code</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_2">選取「掃描 QR code」</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">從登入畫面開始</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">選取「使用 QR code 登入」</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">從登入畫面開始</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">選取「在此裝置上顯示 QR code」</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">到「設定」→「安全與隱私」→「顯示所有工作階段」</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">在您的其他裝置上開啟 ${app_name}</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">請求在另一台裝置上被拒絕。</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">連結未在規定時間內完成。</string> | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">不支援與其裝置連結。</string> | ||||
|     <string name="qr_code_login_header_failed_title">連線不成功</string> | ||||
|     <string name="qr_code_login_header_connected_description">請檢查您已登入的裝置,應該會顯示以下驗證碼。請確認以下驗證碼與該裝置相符:</string> | ||||
|     <string name="qr_code_login_header_connected_title">已建立安全連線</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_link_a_device_description">使用您已登出的裝置掃描以下 QR code。</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_new_device_description">使用您已登入的裝置來掃描下方的 QR code:</string> | ||||
|     <string name="qr_code_login_header_show_qr_code_title">使用 QR code 登入</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_description">使用此裝置的相機掃描您其他裝置上顯示的 QR code:</string> | ||||
|     <string name="qr_code_login_header_scan_qr_code_title">掃描 QR code</string> | ||||
|     <string name="three">3</string> | ||||
|     <string name="two">2</string> | ||||
|     <string name="one">1</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_description">您可以使用此裝置透過 QR code 登入移動裝置或網路裝置。有兩種方法可以作到:</string> | ||||
|     <string name="device_manager_sessions_sign_in_with_qr_code_title">使用 QR code 登入</string> | ||||
|     <string name="login_scan_qr_code">掃描 QR code</string> | ||||
| </resources> | ||||
| @ -3078,6 +3078,14 @@ | ||||
|     <string name="audio_message_reply_content">%1$s (%2$s)</string> | ||||
|     <string name="audio_message_file_size">(%1$s)</string> | ||||
| 
 | ||||
|     <string name="voice_broadcast_live">Live</string> | ||||
|     <string name="a11y_resume_voice_broadcast_record">Resume voice broadcast record</string> | ||||
|     <string name="a11y_pause_voice_broadcast_record">Pause voice broadcast record</string> | ||||
|     <string name="a11y_stop_voice_broadcast_record">Stop voice broadcast record</string> | ||||
|     <string name="a11y_play_voice_broadcast">Play or resume voice broadcast</string> | ||||
|     <string name="a11y_pause_voice_broadcast">Pause voice broadcast</string> | ||||
|     <string name="a11y_voice_broadcast_buffering">Buffering</string> | ||||
| 
 | ||||
|     <string name="upgrade_room_for_restricted">Anyone in %s will be able to find and join this room - no need to manually invite everyone. You’ll be able to change this in room settings anytime.</string> | ||||
|     <string name="upgrade_room_for_restricted_no_param">Anyone in a parent space will be able to find and join this room - no need to manually invite everyone. You’ll be able to change this in room settings anytime.</string> | ||||
| 
 | ||||
| @ -3346,6 +3354,8 @@ | ||||
|     <string name="labs_enable_session_manager_summary">Have greater visibility and control over all your sessions.</string> | ||||
|     <string name="labs_enable_client_info_recording_title">Enable client info recording</string> | ||||
|     <string name="labs_enable_client_info_recording_summary">Record the client name, version, and url to recognise sessions more easily in session manager.</string> | ||||
|     <string name="labs_enable_voice_broadcast_title">Enable voice broadcast (under active development)</string> | ||||
|     <string name="labs_enable_voice_broadcast_summary">Be able to record and send voice broadcast in room timeline.</string> | ||||
| 
 | ||||
|     <!-- Note to translators: %s will be replaces with selected space name --> | ||||
|     <string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string> | ||||
| @ -3384,9 +3394,16 @@ | ||||
|     <string name="qr_code_login_header_failed_device_is_not_supported_description">Linking with this device is not supported.</string> | ||||
|     <string name="qr_code_login_header_failed_timeout_description">The linking wasn’t completed in the required time.</string> | ||||
|     <string name="qr_code_login_header_failed_denied_description">The request was denied on the other device.</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Open ${app_name} on your other device</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Go to Settings -> Security & Privacy -> Show All Sessions</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Select \'Show QR code in this device\'</string> | ||||
|     <string name="qr_code_login_header_failed_other_description">The request failed.</string> | ||||
|     <string name="qr_code_login_header_failed_e2ee_security_issue_description">A security issue was encountered setting up secure messaging. One of the following may be compromised: Your homeserver; Your internet connection(s); Your device(s);</string> | ||||
|     <string name="qr_code_login_header_failed_other_device_already_signed_in_description">The other device is already signed in.</string> | ||||
|     <string name="qr_code_login_header_failed_other_device_not_signed_in_description">The other device must be signed in.</string> | ||||
|     <string name="qr_code_login_header_failed_invalid_qr_code_description">That QR code is invalid.</string> | ||||
|     <string name="qr_code_login_header_failed_user_cancelled_description">The sign in was cancelled on the other device.</string> | ||||
|     <string name="qr_code_login_header_failed_homeserver_is_not_supported_description">The homeserver doesn\'t support sign in with QR code.</string> | ||||
|     <string name="qr_code_login_new_device_instruction_1">Open the app on your other device</string> | ||||
|     <string name="qr_code_login_new_device_instruction_2">Go to Settings -> Security & Privacy</string> | ||||
|     <string name="qr_code_login_new_device_instruction_3">Select \'Show QR code\'</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_1">Start at the sign in screen</string> | ||||
|     <string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Select \'Sign in with QR code\'</string> | ||||
|     <string name="qr_code_login_link_a_device_show_qr_code_instruction_1">Start at the sign in screen</string> | ||||
|  | ||||
| @ -73,6 +73,9 @@ | ||||
|     <dimen name="location_sharing_live_duration_choice_margin_horizontal">12dp</dimen> | ||||
|     <dimen name="location_sharing_live_duration_choice_margin_vertical">22dp</dimen> | ||||
| 
 | ||||
|     <!-- Voice Broadcast --> | ||||
|     <dimen name="voice_broadcast_controller_button_size">48dp</dimen> | ||||
| 
 | ||||
|     <!-- Material 3 --> | ||||
|     <dimen name="collapsing_toolbar_layout_medium_size">112dp</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.4\"" | ||||
|         buildConfigField "String", "SDK_VERSION", "\"1.5.6\"" | ||||
| 
 | ||||
|         buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" | ||||
|         buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" | ||||
|  | ||||
| @ -27,6 +27,7 @@ open class LoggerTag(name: String, parentTag: LoggerTag? = null) { | ||||
|     object SYNC : LoggerTag("SYNC") | ||||
|     object VOIP : LoggerTag("VOIP") | ||||
|     object CRYPTO : LoggerTag("CRYPTO") | ||||
|     object RENDEZVOUS : LoggerTag("RZ") | ||||
| 
 | ||||
|     val value: String = if (parentTag == null) { | ||||
|         name | ||||
|  | ||||
| @ -0,0 +1,229 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous | ||||
| 
 | ||||
| import android.net.Uri | ||||
| import org.matrix.android.sdk.api.auth.AuthenticationService | ||||
| import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig | ||||
| import org.matrix.android.sdk.api.logger.LoggerTag | ||||
| import org.matrix.android.sdk.api.rendezvous.channels.ECDHRendezvousChannel | ||||
| import org.matrix.android.sdk.api.rendezvous.model.ECDHRendezvousCode | ||||
| import org.matrix.android.sdk.api.rendezvous.model.Outcome | ||||
| import org.matrix.android.sdk.api.rendezvous.model.Payload | ||||
| import org.matrix.android.sdk.api.rendezvous.model.PayloadType | ||||
| import org.matrix.android.sdk.api.rendezvous.model.Protocol | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousError | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousIntent | ||||
| import org.matrix.android.sdk.api.rendezvous.transports.SimpleHttpRendezvousTransport | ||||
| import org.matrix.android.sdk.api.session.Session | ||||
| import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel | ||||
| import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME | ||||
| import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME | ||||
| import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME | ||||
| import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME | ||||
| import org.matrix.android.sdk.api.util.MatrixJsonParser | ||||
| import timber.log.Timber | ||||
| 
 | ||||
| /** | ||||
|  * Implementation of MSC3906 to sign in + E2EE set up using a QR code. | ||||
|  */ | ||||
| class Rendezvous( | ||||
|         val channel: RendezvousChannel, | ||||
|         val theirIntent: RendezvousIntent, | ||||
| ) { | ||||
|     companion object { | ||||
|         private val TAG = LoggerTag(Rendezvous::class.java.simpleName, LoggerTag.RENDEZVOUS).value | ||||
| 
 | ||||
|         @Throws(RendezvousError::class) | ||||
|         fun buildChannelFromCode(code: String): Rendezvous { | ||||
|             val parsed = try { | ||||
|                 // we rely on moshi validating the code and throwing exception if invalid JSON or doesn't | ||||
|                 MatrixJsonParser.getMoshi().adapter(ECDHRendezvousCode::class.java).fromJson(code) | ||||
|             } catch (a: Throwable) { | ||||
|                 throw RendezvousError("Invalid code", RendezvousFailureReason.InvalidCode) | ||||
|             } ?: throw RendezvousError("Invalid code", RendezvousFailureReason.InvalidCode) | ||||
| 
 | ||||
|             val transport = SimpleHttpRendezvousTransport(parsed.rendezvous.transport.uri) | ||||
| 
 | ||||
|             return Rendezvous( | ||||
|                     ECDHRendezvousChannel(transport, parsed.rendezvous.key), | ||||
|                     parsed.intent | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private val adapter = MatrixJsonParser.getMoshi().adapter(Payload::class.java) | ||||
| 
 | ||||
|     // not yet implemented: RendezvousIntent.RECIPROCATE_LOGIN_ON_EXISTING_DEVICE | ||||
|     val ourIntent: RendezvousIntent = RendezvousIntent.LOGIN_ON_NEW_DEVICE | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     private suspend fun checkCompatibility() { | ||||
|         val incompatible = theirIntent == ourIntent | ||||
| 
 | ||||
|         Timber.tag(TAG).d("ourIntent: $ourIntent, theirIntent: $theirIntent, incompatible: $incompatible") | ||||
| 
 | ||||
|         if (incompatible) { | ||||
|             // inform the other side | ||||
|             send(Payload(PayloadType.FINISH, intent = ourIntent)) | ||||
|             if (ourIntent == RendezvousIntent.LOGIN_ON_NEW_DEVICE) { | ||||
|                 throw RendezvousError("The other device isn't signed in", RendezvousFailureReason.OtherDeviceNotSignedIn) | ||||
|             } else { | ||||
|                 throw RendezvousError("The other device is already signed in", RendezvousFailureReason.OtherDeviceAlreadySignedIn) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun startAfterScanningCode(): String { | ||||
|         val checksum = channel.connect() | ||||
| 
 | ||||
|         Timber.tag(TAG).i("Connected to secure channel with checksum: $checksum") | ||||
| 
 | ||||
|         checkCompatibility() | ||||
| 
 | ||||
|         // get protocols | ||||
|         Timber.tag(TAG).i("Waiting for protocols") | ||||
|         val protocolsResponse = receive() | ||||
| 
 | ||||
|         if (protocolsResponse?.protocols == null || !protocolsResponse.protocols.contains(Protocol.LOGIN_TOKEN)) { | ||||
|             send(Payload(PayloadType.FINISH, outcome = Outcome.UNSUPPORTED)) | ||||
|             throw RendezvousError("Unsupported protocols", RendezvousFailureReason.UnsupportedHomeserver) | ||||
|         } | ||||
| 
 | ||||
|         send(Payload(PayloadType.PROGRESS, protocol = Protocol.LOGIN_TOKEN)) | ||||
| 
 | ||||
|         return checksum | ||||
|     } | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun waitForLoginOnNewDevice(authenticationService: AuthenticationService): Session { | ||||
|         Timber.tag(TAG).i("Waiting for login_token") | ||||
| 
 | ||||
|         val loginToken = receive() | ||||
| 
 | ||||
|         if (loginToken?.type == PayloadType.FINISH) { | ||||
|             when (loginToken.outcome) { | ||||
|                 Outcome.DECLINED -> { | ||||
|                     throw RendezvousError("Login declined by other device", RendezvousFailureReason.UserDeclined) | ||||
|                 } | ||||
|                 Outcome.UNSUPPORTED -> { | ||||
|                     throw RendezvousError("Homeserver lacks support", RendezvousFailureReason.UnsupportedHomeserver) | ||||
|                 } | ||||
|                 else -> { | ||||
|                     throw RendezvousError("Unknown error", RendezvousFailureReason.Unknown) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         val homeserver = loginToken?.homeserver ?: throw RendezvousError("No homeserver returned", RendezvousFailureReason.ProtocolError) | ||||
|         val token = loginToken.loginToken ?: throw RendezvousError("No login token returned", RendezvousFailureReason.ProtocolError) | ||||
| 
 | ||||
|         Timber.tag(TAG).i("Got login_token now attempting to sign in with $homeserver") | ||||
| 
 | ||||
|         val hsConfig = HomeServerConnectionConfig(homeServerUri = Uri.parse(homeserver)) | ||||
|         return authenticationService.loginUsingQrLoginToken(hsConfig, token) | ||||
|     } | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun completeVerificationOnNewDevice(session: Session) { | ||||
|         val userId = session.myUserId | ||||
|         val crypto = session.cryptoService() | ||||
|         val deviceId = crypto.getMyDevice().deviceId | ||||
|         val deviceKey = crypto.getMyDevice().fingerprint() | ||||
|         send(Payload(PayloadType.PROGRESS, outcome = Outcome.SUCCESS, deviceId = deviceId, deviceKey = deviceKey)) | ||||
| 
 | ||||
|         // await confirmation of verification | ||||
|         val verificationResponse = receive() | ||||
|         if (verificationResponse?.outcome == Outcome.VERIFIED) { | ||||
|             val verifyingDeviceId = verificationResponse.verifyingDeviceId | ||||
|                     ?: throw RendezvousError("No verifying device id returned", RendezvousFailureReason.ProtocolError) | ||||
|             val verifyingDeviceFromServer = crypto.getCryptoDeviceInfo(userId, verifyingDeviceId) | ||||
|             if (verifyingDeviceFromServer?.fingerprint() != verificationResponse.verifyingDeviceKey) { | ||||
|                 Timber.tag(TAG).w( | ||||
|                         "Verifying device $verifyingDeviceId key doesn't match: ${ | ||||
|                             verifyingDeviceFromServer?.fingerprint() | ||||
|                         } vs ${verificationResponse.verifyingDeviceKey})" | ||||
|                 ) | ||||
|                 // inform the other side | ||||
|                 send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) | ||||
|                 throw RendezvousError("Key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) | ||||
|             } | ||||
| 
 | ||||
|             verificationResponse.masterKey?.let { masterKeyFromVerifyingDevice -> | ||||
|                 // verifying device provided us with a master key, so use it to check integrity | ||||
| 
 | ||||
|                 // see what the homeserver told us | ||||
|                 val localMasterKey = crypto.crossSigningService().getMyCrossSigningKeys()?.masterKey() | ||||
| 
 | ||||
|                 // n.b. if no local master key this is a problem, as well as it not matching | ||||
|                 if (localMasterKey?.unpaddedBase64PublicKey != masterKeyFromVerifyingDevice) { | ||||
|                     Timber.tag(TAG).w("Master key from verifying device doesn't match: $masterKeyFromVerifyingDevice vs $localMasterKey") | ||||
|                     // inform the other side | ||||
|                     send(Payload(PayloadType.FINISH, outcome = Outcome.E2EE_SECURITY_ERROR)) | ||||
|                     throw RendezvousError("Master key from verifying device doesn't match", RendezvousFailureReason.E2EESecurityIssue) | ||||
|                 } | ||||
| 
 | ||||
|                 // set other device as verified | ||||
|                 Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") | ||||
|                 crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) | ||||
| 
 | ||||
|                 Timber.tag(TAG).i("Setting master key as trusted") | ||||
|                 crypto.crossSigningService().markMyMasterKeyAsTrusted() | ||||
|             } ?: run { | ||||
|                 // set other device as verified anyway | ||||
|                 Timber.tag(TAG).i("Setting device $verifyingDeviceId as verified") | ||||
|                 crypto.setDeviceVerification(DeviceTrustLevel(locallyVerified = true, crossSigningVerified = false), userId, verifyingDeviceId) | ||||
| 
 | ||||
|                 Timber.tag(TAG).i("No master key given by verifying device") | ||||
|             } | ||||
| 
 | ||||
|             // request secrets from the verifying device | ||||
|             Timber.tag(TAG).i("Requesting secrets from $verifyingDeviceId") | ||||
| 
 | ||||
|             session.sharedSecretStorageService().let { | ||||
|                 it.requestSecret(MASTER_KEY_SSSS_NAME, verifyingDeviceId) | ||||
|                 it.requestSecret(SELF_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) | ||||
|                 it.requestSecret(USER_SIGNING_KEY_SSSS_NAME, verifyingDeviceId) | ||||
|                 it.requestSecret(KEYBACKUP_SECRET_SSSS_NAME, verifyingDeviceId) | ||||
|             } | ||||
|         } else { | ||||
|             Timber.tag(TAG).i("Not doing verification") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     private suspend fun receive(): Payload? { | ||||
|         val data = channel.receive() ?: return null | ||||
|         val payload = try { | ||||
|             adapter.fromJson(data.toString(Charsets.UTF_8)) | ||||
|         } catch (e: Exception) { | ||||
|             Timber.tag(TAG).w(e, "Failed to parse payload") | ||||
|             throw RendezvousError("Invalid payload received", RendezvousFailureReason.Unknown) | ||||
|         } | ||||
| 
 | ||||
|         return payload | ||||
|     } | ||||
| 
 | ||||
|     private suspend fun send(payload: Payload) { | ||||
|         channel.send(adapter.toJson(payload).toByteArray(Charsets.UTF_8)) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun close() { | ||||
|         channel.close() | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous | ||||
| 
 | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousError | ||||
| 
 | ||||
| /** | ||||
|  * Representation of a rendezvous channel such as that described by MSC3903. | ||||
|  */ | ||||
| interface RendezvousChannel { | ||||
|     val transport: RendezvousTransport | ||||
| 
 | ||||
|     /** | ||||
|      * @returns the checksum/confirmation digits to be shown to the user | ||||
|      */ | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun connect(): String | ||||
| 
 | ||||
|     /** | ||||
|      * Send a payload via the channel. | ||||
|      * @param data payload to send | ||||
|      */ | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun send(data: ByteArray) | ||||
| 
 | ||||
|     /** | ||||
|      * Receive a payload from the channel. | ||||
|      * @returns the received payload | ||||
|      */ | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun receive(): ByteArray? | ||||
| 
 | ||||
|     /** | ||||
|      * Closes the channel and cleans up. | ||||
|      */ | ||||
|     suspend fun close() | ||||
| } | ||||
| @ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous | ||||
| 
 | ||||
| enum class RendezvousFailureReason(val canRetry: Boolean = true) { | ||||
|     UserDeclined, | ||||
|     OtherDeviceNotSignedIn, | ||||
|     OtherDeviceAlreadySignedIn, | ||||
|     Unknown, | ||||
|     Expired, | ||||
|     UserCancelled, | ||||
|     InvalidCode, | ||||
|     UnsupportedAlgorithm(false), | ||||
|     UnsupportedTransport(false), | ||||
|     UnsupportedHomeserver(false), | ||||
|     ProtocolError, | ||||
|     E2EESecurityIssue(false) | ||||
| } | ||||
| @ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous | ||||
| 
 | ||||
| import okhttp3.MediaType | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousError | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails | ||||
| 
 | ||||
| interface RendezvousTransport { | ||||
|     var ready: Boolean | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun details(): RendezvousTransportDetails | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun send(contentType: MediaType, data: ByteArray) | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     suspend fun receive(): ByteArray? | ||||
| 
 | ||||
|     suspend fun close() | ||||
| } | ||||
| @ -0,0 +1,183 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.channels | ||||
| 
 | ||||
| import android.util.Base64 | ||||
| import com.squareup.moshi.JsonClass | ||||
| import kotlinx.coroutines.sync.Mutex | ||||
| import kotlinx.coroutines.sync.withLock | ||||
| import okhttp3.MediaType.Companion.toMediaType | ||||
| import org.matrix.android.sdk.api.logger.LoggerTag | ||||
| import org.matrix.android.sdk.api.rendezvous.RendezvousChannel | ||||
| import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason | ||||
| import org.matrix.android.sdk.api.rendezvous.RendezvousTransport | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousError | ||||
| import org.matrix.android.sdk.api.rendezvous.model.SecureRendezvousChannelAlgorithm | ||||
| import org.matrix.android.sdk.api.util.MatrixJsonParser | ||||
| import org.matrix.android.sdk.internal.crypto.verification.SASDefaultVerificationTransaction | ||||
| import org.matrix.olm.OlmSAS | ||||
| import timber.log.Timber | ||||
| import java.security.SecureRandom | ||||
| import java.util.LinkedList | ||||
| import javax.crypto.Cipher | ||||
| import javax.crypto.spec.IvParameterSpec | ||||
| import javax.crypto.spec.SecretKeySpec | ||||
| 
 | ||||
| /** | ||||
|  *  Implements X25519 ECDH key agreement and AES-256-GCM encryption channel as per MSC3903: | ||||
|  *  https://github.com/matrix-org/matrix-spec-proposals/pull/3903 | ||||
|  */ | ||||
| class ECDHRendezvousChannel(override var transport: RendezvousTransport, theirPublicKeyBase64: String?) : RendezvousChannel { | ||||
|     companion object { | ||||
|         private const val ALGORITHM_SPEC = "AES/GCM/NoPadding" | ||||
|         private const val KEY_SPEC = "AES" | ||||
|         private val TAG = LoggerTag(ECDHRendezvousChannel::class.java.simpleName, LoggerTag.RENDEZVOUS).value | ||||
|     } | ||||
| 
 | ||||
|     @JsonClass(generateAdapter = true) | ||||
|     internal data class ECDHPayload( | ||||
|             val algorithm: SecureRendezvousChannelAlgorithm? = null, | ||||
|             val key: String? = null, | ||||
|             val ciphertext: String? = null, | ||||
|             val iv: String? = null | ||||
|     ) | ||||
| 
 | ||||
|     private val olmSASMutex = Mutex() | ||||
|     private var olmSAS: OlmSAS? | ||||
|     private val ourPublicKey: ByteArray | ||||
|     private val ecdhAdapter = MatrixJsonParser.getMoshi().adapter(ECDHPayload::class.java) | ||||
|     private var theirPublicKey: ByteArray? = null | ||||
|     private var aesKey: ByteArray? = null | ||||
| 
 | ||||
|     init { | ||||
|         theirPublicKeyBase64?.let { | ||||
|             theirPublicKey = Base64.decode(it, Base64.NO_WRAP) | ||||
|         } | ||||
|         olmSAS = OlmSAS() | ||||
|         ourPublicKey = Base64.decode(olmSAS!!.publicKey, Base64.NO_WRAP) | ||||
|     } | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     override suspend fun connect(): String { | ||||
|         val sas = olmSAS ?: throw RendezvousError("Channel closed", RendezvousFailureReason.Unknown) | ||||
|         val isInitiator = theirPublicKey == null | ||||
| 
 | ||||
|         if (isInitiator) { | ||||
|             Timber.tag(TAG).i("Waiting for other device to send their public key") | ||||
|             val res = this.receiveAsPayload() ?: throw RendezvousError("No reply from other device", RendezvousFailureReason.ProtocolError) | ||||
| 
 | ||||
|             if (res.key == null) { | ||||
|                 throw RendezvousError( | ||||
|                         "Unsupported algorithm: ${res.algorithm}", | ||||
|                         RendezvousFailureReason.UnsupportedAlgorithm, | ||||
|                 ) | ||||
|             } | ||||
|             theirPublicKey = Base64.decode(res.key, Base64.NO_WRAP) | ||||
|         } else { | ||||
|             // send our public key unencrypted | ||||
|             Timber.tag(TAG).i("Sending public key") | ||||
|             send( | ||||
|                     ECDHPayload( | ||||
|                             algorithm = SecureRendezvousChannelAlgorithm.ECDH_V1, | ||||
|                             key = Base64.encodeToString(ourPublicKey, Base64.NO_WRAP) | ||||
|                     ) | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         olmSASMutex.withLock { | ||||
|             sas.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) | ||||
|             sas.setTheirPublicKey(Base64.encodeToString(theirPublicKey, Base64.NO_WRAP)) | ||||
| 
 | ||||
|             val initiatorKey = Base64.encodeToString(if (isInitiator) ourPublicKey else theirPublicKey, Base64.NO_WRAP) | ||||
|             val recipientKey = Base64.encodeToString(if (isInitiator) theirPublicKey else ourPublicKey, Base64.NO_WRAP) | ||||
|             val aesInfo = "${SecureRendezvousChannelAlgorithm.ECDH_V1.value}|$initiatorKey|$recipientKey" | ||||
| 
 | ||||
|             aesKey = sas.generateShortCode(aesInfo, 32) | ||||
| 
 | ||||
|             val rawChecksum = sas.generateShortCode(aesInfo, 5) | ||||
|             return SASDefaultVerificationTransaction.getDecimalCodeRepresentation(rawChecksum, separator = "-") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private suspend fun send(payload: ECDHPayload) { | ||||
|         transport.send("application/json".toMediaType(), ecdhAdapter.toJson(payload).toByteArray(Charsets.UTF_8)) | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun send(data: ByteArray) { | ||||
|         if (aesKey == null) { | ||||
|             throw IllegalStateException("Shared secret not established") | ||||
|         } | ||||
|         send(encrypt(data)) | ||||
|     } | ||||
| 
 | ||||
|     private suspend fun receiveAsPayload(): ECDHPayload? { | ||||
|         transport.receive()?.toString(Charsets.UTF_8)?.let { | ||||
|             return ecdhAdapter.fromJson(it) | ||||
|         } ?: return null | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun receive(): ByteArray? { | ||||
|         if (aesKey == null) { | ||||
|             throw IllegalStateException("Shared secret not established") | ||||
|         } | ||||
|         val payload = receiveAsPayload() ?: return null | ||||
|         return decrypt(payload) | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun close() { | ||||
|         val sas = olmSAS ?: throw IllegalStateException("Channel already closed") | ||||
|         olmSASMutex.withLock { | ||||
|             // this does a double release check already so we don't re-check ourselves | ||||
|             sas.releaseSas() | ||||
|             olmSAS = null | ||||
|         } | ||||
|         transport.close() | ||||
|     } | ||||
| 
 | ||||
|     private fun encrypt(plainText: ByteArray): ECDHPayload { | ||||
|         val iv = ByteArray(16) | ||||
|         SecureRandom().nextBytes(iv) | ||||
| 
 | ||||
|         val cipherText = LinkedList<Byte>() | ||||
| 
 | ||||
|         val encryptCipher = Cipher.getInstance(ALGORITHM_SPEC) | ||||
|         val secretKeySpec = SecretKeySpec(aesKey, KEY_SPEC) | ||||
|         val ivParameterSpec = IvParameterSpec(iv) | ||||
|         encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) | ||||
|         cipherText.addAll(encryptCipher.update(plainText).toList()) | ||||
|         cipherText.addAll(encryptCipher.doFinal().toList()) | ||||
| 
 | ||||
|         return ECDHPayload( | ||||
|                 ciphertext = Base64.encodeToString(cipherText.toByteArray(), Base64.NO_WRAP), | ||||
|                 iv = Base64.encodeToString(iv, Base64.NO_WRAP) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     private fun decrypt(payload: ECDHPayload): ByteArray { | ||||
|         val iv = Base64.decode(payload.iv, Base64.NO_WRAP) | ||||
|         val encryptCipher = Cipher.getInstance(ALGORITHM_SPEC) | ||||
|         val secretKeySpec = SecretKeySpec(aesKey, KEY_SPEC) | ||||
|         val ivParameterSpec = IvParameterSpec(iv) | ||||
|         encryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) | ||||
| 
 | ||||
|         val plainText = LinkedList<Byte>() | ||||
|         plainText.addAll(encryptCipher.update(Base64.decode(payload.ciphertext, Base64.NO_WRAP)).toList()) | ||||
|         plainText.addAll(encryptCipher.doFinal().toList()) | ||||
| 
 | ||||
|         return plainText.toByteArray() | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = true) | ||||
| data class ECDHRendezvous( | ||||
|         val transport: SimpleHttpRendezvousTransportDetails, | ||||
|         val algorithm: SecureRendezvousChannelAlgorithm, | ||||
|         val key: String | ||||
| ) | ||||
| @ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = true) | ||||
| data class ECDHRendezvousCode( | ||||
|         val intent: RendezvousIntent, | ||||
|         val rendezvous: ECDHRendezvous | ||||
| ) | ||||
| @ -0,0 +1,38 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.Json | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = false) | ||||
| enum class Outcome(val value: String) { | ||||
|     @Json(name = "success") | ||||
|     SUCCESS("success"), | ||||
| 
 | ||||
|     @Json(name = "declined") | ||||
|     DECLINED("declined"), | ||||
| 
 | ||||
|     @Json(name = "unsupported") | ||||
|     UNSUPPORTED("unsupported"), | ||||
| 
 | ||||
|     @Json(name = "verified") | ||||
|     VERIFIED("verified"), | ||||
| 
 | ||||
|     @Json(name = "e2ee_security_error") | ||||
|     E2EE_SECURITY_ERROR("e2ee_security_error") | ||||
| } | ||||
| @ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.Json | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = true) | ||||
| internal data class Payload( | ||||
|         val type: PayloadType, | ||||
|         val intent: RendezvousIntent? = null, | ||||
|         val outcome: Outcome? = null, | ||||
|         val protocols: List<Protocol>? = null, | ||||
|         val protocol: Protocol? = null, | ||||
|         val homeserver: String? = null, | ||||
|         @Json(name = "login_token") val loginToken: String? = null, | ||||
|         @Json(name = "device_id") val deviceId: String? = null, | ||||
|         @Json(name = "device_key") val deviceKey: String? = null, | ||||
|         @Json(name = "verifying_device_id") val verifyingDeviceId: String? = null, | ||||
|         @Json(name = "verifying_device_key") val verifyingDeviceKey: String? = null, | ||||
|         @Json(name = "master_key") val masterKey: String? = null | ||||
| ) | ||||
| @ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.Json | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = false) | ||||
| internal enum class PayloadType(val value: String) { | ||||
|     @Json(name = "m.login.start") | ||||
|     START("m.login.start"), | ||||
| 
 | ||||
|     @Json(name = "m.login.finish") | ||||
|     FINISH("m.login.finish"), | ||||
| 
 | ||||
|     @Json(name = "m.login.progress") | ||||
|     PROGRESS("m.login.progress") | ||||
| } | ||||
| @ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.Json | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = false) | ||||
| enum class Protocol(val value: String) { | ||||
|     @Json(name = "org.matrix.msc3906.login_token") | ||||
|     LOGIN_TOKEN("org.matrix.msc3906.login_token") | ||||
| } | ||||
| @ -0,0 +1,21 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason | ||||
| 
 | ||||
| class RendezvousError(val description: String, val reason: RendezvousFailureReason) : Exception(description) | ||||
| @ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.Json | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = false) | ||||
| enum class RendezvousIntent { | ||||
|     @Json(name = "login.start") LOGIN_ON_NEW_DEVICE, | ||||
|     @Json(name = "login.reciprocate") RECIPROCATE_LOGIN_ON_EXISTING_DEVICE | ||||
| } | ||||
| @ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = true) | ||||
| open class RendezvousTransportDetails( | ||||
|     val type: RendezvousTransportType | ||||
| ) | ||||
| @ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.Json | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = false) | ||||
| enum class RendezvousTransportType(val value: String) { | ||||
|     @Json(name = "org.matrix.msc3886.http.v1") | ||||
|     MSC3886_SIMPLE_HTTP_V1("org.matrix.msc3886.http.v1") | ||||
| } | ||||
| @ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.Json | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = false) | ||||
| enum class SecureRendezvousChannelAlgorithm(val value: String) { | ||||
|     @Json(name = "org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256") | ||||
|     ECDH_V1("org.matrix.msc3903.rendezvous.v1.curve25519-aes-sha256") | ||||
| } | ||||
| @ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.model | ||||
| 
 | ||||
| import com.squareup.moshi.JsonClass | ||||
| 
 | ||||
| @JsonClass(generateAdapter = true) | ||||
| data class SimpleHttpRendezvousTransportDetails( | ||||
|         val uri: String | ||||
| ) : RendezvousTransportDetails(type = RendezvousTransportType.MSC3886_SIMPLE_HTTP_V1) | ||||
| @ -0,0 +1,173 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.rendezvous.transports | ||||
| 
 | ||||
| import kotlinx.coroutines.delay | ||||
| import okhttp3.MediaType | ||||
| import okhttp3.Request | ||||
| import okhttp3.RequestBody.Companion.toRequestBody | ||||
| import org.matrix.android.sdk.api.logger.LoggerTag | ||||
| import org.matrix.android.sdk.api.rendezvous.RendezvousFailureReason | ||||
| import org.matrix.android.sdk.api.rendezvous.RendezvousTransport | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousError | ||||
| import org.matrix.android.sdk.api.rendezvous.model.RendezvousTransportDetails | ||||
| import org.matrix.android.sdk.api.rendezvous.model.SimpleHttpRendezvousTransportDetails | ||||
| import timber.log.Timber | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Date | ||||
| import java.util.Locale | ||||
| 
 | ||||
| /** | ||||
|  * Implementation of the Simple HTTP transport MSC3886: https://github.com/matrix-org/matrix-spec-proposals/pull/3886 | ||||
|  */ | ||||
| class SimpleHttpRendezvousTransport(rendezvousUri: String?) : RendezvousTransport { | ||||
|     companion object { | ||||
|         private val TAG = LoggerTag(SimpleHttpRendezvousTransport::class.java.simpleName, LoggerTag.RENDEZVOUS).value | ||||
|     } | ||||
| 
 | ||||
|     override var ready = false | ||||
|     private var cancelled = false | ||||
|     private var uri: String? | ||||
|     private var etag: String? = null | ||||
|     private var expiresAt: Date? = null | ||||
| 
 | ||||
|     init { | ||||
|         uri = rendezvousUri | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun details(): RendezvousTransportDetails { | ||||
|         val uri = uri ?: throw IllegalStateException("Rendezvous not set up") | ||||
| 
 | ||||
|         return SimpleHttpRendezvousTransportDetails(uri) | ||||
|     } | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     override suspend fun send(contentType: MediaType, data: ByteArray) { | ||||
|         if (cancelled) { | ||||
|             throw IllegalStateException("Rendezvous cancelled") | ||||
|         } | ||||
| 
 | ||||
|         val method = if (uri != null) "PUT" else "POST" | ||||
|         val uri = this.uri ?: throw RuntimeException("No rendezvous URI") | ||||
| 
 | ||||
|         val httpClient = okhttp3.OkHttpClient.Builder().build() | ||||
| 
 | ||||
|         val request = Request.Builder() | ||||
|                 .url(uri) | ||||
|                 .method(method, data.toRequestBody()) | ||||
|                 .header("content-type", contentType.toString()) | ||||
| 
 | ||||
|         etag?.let { | ||||
|             request.header("if-match", it) | ||||
|         } | ||||
| 
 | ||||
|         val response = httpClient.newCall(request.build()).execute() | ||||
| 
 | ||||
|         if (response.code == 404) { | ||||
|             throw get404Error() | ||||
|         } | ||||
|         etag = response.header("etag") | ||||
| 
 | ||||
|         Timber.tag(TAG).i("Sent data to $uri new etag $etag") | ||||
| 
 | ||||
|         if (method == "POST") { | ||||
|             val location = response.header("location") ?: throw RuntimeException("No rendezvous URI found in response") | ||||
| 
 | ||||
|             response.header("expires")?.let { | ||||
|                 val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) | ||||
|                 expiresAt = format.parse(it) | ||||
|             } | ||||
| 
 | ||||
|             // resolve location header which could be relative or absolute | ||||
|             this.uri = response.request.url.toUri().resolve(location).toString() | ||||
|             ready = true | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Throws(RendezvousError::class) | ||||
|     override suspend fun receive(): ByteArray? { | ||||
|         if (cancelled) { | ||||
|             throw IllegalStateException("Rendezvous cancelled") | ||||
|         } | ||||
|         val uri = uri ?: throw IllegalStateException("Rendezvous not set up") | ||||
|         val httpClient = okhttp3.OkHttpClient.Builder().build() | ||||
|         while (true) { | ||||
|             Timber.tag(TAG).i("Polling: $uri after etag $etag") | ||||
|             val request = Request.Builder() | ||||
|                     .url(uri) | ||||
|                     .get() | ||||
| 
 | ||||
|             etag?.let { | ||||
|                 request.header("if-none-match", it) | ||||
|             } | ||||
| 
 | ||||
|             val response = httpClient.newCall(request.build()).execute() | ||||
| 
 | ||||
|             try { | ||||
|                 // expired | ||||
|                 if (response.code == 404) { | ||||
|                     throw get404Error() | ||||
|                 } | ||||
| 
 | ||||
|                 // rely on server expiring the channel rather than checking ourselves | ||||
| 
 | ||||
|                 if (response.header("content-type") != "application/json") { | ||||
|                     response.header("etag")?.let { | ||||
|                         etag = it | ||||
|                     } | ||||
|                 } else if (response.code == 200) { | ||||
|                     response.header("etag")?.let { | ||||
|                         etag = it | ||||
|                     } | ||||
|                     return response.body?.bytes() | ||||
|                 } | ||||
| 
 | ||||
|                 // sleep for a second before polling again | ||||
|                 // we rely on the server expiring the channel rather than checking it ourselves | ||||
|                 delay(1000) | ||||
|             } finally { | ||||
|                 response.close() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun get404Error(): RendezvousError { | ||||
|         if (expiresAt != null && Date() > expiresAt) { | ||||
|             return RendezvousError("Expired", RendezvousFailureReason.Expired) | ||||
|         } | ||||
| 
 | ||||
|         return RendezvousError("Received unexpected 404", RendezvousFailureReason.Unknown) | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun close() { | ||||
|         cancelled = true | ||||
|         ready = false | ||||
| 
 | ||||
|         uri?.let { | ||||
|             try { | ||||
|                 val httpClient = okhttp3.OkHttpClient.Builder().build() | ||||
|                 val request = Request.Builder() | ||||
|                         .url(it) | ||||
|                         .delete() | ||||
|                         .build() | ||||
|                 httpClient.newCall(request).execute() | ||||
|             } catch (e: Throwable) { | ||||
|                 Timber.tag(TAG).w(e, "Failed to delete channel") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -31,6 +31,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent | ||||
| import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent | ||||
| import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent | ||||
| import org.matrix.android.sdk.api.session.room.model.message.MessageType | ||||
| import org.matrix.android.sdk.api.session.room.model.message.asMessageAudioEvent | ||||
| import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent | ||||
| import org.matrix.android.sdk.api.session.room.model.relation.shouldRenderInThread | ||||
| import org.matrix.android.sdk.api.session.room.send.SendState | ||||
| @ -357,6 +358,10 @@ fun Event.isAudioMessage(): Boolean { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fun Event.isVoiceMessage(): Boolean { | ||||
|     return this.asMessageAudioEvent()?.content?.voiceMessageIndicator != null | ||||
| } | ||||
| 
 | ||||
| fun Event.isFileMessage(): Boolean { | ||||
|     return when (getMsgType()) { | ||||
|         MessageType.MSGTYPE_FILE -> true | ||||
| @ -396,7 +401,7 @@ fun Event.getRelationContent(): RelationDefaultContent? { | ||||
|             when (getClearType()) { | ||||
|                 EventType.STICKER -> getClearContent().toModel<MessageStickerContent>()?.relatesTo | ||||
|                 in EventType.BEACON_LOCATION_DATA -> getClearContent().toModel<MessageBeaconLocationDataContent>()?.relatesTo | ||||
|                 else -> null | ||||
|                 else -> getClearContent()?.get("m.relates_to")?.toContent().toModel() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -0,0 +1,47 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Matrix.org Foundation C.I.C. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.matrix.android.sdk.api.session.room.model.message | ||||
| 
 | ||||
| import org.matrix.android.sdk.api.extensions.tryOrNull | ||||
| import org.matrix.android.sdk.api.session.events.model.Event | ||||
| import org.matrix.android.sdk.api.session.events.model.EventType | ||||
| import org.matrix.android.sdk.api.session.events.model.toModel | ||||
| 
 | ||||
| /** | ||||
|  * [Event] wrapper for [EventType.MESSAGE] event type. | ||||
|  * Provides additional fields and functions related to this event type. | ||||
|  */ | ||||
| @JvmInline | ||||
| value class MessageAudioEvent(val root: Event) { | ||||
| 
 | ||||
|     /** | ||||
|      * The mapped [MessageAudioContent] model of the event content. | ||||
|      */ | ||||
|     val content: MessageAudioContent | ||||
|         get() = root.getClearContent().toModel<MessageContent>() as MessageAudioContent | ||||
| 
 | ||||
|     init { | ||||
|         require(tryOrNull { content } != null) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Map a [EventType.MESSAGE] event to a [MessageAudioEvent]. | ||||
|  */ | ||||
| fun Event.asMessageAudioEvent() = if (getClearType() == EventType.MESSAGE) { | ||||
|     tryOrNull { MessageAudioEvent(this) } | ||||
| } else null | ||||
| @ -45,18 +45,30 @@ interface SendService { | ||||
|      * @param text the text message to send | ||||
|      * @param msgType the message type: MessageType.MSGTYPE_TEXT (default) or MessageType.MSGTYPE_EMOTE | ||||
|      * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun sendTextMessage(text: CharSequence, msgType: String = MessageType.MSGTYPE_TEXT, autoMarkdown: Boolean = false): Cancelable | ||||
|     fun sendTextMessage( | ||||
|             text: CharSequence, | ||||
|             msgType: String = MessageType.MSGTYPE_TEXT, | ||||
|             autoMarkdown: Boolean = false, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Cancelable | ||||
| 
 | ||||
|     /** | ||||
|      * Method to send a text message with a formatted body. | ||||
|      * @param text the text message to send | ||||
|      * @param formattedText The formatted body using MessageType#FORMAT_MATRIX_HTML | ||||
|      * @param msgType the message type: MessageType.MSGTYPE_TEXT (default) or MessageType.MSGTYPE_EMOTE | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String = MessageType.MSGTYPE_TEXT): Cancelable | ||||
|     fun sendFormattedTextMessage( | ||||
|             text: String, | ||||
|             formattedText: String, | ||||
|             msgType: String = MessageType.MSGTYPE_TEXT, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Cancelable | ||||
| 
 | ||||
|     /** | ||||
|      * Method to quote an events content. | ||||
| @ -65,6 +77,7 @@ interface SendService { | ||||
|      * @param formattedText the formatted text message to send | ||||
|      * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present | ||||
|      * @param rootThreadEventId when this param is not null, the message will be sent in this specific thread | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun sendQuotedTextMessage( | ||||
| @ -73,6 +86,7 @@ interface SendService { | ||||
|             formattedText: String? = null, | ||||
|             autoMarkdown: Boolean, | ||||
|             rootThreadEventId: String? = null, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Cancelable | ||||
| 
 | ||||
|     /** | ||||
| @ -83,6 +97,7 @@ interface SendService { | ||||
|      *                It can be useful to send media to multiple room. It's safe to include the current roomId in this set | ||||
|      * @param rootThreadEventId when this param is not null, the Media will be sent in this specific thread | ||||
|      * @param relatesTo add a relation content to the media event | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun sendMedia( | ||||
| @ -91,6 +106,7 @@ interface SendService { | ||||
|             roomIds: Set<String>, | ||||
|             rootThreadEventId: String? = null, | ||||
|             relatesTo: RelationDefaultContent? = null, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Cancelable | ||||
| 
 | ||||
|     /** | ||||
| @ -100,6 +116,7 @@ interface SendService { | ||||
|      * @param roomIds set of roomIds to where the media will be sent. The current roomId will be add to this set if not present. | ||||
|      *                It can be useful to send media to multiple room. It's safe to include the current roomId in this set | ||||
|      * @param rootThreadEventId when this param is not null, all the Media will be sent in this specific thread | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun sendMedias( | ||||
| @ -107,6 +124,7 @@ interface SendService { | ||||
|             compressBeforeSending: Boolean, | ||||
|             roomIds: Set<String>, | ||||
|             rootThreadEventId: String? = null, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Cancelable | ||||
| 
 | ||||
|     /** | ||||
| @ -114,31 +132,35 @@ interface SendService { | ||||
|      * @param pollType indicates open or closed polls | ||||
|      * @param question the question | ||||
|      * @param options list of options | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun sendPoll(pollType: PollType, question: String, options: List<String>): Cancelable | ||||
|     fun sendPoll(pollType: PollType, question: String, options: List<String>, additionalContent: Content? = null): Cancelable | ||||
| 
 | ||||
|     /** | ||||
|      * Method to send a poll response. | ||||
|      * @param pollEventId the poll currently replied to | ||||
|      * @param answerId The id of the answer | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun voteToPoll(pollEventId: String, answerId: String): Cancelable | ||||
|     fun voteToPoll(pollEventId: String, answerId: String, additionalContent: Content? = null): Cancelable | ||||
| 
 | ||||
|     /** | ||||
|      * End a poll in the room. | ||||
|      * @param pollEventId event id of the poll | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      * @return a [Cancelable] | ||||
|      */ | ||||
|     fun endPoll(pollEventId: String): Cancelable | ||||
|     fun endPoll(pollEventId: String, additionalContent: Content? = null): Cancelable | ||||
| 
 | ||||
|     /** | ||||
|      * Redact (delete) the given event. | ||||
|      * @param event The event to redact | ||||
|      * @param reason Optional reason string | ||||
|      * @param additionalContent additional content to put in the event content | ||||
|      */ | ||||
|     fun redactEvent(event: Event, reason: String?): Cancelable | ||||
|     fun redactEvent(event: Event, reason: String?, additionalContent: Content? = null): Cancelable | ||||
| 
 | ||||
|     /** | ||||
|      * Schedule this message to be resent. | ||||
|  | ||||
| @ -106,6 +106,8 @@ interface Timeline { | ||||
| 
 | ||||
|         /** | ||||
|          * Called when new events come through the sync. | ||||
|          * Note that the corresponding events may not be available yet in the database. | ||||
|          * [onTimelineUpdated] will be called with the event content. | ||||
|          */ | ||||
|         fun onNewTimelineEvents(eventIds: List<String>) = Unit | ||||
| 
 | ||||
|  | ||||
| @ -55,4 +55,9 @@ interface TimelineService { | ||||
|      * Returns a snapshot list of TimelineEvent with EventType.MESSAGE and MessageType.MSGTYPE_IMAGE or MessageType.MSGTYPE_VIDEO. | ||||
|      */ | ||||
|     fun getAttachmentMessages(): List<TimelineEvent> | ||||
| 
 | ||||
|     /** | ||||
|      * Returns a snapshot list of TimelineEvent with a content relation of the given type to the given eventId. | ||||
|      */ | ||||
|     fun getTimelineEventsRelatedTo(relationType: String, eventId: String): List<TimelineEvent> | ||||
| } | ||||
|  | ||||
| @ -82,6 +82,33 @@ internal abstract class SASDefaultVerificationTransaction( | ||||
|         // older devices have limited support of emoji but SDK offers images for the 64 verification emojis | ||||
|         // so always send that we support EMOJI | ||||
|         val KNOWN_SHORT_CODES = listOf(SasMode.EMOJI, SasMode.DECIMAL) | ||||
| 
 | ||||
|         /** | ||||
|          * decimal: generate five bytes by using HKDF. | ||||
|          * Take the first 13 bits and convert it to a decimal number (which will be a number between 0 and 8191 inclusive), | ||||
|          * and add 1000 (resulting in a number between 1000 and 9191 inclusive). | ||||
|          * Do the same with the second 13 bits, and the third 13 bits, giving three 4-digit numbers. | ||||
|          * In other words, if the five bytes are B0, B1, B2, B3, and B4, then the first number is (B0 << 5 | B1 >> 3) + 1000, | ||||
|          * the second number is ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000, and the third number is ((B3 & 0x3f) << 7 | B4 >> 1) + 1000. | ||||
|          * (This method of converting 13 bits at a time is used to avoid requiring 32-bit clients to do big-number arithmetic, | ||||
|          * and adding 1000 to the number avoids having clients to worry about properly zero-padding the number when displaying to the user.) | ||||
|          * The three 4-digit numbers are displayed to the user either with dashes (or another appropriate separator) separating the three numbers, | ||||
|          * or with the three numbers on separate lines. | ||||
|          */ | ||||
|         fun getDecimalCodeRepresentation(byteArray: ByteArray, separator: String = " "): String { | ||||
|             val b0 = byteArray[0].toUnsignedInt() // need unsigned byte | ||||
|             val b1 = byteArray[1].toUnsignedInt() // need unsigned byte | ||||
|             val b2 = byteArray[2].toUnsignedInt() // need unsigned byte | ||||
|             val b3 = byteArray[3].toUnsignedInt() // need unsigned byte | ||||
|             val b4 = byteArray[4].toUnsignedInt() // need unsigned byte | ||||
|             // (B0 << 5 | B1 >> 3) + 1000 | ||||
|             val first = (b0.shl(5) or b1.shr(3)) + 1000 | ||||
|             // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 | ||||
|             val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 | ||||
|             // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 | ||||
|             val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 | ||||
|             return "$first$separator$second$separator$third" | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override var state: VerificationTxState = VerificationTxState.None | ||||
| @ -371,33 +398,6 @@ internal abstract class SASDefaultVerificationTransaction( | ||||
|         return getDecimalCodeRepresentation(shortCodeBytes!!) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * decimal: generate five bytes by using HKDF. | ||||
|      * Take the first 13 bits and convert it to a decimal number (which will be a number between 0 and 8191 inclusive), | ||||
|      * and add 1000 (resulting in a number between 1000 and 9191 inclusive). | ||||
|      * Do the same with the second 13 bits, and the third 13 bits, giving three 4-digit numbers. | ||||
|      * In other words, if the five bytes are B0, B1, B2, B3, and B4, then the first number is (B0 << 5 | B1 >> 3) + 1000, | ||||
|      * the second number is ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000, and the third number is ((B3 & 0x3f) << 7 | B4 >> 1) + 1000. | ||||
|      * (This method of converting 13 bits at a time is used to avoid requiring 32-bit clients to do big-number arithmetic, | ||||
|      * and adding 1000 to the number avoids having clients to worry about properly zero-padding the number when displaying to the user.) | ||||
|      * The three 4-digit numbers are displayed to the user either with dashes (or another appropriate separator) separating the three numbers, | ||||
|      * or with the three numbers on separate lines. | ||||
|      */ | ||||
|     fun getDecimalCodeRepresentation(byteArray: ByteArray): String { | ||||
|         val b0 = byteArray[0].toUnsignedInt() // need unsigned byte | ||||
|         val b1 = byteArray[1].toUnsignedInt() // need unsigned byte | ||||
|         val b2 = byteArray[2].toUnsignedInt() // need unsigned byte | ||||
|         val b3 = byteArray[3].toUnsignedInt() // need unsigned byte | ||||
|         val b4 = byteArray[4].toUnsignedInt() // need unsigned byte | ||||
|         // (B0 << 5 | B1 >> 3) + 1000 | ||||
|         val first = (b0.shl(5) or b1.shr(3)) + 1000 | ||||
|         // ((B1 & 0x7) << 10 | B2 << 2 | B3 >> 6) + 1000 | ||||
|         val second = ((b1 and 0x7).shl(10) or b2.shl(2) or b3.shr(6)) + 1000 | ||||
|         // ((B3 & 0x3f) << 7 | B4 >> 1) + 1000 | ||||
|         val third = ((b3 and 0x3f).shl(7) or b4.shr(1)) + 1000 | ||||
|         return "$first $second $third" | ||||
|     } | ||||
| 
 | ||||
|     override fun getEmojiCodeRepresentation(): List<EmojiRepresentation> { | ||||
|         return getEmojiCodeRepresentation(shortCodeBytes!!) | ||||
|     } | ||||
|  | ||||
| @ -26,6 +26,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull | ||||
| import org.matrix.android.sdk.api.listeners.ProgressListener | ||||
| import org.matrix.android.sdk.api.session.content.ContentAttachmentData | ||||
| import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileInfo | ||||
| import org.matrix.android.sdk.api.session.events.model.Content | ||||
| import org.matrix.android.sdk.api.session.events.model.toContent | ||||
| import org.matrix.android.sdk.api.session.events.model.toModel | ||||
| import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent | ||||
| @ -407,7 +408,10 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter | ||||
|             newAttachmentAttributes: NewAttachmentAttributes | ||||
|     ) { | ||||
|         localEchoRepository.updateEcho(eventId) { _, event -> | ||||
|             val messageContent: MessageContent? = event.asDomain().content.toModel() | ||||
|             val content: Content? = event.asDomain().content | ||||
|             val messageContent: MessageContent? = content.toModel() | ||||
|             // Retrieve potential additional content from the original event | ||||
|             val additionalContent = content.orEmpty() - messageContent?.toContent().orEmpty().keys | ||||
|             val updatedContent = when (messageContent) { | ||||
|                 is MessageImageContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes) | ||||
|                 is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newAttachmentAttributes) | ||||
| @ -415,7 +419,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter | ||||
|                 is MessageAudioContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize) | ||||
|                 else -> messageContent | ||||
|             } | ||||
|             event.content = ContentMapper.map(updatedContent.toContent()) | ||||
|             event.content = ContentMapper.map(updatedContent.toContent().plus(additionalContent)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -17,26 +17,40 @@ | ||||
| 
 | ||||
| package org.matrix.android.sdk.internal.session.profile | ||||
| 
 | ||||
| import com.zhuinden.monarchy.Monarchy | ||||
| import org.matrix.android.sdk.api.session.user.model.User | ||||
| import org.matrix.android.sdk.api.util.JsonDict | ||||
| import org.matrix.android.sdk.internal.di.SessionDatabase | ||||
| import org.matrix.android.sdk.internal.network.GlobalErrorReceiver | ||||
| import org.matrix.android.sdk.internal.network.executeRequest | ||||
| import org.matrix.android.sdk.internal.session.user.UserEntityFactory | ||||
| import org.matrix.android.sdk.internal.task.Task | ||||
| import org.matrix.android.sdk.internal.util.awaitTransaction | ||||
| import javax.inject.Inject | ||||
| 
 | ||||
| internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, JsonDict> { | ||||
|     data class Params( | ||||
|             val userId: String | ||||
|             val userId: String, | ||||
|             val storeInDatabase: Boolean = true, | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| internal class DefaultGetProfileInfoTask @Inject constructor( | ||||
|         private val profileAPI: ProfileAPI, | ||||
|         private val globalErrorReceiver: GlobalErrorReceiver | ||||
|         private val globalErrorReceiver: GlobalErrorReceiver, | ||||
|         @SessionDatabase private val monarchy: Monarchy, | ||||
| ) : GetProfileInfoTask() { | ||||
| 
 | ||||
|     override suspend fun execute(params: Params): JsonDict { | ||||
|         return executeRequest(globalErrorReceiver) { | ||||
|             profileAPI.getProfile(params.userId) | ||||
|         }.also { user -> | ||||
|             if (params.storeInDatabase) { | ||||
|                 // Insert into DB | ||||
|                 monarchy.awaitTransaction { | ||||
|                     it.insertOrUpdate(UserEntityFactory.create(User.fromJson(params.userId, user))) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -27,6 +27,7 @@ import dagger.assisted.AssistedInject | ||||
| import kotlinx.coroutines.launch | ||||
| import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl | ||||
| import org.matrix.android.sdk.api.session.content.ContentAttachmentData | ||||
| import org.matrix.android.sdk.api.session.events.model.Content | ||||
| import org.matrix.android.sdk.api.session.events.model.Event | ||||
| import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage | ||||
| import org.matrix.android.sdk.api.session.events.model.isTextMessage | ||||
| @ -88,14 +89,14 @@ internal class DefaultSendService @AssistedInject constructor( | ||||
|                 .let { sendEvent(it) } | ||||
|     } | ||||
| 
 | ||||
|     override fun sendTextMessage(text: CharSequence, msgType: String, autoMarkdown: Boolean): Cancelable { | ||||
|         return localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown) | ||||
|     override fun sendTextMessage(text: CharSequence, msgType: String, autoMarkdown: Boolean, additionalContent: Content?): Cancelable { | ||||
|         return localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown, additionalContent) | ||||
|                 .also { createLocalEcho(it) } | ||||
|                 .let { sendEvent(it) } | ||||
|     } | ||||
| 
 | ||||
|     override fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String): Cancelable { | ||||
|         return localEchoEventFactory.createFormattedTextEvent(roomId, TextContent(text, formattedText), msgType) | ||||
|     override fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String, additionalContent: Content?): Cancelable { | ||||
|         return localEchoEventFactory.createFormattedTextEvent(roomId, TextContent(text, formattedText), msgType, additionalContent) | ||||
|                 .also { createLocalEcho(it) } | ||||
|                 .let { sendEvent(it) } | ||||
|     } | ||||
| @ -105,7 +106,8 @@ internal class DefaultSendService @AssistedInject constructor( | ||||
|             text: String, | ||||
|             formattedText: String?, | ||||
|             autoMarkdown: Boolean, | ||||
|             rootThreadEventId: String? | ||||
|             rootThreadEventId: String?, | ||||
|             additionalContent: Content?, | ||||
|     ): Cancelable { | ||||
|         return localEchoEventFactory.createQuotedTextEvent( | ||||
|                 roomId = roomId, | ||||
| @ -113,33 +115,34 @@ internal class DefaultSendService @AssistedInject constructor( | ||||
|                 text = text, | ||||
|                 formattedText = formattedText, | ||||
|                 autoMarkdown = autoMarkdown, | ||||
|                 rootThreadEventId = rootThreadEventId | ||||
|                 rootThreadEventId = rootThreadEventId, | ||||
|                 additionalContent = additionalContent, | ||||
|         ) | ||||
|                 .also { createLocalEcho(it) } | ||||
|                 .let { sendEvent(it) } | ||||
|     } | ||||
| 
 | ||||
|     override fun sendPoll(pollType: PollType, question: String, options: List<String>): Cancelable { | ||||
|         return localEchoEventFactory.createPollEvent(roomId, pollType, question, options) | ||||
|     override fun sendPoll(pollType: PollType, question: String, options: List<String>, additionalContent: Content?): Cancelable { | ||||
|         return localEchoEventFactory.createPollEvent(roomId, pollType, question, options, additionalContent) | ||||
|                 .also { createLocalEcho(it) } | ||||
|                 .let { sendEvent(it) } | ||||
|     } | ||||
| 
 | ||||
|     override fun voteToPoll(pollEventId: String, answerId: String): Cancelable { | ||||
|         return localEchoEventFactory.createPollReplyEvent(roomId, pollEventId, answerId) | ||||
|     override fun voteToPoll(pollEventId: String, answerId: String, additionalContent: Content?): Cancelable { | ||||
|         return localEchoEventFactory.createPollReplyEvent(roomId, pollEventId, answerId, additionalContent) | ||||
|                 .also { createLocalEcho(it) } | ||||
|                 .let { sendEvent(it) } | ||||
|     } | ||||
| 
 | ||||
|     override fun endPoll(pollEventId: String): Cancelable { | ||||
|         return localEchoEventFactory.createEndPollEvent(roomId, pollEventId) | ||||
|     override fun endPoll(pollEventId: String, additionalContent: Content?): Cancelable { | ||||
|         return localEchoEventFactory.createEndPollEvent(roomId, pollEventId, additionalContent) | ||||
|                 .also { createLocalEcho(it) } | ||||
|                 .let { sendEvent(it) } | ||||
|     } | ||||
| 
 | ||||
|     override fun redactEvent(event: Event, reason: String?): Cancelable { | ||||
|     override fun redactEvent(event: Event, reason: String?, additionalContent: Content?): Cancelable { | ||||
|         // TODO manage media/attachements? | ||||
|         val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason) | ||||
|         val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason, additionalContent) | ||||
|                 .also { createLocalEcho(it) } | ||||
|         return eventSenderProcessor.postRedaction(redactionEcho, reason) | ||||
|     } | ||||
| @ -265,7 +268,8 @@ internal class DefaultSendService @AssistedInject constructor( | ||||
|             attachments: List<ContentAttachmentData>, | ||||
|             compressBeforeSending: Boolean, | ||||
|             roomIds: Set<String>, | ||||
|             rootThreadEventId: String? | ||||
|             rootThreadEventId: String?, | ||||
|             additionalContent: Content?, | ||||
|     ): Cancelable { | ||||
|         return attachments.mapTo(CancelableBag()) { | ||||
|             sendMedia( | ||||
| @ -283,6 +287,7 @@ internal class DefaultSendService @AssistedInject constructor( | ||||
|             roomIds: Set<String>, | ||||
|             rootThreadEventId: String?, | ||||
|             relatesTo: RelationDefaultContent?, | ||||
|             additionalContent: Content?, | ||||
|     ): Cancelable { | ||||
|         // Ensure that the event will not be send in a thread if we are a different flow. | ||||
|         // Like sending files to multiple rooms | ||||
| @ -299,6 +304,7 @@ internal class DefaultSendService @AssistedInject constructor( | ||||
|                     attachment = attachment, | ||||
|                     rootThreadEventId = rootThreadId, | ||||
|                     relatesTo, | ||||
|                     additionalContent, | ||||
|             ).also { event -> | ||||
|                 createLocalEcho(event) | ||||
|             } | ||||
|  | ||||
| @ -95,12 +95,12 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|         private val permalinkFactory: PermalinkFactory, | ||||
|         private val clock: Clock, | ||||
| ) { | ||||
|     fun createTextEvent(roomId: String, msgType: String, text: CharSequence, autoMarkdown: Boolean): Event { | ||||
|     fun createTextEvent(roomId: String, msgType: String, text: CharSequence, autoMarkdown: Boolean, additionalContent: Content? = null): Event { | ||||
|         if (msgType == MessageType.MSGTYPE_TEXT || msgType == MessageType.MSGTYPE_EMOTE) { | ||||
|             return createFormattedTextEvent(roomId, createTextContent(text, autoMarkdown), msgType) | ||||
|             return createFormattedTextEvent(roomId, createTextContent(text, autoMarkdown), msgType, additionalContent) | ||||
|         } | ||||
|         val content = MessageTextContent(msgType = msgType, body = text.toString()) | ||||
|         return createMessageEvent(roomId, content) | ||||
|         return createMessageEvent(roomId, content, additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     private fun createTextContent(text: CharSequence, autoMarkdown: Boolean): TextContent { | ||||
| @ -116,8 +116,8 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|         return TextContent(text.toString()) | ||||
|     } | ||||
| 
 | ||||
|     fun createFormattedTextEvent(roomId: String, textContent: TextContent, msgType: String): Event { | ||||
|         return createMessageEvent(roomId, textContent.toMessageTextContent(msgType)) | ||||
|     fun createFormattedTextEvent(roomId: String, textContent: TextContent, msgType: String, additionalContent: Content? = null): Event { | ||||
|         return createMessageEvent(roomId, textContent.toMessageTextContent(msgType), additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     fun createReplaceTextEvent( | ||||
| @ -128,6 +128,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             newBodyAutoMarkdown: Boolean, | ||||
|             msgType: String, | ||||
|             compatibilityText: String, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val content = if (newBodyFormattedText != null) { | ||||
|             TextContent(newBodyText.toString(), newBodyFormattedText.toString()).toMessageTextContent(msgType) | ||||
| @ -141,7 +142,8 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                         body = compatibilityText, | ||||
|                         relatesTo = RelationDefaultContent(RelationType.REPLACE, targetEventId), | ||||
|                         newContent = content, | ||||
|                 ) | ||||
|                 ), | ||||
|                 additionalContent, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
| @ -167,6 +169,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             targetEventId: String, | ||||
|             question: String, | ||||
|             options: List<String>, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val newContent = MessagePollContent( | ||||
|                 relatesTo = RelationDefaultContent(RelationType.REPLACE, targetEventId), | ||||
| @ -179,7 +182,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 senderId = userId, | ||||
|                 eventId = localId, | ||||
|                 type = EventType.POLL_START.first(), | ||||
|                 content = newContent.toContent() | ||||
|                 content = newContent.toContent().plus(additionalContent.orEmpty()) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
| @ -187,6 +190,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             roomId: String, | ||||
|             pollEventId: String, | ||||
|             answerId: String, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val content = MessagePollResponseContent( | ||||
|                 body = answerId, | ||||
| @ -203,7 +207,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 senderId = userId, | ||||
|                 eventId = localId, | ||||
|                 type = EventType.POLL_RESPONSE.first(), | ||||
|                 content = content.toContent(), | ||||
|                 content = content.toContent().plus(additionalContent.orEmpty()), | ||||
|                 unsignedData = UnsignedData(age = null, transactionId = localId) | ||||
|         ) | ||||
|     } | ||||
| @ -213,6 +217,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             pollType: PollType, | ||||
|             question: String, | ||||
|             options: List<String>, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val content = createPollContent(question, options, pollType) | ||||
|         val localId = LocalEcho.createLocalEchoId() | ||||
| @ -222,7 +227,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 senderId = userId, | ||||
|                 eventId = localId, | ||||
|                 type = EventType.POLL_START.first(), | ||||
|                 content = content.toContent(), | ||||
|                 content = content.toContent().plus(additionalContent.orEmpty()), | ||||
|                 unsignedData = UnsignedData(age = null, transactionId = localId) | ||||
|         ) | ||||
|     } | ||||
| @ -230,6 +235,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|     fun createEndPollEvent( | ||||
|             roomId: String, | ||||
|             eventId: String, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val content = MessageEndPollContent( | ||||
|                 relatesTo = RelationDefaultContent( | ||||
| @ -244,7 +250,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 senderId = userId, | ||||
|                 eventId = localId, | ||||
|                 type = EventType.POLL_END.first(), | ||||
|                 content = content.toContent(), | ||||
|                 content = content.toContent().plus(additionalContent.orEmpty()), | ||||
|                 unsignedData = UnsignedData(age = null, transactionId = localId) | ||||
|         ) | ||||
|     } | ||||
| @ -255,6 +261,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             longitude: Double, | ||||
|             uncertainty: Double?, | ||||
|             isUserLocation: Boolean, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val geoUri = buildGeoUri(latitude, longitude, uncertainty) | ||||
|         val assetType = if (isUserLocation) LocationAssetType.SELF else LocationAssetType.PIN | ||||
| @ -266,7 +273,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 unstableTimestampMillis = clock.epochMillis(), | ||||
|                 unstableText = geoUri | ||||
|         ) | ||||
|         return createMessageEvent(roomId, content) | ||||
|         return createMessageEvent(roomId, content, additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     fun createLiveLocationEvent( | ||||
| @ -275,6 +282,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             latitude: Double, | ||||
|             longitude: Double, | ||||
|             uncertainty: Double?, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val geoUri = buildGeoUri(latitude, longitude, uncertainty) | ||||
|         val content = MessageBeaconLocationDataContent( | ||||
| @ -293,7 +301,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 senderId = userId, | ||||
|                 eventId = localId, | ||||
|                 type = EventType.BEACON_LOCATION_DATA.first(), | ||||
|                 content = content.toContent(), | ||||
|                 content = content.toContent().plus(additionalContent.orEmpty()), | ||||
|                 unsignedData = UnsignedData(age = null, transactionId = localId) | ||||
|         ) | ||||
|     } | ||||
| @ -306,6 +314,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             autoMarkdown: Boolean, | ||||
|             msgType: String, | ||||
|             compatibilityText: String, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val permalink = permalinkFactory.createPermalink(roomId, originalEvent.root.eventId ?: "", false) | ||||
|         val userLink = originalEvent.root.senderId?.let { permalinkFactory.createPermalink(it, false) } ?: "" | ||||
| @ -340,7 +349,8 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                                 formattedBody = replyFormatted | ||||
|                         ) | ||||
|                                 .toContent() | ||||
|                 ) | ||||
|                 ), | ||||
|                 additionalContent, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
| @ -349,23 +359,32 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             attachment: ContentAttachmentData, | ||||
|             rootThreadEventId: String?, | ||||
|             relatesTo: RelationDefaultContent?, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         return when (attachment.type) { | ||||
|             ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment, rootThreadEventId, relatesTo) | ||||
|             ContentAttachmentData.Type.VIDEO -> createVideoEvent(roomId, attachment, rootThreadEventId, relatesTo) | ||||
|             ContentAttachmentData.Type.AUDIO -> createAudioEvent(roomId, attachment, isVoiceMessage = false, rootThreadEventId = rootThreadEventId, relatesTo) | ||||
|             ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment, rootThreadEventId, relatesTo, additionalContent) | ||||
|             ContentAttachmentData.Type.VIDEO -> createVideoEvent(roomId, attachment, rootThreadEventId, relatesTo, additionalContent) | ||||
|             ContentAttachmentData.Type.AUDIO -> createAudioEvent( | ||||
|                     roomId, | ||||
|                     attachment, | ||||
|                     isVoiceMessage = false, | ||||
|                     rootThreadEventId = rootThreadEventId, | ||||
|                     relatesTo, | ||||
|                     additionalContent | ||||
|             ) | ||||
|             ContentAttachmentData.Type.VOICE_MESSAGE -> createAudioEvent( | ||||
|                     roomId, | ||||
|                     attachment, | ||||
|                     isVoiceMessage = true, | ||||
|                     rootThreadEventId = rootThreadEventId, | ||||
|                     relatesTo, | ||||
|                     additionalContent, | ||||
|             ) | ||||
|             ContentAttachmentData.Type.FILE -> createFileEvent(roomId, attachment, rootThreadEventId, relatesTo) | ||||
|             ContentAttachmentData.Type.FILE -> createFileEvent(roomId, attachment, rootThreadEventId, relatesTo, additionalContent) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun createReactionEvent(roomId: String, targetEventId: String, reaction: String): Event { | ||||
|     fun createReactionEvent(roomId: String, targetEventId: String, reaction: String, additionalContent: Content? = null): Event { | ||||
|         val content = ReactionContent( | ||||
|                 ReactionInfo( | ||||
|                         RelationType.ANNOTATION, | ||||
| @ -380,7 +399,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 senderId = userId, | ||||
|                 eventId = localId, | ||||
|                 type = EventType.REACTION, | ||||
|                 content = content.toContent(), | ||||
|                 content = content.toContent().plus(additionalContent.orEmpty()), | ||||
|                 unsignedData = UnsignedData(age = null, transactionId = localId) | ||||
|         ) | ||||
|     } | ||||
| @ -390,6 +409,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             attachment: ContentAttachmentData, | ||||
|             rootThreadEventId: String?, | ||||
|             relatesTo: RelationDefaultContent?, | ||||
|             additionalContent: Content?, | ||||
|     ): Event { | ||||
|         var width = attachment.width | ||||
|         var height = attachment.height | ||||
| @ -417,7 +437,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 url = attachment.queryUri.toString(), | ||||
|                 relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } | ||||
|         ) | ||||
|         return createMessageEvent(roomId, content) | ||||
|         return createMessageEvent(roomId, content, additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     private fun createVideoEvent( | ||||
| @ -425,6 +445,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             attachment: ContentAttachmentData, | ||||
|             rootThreadEventId: String?, | ||||
|             relatesTo: RelationDefaultContent?, | ||||
|             additionalContent: Content?, | ||||
|     ): Event { | ||||
|         val mediaDataRetriever = MediaMetadataRetriever() | ||||
|         mediaDataRetriever.setDataSource(context, attachment.queryUri) | ||||
| @ -459,7 +480,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 url = attachment.queryUri.toString(), | ||||
|                 relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } | ||||
|         ) | ||||
|         return createMessageEvent(roomId, content) | ||||
|         return createMessageEvent(roomId, content, additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     private fun createAudioEvent( | ||||
| @ -468,6 +489,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             isVoiceMessage: Boolean, | ||||
|             rootThreadEventId: String?, | ||||
|             relatesTo: RelationDefaultContent?, | ||||
|             additionalContent: Content? | ||||
|     ): Event { | ||||
|         val content = MessageAudioContent( | ||||
|                 msgType = MessageType.MSGTYPE_AUDIO, | ||||
| @ -485,7 +507,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 voiceMessageIndicator = if (!isVoiceMessage) null else emptyMap(), | ||||
|                 relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } | ||||
|         ) | ||||
|         return createMessageEvent(roomId, content) | ||||
|         return createMessageEvent(roomId, content, additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     private fun createFileEvent( | ||||
| @ -493,6 +515,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             attachment: ContentAttachmentData, | ||||
|             rootThreadEventId: String?, | ||||
|             relatesTo: RelationDefaultContent?, | ||||
|             additionalContent: Content? | ||||
|     ): Event { | ||||
|         val content = MessageFileContent( | ||||
|                 msgType = MessageType.MSGTYPE_FILE, | ||||
| @ -504,15 +527,16 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 url = attachment.queryUri.toString(), | ||||
|                 relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } | ||||
|         ) | ||||
|         return createMessageEvent(roomId, content) | ||||
|         return createMessageEvent(roomId, content, additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     private fun createMessageEvent(roomId: String, content: MessageContent? = null): Event { | ||||
|         return createEvent(roomId, EventType.MESSAGE, content.toContent()) | ||||
|     private fun createMessageEvent(roomId: String, content: MessageContent, additionalContent: Content?): Event { | ||||
|         return createEvent(roomId, EventType.MESSAGE, content.toContent(), additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     fun createEvent(roomId: String, type: String, content: Content?): Event { | ||||
|     fun createEvent(roomId: String, type: String, content: Content?, additionalContent: Content? = null): Event { | ||||
|         val newContent = enhanceStickerIfNeeded(type, content) ?: content | ||||
|         val updatedNewContent = newContent?.plus(additionalContent.orEmpty()) ?: additionalContent | ||||
|         val localId = LocalEcho.createLocalEchoId() | ||||
|         return Event( | ||||
|                 roomId = roomId, | ||||
| @ -520,7 +544,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 senderId = userId, | ||||
|                 eventId = localId, | ||||
|                 type = type, | ||||
|                 content = newContent, | ||||
|                 content = updatedNewContent, | ||||
|                 unsignedData = UnsignedData(age = null, transactionId = localId) | ||||
|         ) | ||||
|     } | ||||
| @ -555,6 +579,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             msgType: String, | ||||
|             autoMarkdown: Boolean, | ||||
|             formattedText: String?, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val content = formattedText?.let { TextContent(text.toString(), it) } ?: createTextContent(text, autoMarkdown) | ||||
|         return createEvent( | ||||
| @ -564,8 +589,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                         rootThreadEventId = rootThreadEventId, | ||||
|                         latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId), | ||||
|                         msgType = msgType | ||||
|                 ) | ||||
|                         .toContent() | ||||
|                 ).toContent().plus(additionalContent.orEmpty()) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
| @ -584,6 +608,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             autoMarkdown: Boolean, | ||||
|             rootThreadEventId: String? = null, | ||||
|             showInThread: Boolean, | ||||
|             additionalContent: Content? = null | ||||
|     ): Event? { | ||||
|         // Fallbacks and event representation | ||||
|         // TODO Add error/warning logs when any of this is null | ||||
| @ -621,7 +646,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                         showInThread = showInThread | ||||
|                 ) | ||||
|         ) | ||||
|         return createMessageEvent(roomId, content) | ||||
|         return createMessageEvent(roomId, content, additionalContent) | ||||
|     } | ||||
| 
 | ||||
|     private fun generateThreadRelationContent(rootThreadEventId: String) = | ||||
| @ -750,7 +775,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|         } | ||||
|     } | ||||
|      */ | ||||
|     fun createRedactEvent(roomId: String, eventId: String, reason: String?): Event { | ||||
|     fun createRedactEvent(roomId: String, eventId: String, reason: String?, additionalContent: Content? = null): Event { | ||||
|         val localId = LocalEcho.createLocalEchoId() | ||||
|         return Event( | ||||
|                 roomId = roomId, | ||||
| @ -759,7 +784,7 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                 eventId = localId, | ||||
|                 type = EventType.REDACTION, | ||||
|                 redacts = eventId, | ||||
|                 content = reason?.let { mapOf("reason" to it).toContent() }, | ||||
|                 content = reason?.let { mapOf("reason" to it).toContent().plus(additionalContent.orEmpty()) } ?: additionalContent, | ||||
|                 unsignedData = UnsignedData(age = null, transactionId = localId) | ||||
|         ) | ||||
|     } | ||||
| @ -776,9 +801,14 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|             formattedText: String?, | ||||
|             autoMarkdown: Boolean, | ||||
|             rootThreadEventId: String?, | ||||
|             additionalContent: Content? = null, | ||||
|     ): Event { | ||||
|         val messageContent = quotedEvent.getLastMessageContent() | ||||
|         val textMsg = if (messageContent is MessageContentWithFormattedBody) { messageContent.formattedBody } else { messageContent?.body } | ||||
|         val textMsg = if (messageContent is MessageContentWithFormattedBody) { | ||||
|             messageContent.formattedBody | ||||
|         } else { | ||||
|             messageContent?.body | ||||
|         } | ||||
|         val quoteText = legacyRiotQuoteText(textMsg, text) | ||||
|         val quoteFormattedText = "<blockquote>$textMsg</blockquote>$formattedText" | ||||
| 
 | ||||
| @ -791,13 +821,15 @@ internal class LocalEchoEventFactory @Inject constructor( | ||||
|                                     rootThreadEventId = rootThreadEventId, | ||||
|                                     latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId), | ||||
|                                     msgType = MessageType.MSGTYPE_TEXT | ||||
|                             ) | ||||
|                             ), | ||||
|                     additionalContent, | ||||
|             ) | ||||
|         } else { | ||||
|             createFormattedTextEvent( | ||||
|                     roomId, | ||||
|                     markdownParser.parse(quoteText, force = true, advanced = autoMarkdown).copy(formattedText = quoteFormattedText), | ||||
|                     MessageType.MSGTYPE_TEXT | ||||
|                     MessageType.MSGTYPE_TEXT, | ||||
|                     additionalContent, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -96,4 +96,8 @@ internal class DefaultTimelineService @AssistedInject constructor( | ||||
|     override fun getAttachmentMessages(): List<TimelineEvent> { | ||||
|         return timelineEventDataSource.getAttachmentMessages(roomId) | ||||
|     } | ||||
| 
 | ||||
|     override fun getTimelineEventsRelatedTo(relationType: String, eventId: String): List<TimelineEvent> { | ||||
|         return timelineEventDataSource.getTimelineEventsRelatedTo(roomId, relationType, eventId) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -19,8 +19,11 @@ package org.matrix.android.sdk.internal.session.room.timeline | ||||
| import androidx.lifecycle.LiveData | ||||
| import com.zhuinden.monarchy.Monarchy | ||||
| import io.realm.Sort | ||||
| import org.matrix.android.sdk.api.session.events.model.getRelationContent | ||||
| import org.matrix.android.sdk.api.session.events.model.isImageMessage | ||||
| import org.matrix.android.sdk.api.session.events.model.isVideoMessage | ||||
| import org.matrix.android.sdk.api.session.events.model.toModel | ||||
| import org.matrix.android.sdk.api.session.room.model.message.MessageContent | ||||
| import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent | ||||
| import org.matrix.android.sdk.api.util.Optional | ||||
| import org.matrix.android.sdk.internal.database.RealmSessionProvider | ||||
| @ -63,4 +66,24 @@ internal class TimelineEventDataSource @Inject constructor( | ||||
|                     .orEmpty() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun getTimelineEventsRelatedTo(roomId: String, eventType: String, eventId: String): List<TimelineEvent> { | ||||
|         // TODO Remove this trick and call relations API | ||||
|         // see https://spec.matrix.org/latest/client-server-api/#get_matrixclientv1roomsroomidrelationseventidreltypeeventtype | ||||
|         return realmSessionProvider.withRealm { realm -> | ||||
|             TimelineEventEntity.whereRoomId(realm, roomId) | ||||
|                     .sort(TimelineEventEntityFields.ROOT.ORIGIN_SERVER_TS, Sort.ASCENDING) | ||||
|                     .distinct(TimelineEventEntityFields.EVENT_ID) | ||||
|                     .findAll() | ||||
|                     .mapNotNull { | ||||
|                         timelineEventMapper.map(it) | ||||
|                                 .takeIf { | ||||
|                                     val isEventRelatedTo = it.root.getRelationContent()?.takeIf { it.type == eventType && it.eventId == eventId } != null | ||||
|                                     val isContentRelatedTo = it.root.getClearContent()?.toModel<MessageContent>() | ||||
|                                             ?.relatesTo?.takeIf { it.type == eventType && it.eventId == eventId } != null | ||||
|                                     isEventRelatedTo || isContentRelatedTo | ||||
|                                 } | ||||
|                     } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -71,10 +71,16 @@ internal class UpdateUserWorker(context: Context, params: WorkerParameters, sess | ||||
|                 ?.saveLocally() | ||||
|     } | ||||
| 
 | ||||
|     private suspend fun fetchUsers(userIdsToFetch: Collection<String>) = userIdsToFetch.mapNotNull { | ||||
|         tryOrNull { | ||||
|             val profileJson = getProfileInfoTask.execute(GetProfileInfoTask.Params(it)) | ||||
|             User.fromJson(it, profileJson) | ||||
|     private suspend fun fetchUsers(userIdsToFetch: Collection<String>): List<User> { | ||||
|         return userIdsToFetch.mapNotNull { userId -> | ||||
|             tryOrNull { | ||||
|                 val profileJson = getProfileInfoTask.execute(GetProfileInfoTask.Params( | ||||
|                         userId = userId, | ||||
|                         // Bulk insert later, so tell the task not to store the User. | ||||
|                         storeInDatabase = false, | ||||
|                 )) | ||||
|                 User.fromJson(userId, profileJson) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -66,6 +66,8 @@ internal class UserDataSource @Inject constructor( | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun getUserOrDefault(userId: String): User = getUser(userId) ?: User(userId) | ||||
| 
 | ||||
|     fun getUserLive(userId: String): LiveData<Optional<User>> { | ||||
|         val liveData = monarchy.findAllMappedWithChanges( | ||||
|                 { UserEntity.where(it, userId) }, | ||||
|  | ||||
| @ -20,7 +20,6 @@ import org.matrix.android.sdk.api.session.content.ContentUrlResolver | ||||
| import org.matrix.android.sdk.api.session.events.model.Event | ||||
| import org.matrix.android.sdk.api.session.events.model.toModel | ||||
| import org.matrix.android.sdk.api.session.room.sender.SenderInfo | ||||
| import org.matrix.android.sdk.api.session.user.model.User | ||||
| import org.matrix.android.sdk.api.session.widgets.model.Widget | ||||
| import org.matrix.android.sdk.api.session.widgets.model.WidgetContent | ||||
| import org.matrix.android.sdk.api.session.widgets.model.WidgetType | ||||
| @ -74,7 +73,7 @@ internal class WidgetFactory @Inject constructor( | ||||
|     // Ref: https://github.com/matrix-org/matrix-widget-api/blob/master/src/templating/url-template.ts#L29-L33 | ||||
|     fun computeURL(widget: Widget, isLightTheme: Boolean): String? { | ||||
|         var computedUrl = widget.widgetContent.url ?: return null | ||||
|         val myUser = userDataSource.getUser(userId) ?: User(userId) | ||||
|         val myUser = userDataSource.getUserOrDefault(userId) | ||||
| 
 | ||||
|         val keyValue = widget.widgetContent.data.mapKeys { "\$${it.key}" }.toMutableMap() | ||||
| 
 | ||||
|  | ||||
| @ -81,6 +81,7 @@ const allowList = [ | ||||
|     "Florian14", | ||||
|     "ganfra", | ||||
|     "jmartinesp", | ||||
|     "jonnyandrew", | ||||
|     "langleyd", | ||||
|     "MadLittleMods", | ||||
|     "manuroe", | ||||
|  | ||||
| @ -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 = 4 | ||||
| ext.versionPatch = 6 | ||||
| 
 | ||||
| static def getGitTimestamp() { | ||||
|     def cmd = 'git show -s --format=%ct' | ||||
|  | ||||
| @ -0,0 +1,44 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022 New Vector Ltd | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package im.vector.app.espresso.tools | ||||
| 
 | ||||
| import android.view.View | ||||
| import androidx.test.espresso.PerformException | ||||
| import androidx.test.espresso.UiController | ||||
| import androidx.test.espresso.ViewAction | ||||
| import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom | ||||
| import androidx.test.espresso.matcher.ViewMatchers.isDisplayed | ||||
| import com.google.android.material.tabs.TabLayout | ||||
| import org.hamcrest.Matchers.allOf | ||||
| 
 | ||||
| fun selectTabAtPosition(tabIndex: Int): ViewAction { | ||||
|     return object : ViewAction { | ||||
|         override fun getDescription() = "with tab at index $tabIndex" | ||||
| 
 | ||||
|         override fun getConstraints() = allOf(isDisplayed(), isAssignableFrom(TabLayout::class.java)) | ||||
| 
 | ||||
|         override fun perform(uiController: UiController, view: View) { | ||||
|             val tabLayout = view as TabLayout | ||||
|             val tabAtIndex: TabLayout.Tab = tabLayout.getTabAt(tabIndex) | ||||
|                     ?: throw PerformException.Builder() | ||||
|                             .withCause(Throwable("No tab at index $tabIndex")) | ||||
|                             .build() | ||||
| 
 | ||||
|             tabAtIndex.select() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -135,6 +135,14 @@ class UiAllScreensSanityTest { | ||||
| 
 | ||||
|         elementRobot.space { selectSpace(spaceName) } | ||||
| 
 | ||||
|         elementRobot.layoutPreferences { | ||||
|             crawl() | ||||
|         } | ||||
| 
 | ||||
|         elementRobot.roomList { | ||||
|             crawlTabs() | ||||
|         } | ||||
| 
 | ||||
|         elementRobot.withDeveloperMode { | ||||
|             settings { | ||||
|                 advancedSettings { crawlDeveloperOptions() } | ||||
|  | ||||
| @ -17,8 +17,10 @@ | ||||
| package im.vector.app.ui.robot | ||||
| 
 | ||||
| import android.view.View | ||||
| import androidx.test.core.app.ApplicationProvider | ||||
| import androidx.test.espresso.Espresso.closeSoftKeyboard | ||||
| import androidx.test.espresso.Espresso.onView | ||||
| import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu | ||||
| import androidx.test.espresso.Espresso.pressBack | ||||
| import androidx.test.espresso.action.ViewActions | ||||
| import androidx.test.espresso.action.ViewActions.click | ||||
| @ -94,6 +96,18 @@ class ElementRobot( | ||||
|         waitUntilViewVisible(withId(R.id.roomListContainer)) | ||||
|     } | ||||
| 
 | ||||
|     fun layoutPreferences(block: LayoutPreferencesRobot.() -> Unit) { | ||||
|         openActionBarOverflowOrOptionsMenu( | ||||
|                 ApplicationProvider.getApplicationContext() | ||||
|         ) | ||||
|         clickOn(R.string.home_layout_preferences) | ||||
|         waitUntilDialogVisible(withId(R.id.home_layout_settings_recents)) | ||||
| 
 | ||||
|         block(LayoutPreferencesRobot()) | ||||
| 
 | ||||
|         pressBack() | ||||
|     } | ||||
| 
 | ||||
|     fun newDirectMessage(block: NewDirectMessageRobot.() -> Unit) { | ||||
|         if (labsPreferences.isNewAppLayoutEnabled) { | ||||
|             clickOn(R.id.newLayoutCreateChatButton) | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user