Merge tag 'v1.5.10' into merge-v1.5.10
TODO: re-implement our composer constraint changes Conflicts: matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/DefaultReadService.kt matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/read/SetReadMarkersTask.kt matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt vector/src/main/AndroidManifest.xml vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerAction.kt vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt vector/src/main/java/im/vector/app/features/home/room/detail/composer/PlainTextComposerLayout.kt vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageViews.kt vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/CheckIfCanReplyEventUseCase.kt vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/ReadReceiptsItemFactory.kt vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt vector/src/main/res/drawable/ic_voice_mic_recording.xml vector/src/main/res/layout/composer_layout.xml vector/src/main/res/layout/composer_layout_constraint_set_compact.xml vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml vector/src/main/res/layout/composer_rich_text_layout_constraint_set_compact.xml vector/src/main/res/layout/composer_rich_text_layout_constraint_set_expanded.xml vector/src/main/res/layout/composer_rich_text_layout_constraint_set_fullscreen.xml vector/src/main/res/layout/fragment_timeline.xml vector/src/main/res/layout/view_voice_message_recorder.xml vector/src/main/res/xml/vector_settings_preferences.xml vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt Change-Id: I55e95d86b4bb019544d75dcb653afe05194cd224
This commit is contained in:
commit
65be0039a5
|
@ -10,7 +10,6 @@ body:
|
|||
id: checklist
|
||||
attributes:
|
||||
label: Release checklist
|
||||
description: For the template example, we are releasing the version 1.2.3. Replace 1.2.3 with the version in the issue body.
|
||||
placeholder: |
|
||||
If you are reading this, you have deleted the content of the release template: undo the deletion or start again.
|
||||
value: |
|
||||
|
@ -24,27 +23,7 @@ body:
|
|||
|
||||
### Do the release
|
||||
|
||||
- [ ] Make sure `develop` and `main` are up to date and create a release with gitflow: `git checkout main; git pull; git checkout develop; git pull; git flow release start '1.2.3'`
|
||||
- [ ] Check the crashes from the PlayStore
|
||||
- [ ] Check the rageshake with the current dev version: https://github.com/matrix-org/element-android-rageshakes/labels/1.2.3-dev
|
||||
- [ ] 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 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.
|
||||
- [ ] Finish release with gitflow, delete the draft PR (if created): `git flow release finish '1.2.3'`
|
||||
- [ ] Push `main` and the new tag `v1.2.3` to origin: `git push origin main; git push origin 'v1.2.3'`
|
||||
- [ ] Checkout `develop`: `git checkout develop`
|
||||
- [ ] Increase version (versionPatch + 2) in `./vector/build.gradle`
|
||||
- [ ] Change the value of SDK_VERSION in the file `./matrix-sdk-android/build.gradle`
|
||||
- [ ] Commit and push `develop`: `git commit -m 'version++'; git push origin develop`
|
||||
- [ ] Wait for [Buildkite](https://buildkite.com/matrix-dot-org/element-android/builds?branch=main) to build the `main` branch.
|
||||
- [ ] Run the script `~/scripts/releaseElement.sh`. It will download the APKs from Buildkite check them and sign them.
|
||||
- [ ] Install the APK on your phone to check that the upgrade went well (no init sync, etc.)
|
||||
- [ ] Create the release on gitHub [from the tag](https://github.com/vector-im/element-android/tags), copy paste the block from the file CHANGES.md
|
||||
- [ ] Add the 4 signed APKs to the GitHub release
|
||||
- [ ] Ping the Android Internal room
|
||||
- [ ] Run the script ./tools/release/releaseScript.sh and follow the steps.
|
||||
|
||||
### Once tested and validated internally
|
||||
|
||||
|
@ -81,29 +60,9 @@ body:
|
|||
|
||||
The SDK2 and the sample app are released only when Element has been pushed to production.
|
||||
|
||||
- [ ] Checkout the `main` branch on Element Android project
|
||||
- [ ] On the [SDK2 project](https://github.com/matrix-org/matrix-android-sdk2), run the script ./tools/releaseScript.sh and follow the instructions.
|
||||
|
||||
#### On the SDK2 project
|
||||
|
||||
https://github.com/matrix-org/matrix-android-sdk2
|
||||
|
||||
- [ ] Create a release with GitFlow
|
||||
- [ ] Update the value of VERSION_NAME in the file gradle.properties
|
||||
- [ ] Update the files `./build.gradle` and `./gradle/gradle-wrapper.properties` manually, to use the latest version for the dependency. You can get inspired by the same files on Element Android project.
|
||||
- [ ] Run the script `./tools/import_from_element.sh`
|
||||
- [ ] Check the diff in the file `./matrix-sdk-android/build.gradle` and restore what may have been erased (in particular the line `apply plugin: "com.vanniktech.maven.publish"` and the line about the version)
|
||||
- [ ] Let the script finish to build the library
|
||||
- [ ] Update the file `CHANGES.md`
|
||||
- [ ] Finish the release using GitFlow
|
||||
- [ ] Push the branch `main`, the new tag and the branch `develop` to origin
|
||||
|
||||
##### Release on MavenCentral
|
||||
|
||||
- [ ] Checkout the branch `main`
|
||||
- [ ] Run the command `./gradlew publish --no-daemon --no-parallel`. You'll need some non-public element to do so
|
||||
- [ ] Run the command `./gradlew closeAndReleaseRepository`. If it is working well, you can jump directly to the final step of this section.
|
||||
|
||||
If `./gradlew closeAndReleaseRepository` fails (for instance, several repositories are waiting to be handled), you have to close and release the repository manually. Do the following steps:
|
||||
Note: if the step `./gradlew closeAndReleaseRepository` fails (for instance, several repositories are waiting to be handled), you have to close and release the repository manually. Do the following steps:
|
||||
|
||||
- [ ] Connect to https://s01.oss.sonatype.org
|
||||
- [ ] Click on Staging Repositories and check the the files have been uploaded
|
||||
|
@ -111,15 +70,6 @@ body:
|
|||
- [ ] Wait (check Activity tab until step "Repository closed" is displayed)
|
||||
- [ ] Click on release. The staging repository will disappear
|
||||
|
||||
Final step
|
||||
|
||||
- [ ] Check that the release is available in https://repo1.maven.org/maven2/org/matrix/android/matrix-android-sdk2/ (it can take a few minutes)
|
||||
|
||||
##### Release on GitHub
|
||||
|
||||
- [ ] Create the release on GitHub from [the tag](https://github.com/matrix-org/matrix-android-sdk2/tags)
|
||||
- [ ] Upload the AAR on the GitHub release
|
||||
|
||||
### Android SDK2 sample
|
||||
|
||||
https://github.com/matrix-org/matrix-android-sdk2-sample
|
||||
|
|
|
@ -16,7 +16,7 @@ env:
|
|||
jobs:
|
||||
|
||||
# More info on should-i-run:
|
||||
# If this fails to run (the IF doesn't complete) then the needs will not be satisfied for any of the
|
||||
# If this fails to run (the IF doesn't complete) then the needs will not be satisfied for any of the
|
||||
# other jobs below, so none will run.
|
||||
# except for the notification job at the bottom which will run all the time, unless should-i-run isn't
|
||||
# successful, or all the other jobs have succeeded
|
||||
|
@ -27,11 +27,12 @@ jobs:
|
|||
if: github.event.pull_request.merged # Additionally require PR to have been completely merged.
|
||||
steps:
|
||||
- run: echo "Run those tests!" # no-op success
|
||||
|
||||
|
||||
ui-tests:
|
||||
name: UI Tests (Synapse)
|
||||
needs: should-i-run
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
timeout-minutes: 90 # We might need to increase it if the time for tests grows
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
|
@ -14,6 +14,7 @@ jobs:
|
|||
tests:
|
||||
name: Runs all tests
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
timeout-minutes: 90 # We might need to increase it if the time for tests grows
|
||||
strategy:
|
||||
matrix:
|
||||
api-level: [28]
|
||||
|
@ -126,26 +127,26 @@ jobs:
|
|||
# Unneeded as part of the test suite above, kept around in case we want to re-enable them.
|
||||
#
|
||||
# # Build Android Tests
|
||||
# build-android-tests:
|
||||
# name: Build Android Tests
|
||||
# runs-on: ubuntu-latest
|
||||
# build-android-tests:
|
||||
# name: Build Android Tests
|
||||
# runs-on: ubuntu-latest
|
||||
# concurrency:
|
||||
# group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('build-android-tests-{0}', github.ref) }}
|
||||
# cancel-in-progress: true
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: actions/setup-java@v3
|
||||
# with:
|
||||
# distribution: 'adopt'
|
||||
# java-version: 11
|
||||
# - uses: actions/cache@v3
|
||||
# with:
|
||||
# path: |
|
||||
# ~/.gradle/caches
|
||||
# ~/.gradle/wrapper
|
||||
# key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-gradle-
|
||||
# - name: Build Android Tests
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: actions/setup-java@v3
|
||||
# with:
|
||||
# distribution: 'adopt'
|
||||
# java-version: 11
|
||||
# - uses: actions/cache@v3
|
||||
# with:
|
||||
# path: |
|
||||
# ~/.gradle/caches
|
||||
# ~/.gradle/wrapper
|
||||
# key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-gradle-
|
||||
# - name: Build Android Tests
|
||||
# run: ./gradlew clean assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES
|
||||
|
||||
|
|
|
@ -79,8 +79,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -129,8 +129,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +154,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -178,8 +178,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -203,8 +203,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -228,8 +228,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
@ -258,8 +258,8 @@ jobs:
|
|||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[Rich text editor] Fix design and spacing of rich text editor
|
36
CHANGES.md
36
CHANGES.md
|
@ -1,3 +1,39 @@
|
|||
Changes in Element v1.5.10 (2022-11-30)
|
||||
=======================================
|
||||
|
||||
Features ✨
|
||||
----------
|
||||
- Add setting to allow disabling direct share ([#2725](https://github.com/vector-im/element-android/issues/2725))
|
||||
- [Device Manager] Toggle IP address visibility ([#7546](https://github.com/vector-im/element-android/issues/7546))
|
||||
- New implementation of the full screen mode for the Rich Text Editor. ([#7577](https://github.com/vector-im/element-android/issues/7577))
|
||||
|
||||
Bugfixes 🐛
|
||||
----------
|
||||
- Fix italic text is truncated when bubble mode and markdown is enabled ([#5679](https://github.com/vector-im/element-android/issues/5679))
|
||||
- Missing translations on "replyTo" messages ([#7555](https://github.com/vector-im/element-android/issues/7555))
|
||||
- ANR on session start when sending client info is enabled ([#7604](https://github.com/vector-im/element-android/issues/7604))
|
||||
- Make the plain text mode layout of the RTE more compact. ([#7620](https://github.com/vector-im/element-android/issues/7620))
|
||||
- Push notification for thread message is now shown correctly when user observes rooms main timeline ([#7634](https://github.com/vector-im/element-android/issues/7634))
|
||||
- Voice Broadcast - Fix playback stuck in buffering mode ([#7646](https://github.com/vector-im/element-android/issues/7646))
|
||||
|
||||
In development 🚧
|
||||
----------------
|
||||
- Voice Broadcast - Handle redaction of the state events on the listener and recorder sides ([#7629](https://github.com/vector-im/element-android/issues/7629))
|
||||
- Voice Broadcast - Update the buffering display in the timeline ([#7655](https://github.com/vector-im/element-android/issues/7655))
|
||||
- Voice Broadcast - Remove voice messages related to a VB from the room attachments ([#7656](https://github.com/vector-im/element-android/issues/7656))
|
||||
|
||||
SDK API changes ⚠️
|
||||
------------------
|
||||
- Added support for read receipts in threads. Now user in a room can have multiple read receipts (one per thread + one in main thread + one without threadId) ([#6996](https://github.com/vector-im/element-android/issues/6996))
|
||||
- Sync Filter now taking in account homeserver capabilities to not pass unsupported parameters.
|
||||
Sync Filter is now configured by providing SyncFilterBuilder class instance, instead of Filter to identify Filter changes related to homeserver capabilities ([#7626](https://github.com/vector-im/element-android/issues/7626))
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
- Remove usage of Buildkite. ([#7583](https://github.com/vector-im/element-android/issues/7583))
|
||||
- Better validation of edits ([#7594](https://github.com/vector-im/element-android/issues/7594))
|
||||
|
||||
|
||||
Changes in Element v1.5.8 (2022-11-17)
|
||||
======================================
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* [Code quality](#code-quality)
|
||||
* [Internal tool](#internal-tool)
|
||||
* [ktlint](#ktlint)
|
||||
* [knit](#knit)
|
||||
* [lint](#lint)
|
||||
* [Unit tests](#unit-tests)
|
||||
* [Tests](#tests)
|
||||
|
@ -126,6 +127,23 @@ Note that you can run
|
|||
|
||||
For ktlint to fix some detected errors for you (you still have to check and commit the fix of course)
|
||||
|
||||
#### knit
|
||||
|
||||
[knit](https://github.com/Kotlin/kotlinx-knit) is a tool which checks markdown files on the project. Also it generates/updates the table of content (toc) of the markdown files.
|
||||
|
||||
So everytime the toc should be updated, just run
|
||||
<pre>
|
||||
./gradlew knit
|
||||
</pre>
|
||||
|
||||
and commit the changes.
|
||||
|
||||
The CI will check that markdown files are up to date by running
|
||||
|
||||
<pre>
|
||||
./gradlew knitCheck
|
||||
</pre>
|
||||
|
||||
#### lint
|
||||
|
||||
<pre>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[![Buildkite](https://badge.buildkite.com/ad0065c1b70f557cd3b1d3d68f9c2154010f83c4d6f71706a9.svg?branch=develop)](https://buildkite.com/matrix-dot-org/element-android/builds?branch=develop)
|
||||
[![Latest build](https://github.com/vector-im/element-android/actions/workflows/build.yml/badge.svg?query=branch%3Adevelop)](https://github.com/vector-im/element-android/actions/workflows/build.yml?query=branch%3Adevelop)
|
||||
[![Weblate](https://translate.element.io/widgets/element-android/-/svg-badge.svg)](https://translate.element.io/engage/element-android/?utm_source=widget)
|
||||
[![Element Android Matrix room #element-android:matrix.org](https://img.shields.io/matrix/element-android:matrix.org.svg?label=%23element-android:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#element-android:matrix.org)
|
||||
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vector-im_element-android&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vector-im_element-android)
|
||||
|
@ -14,7 +14,7 @@ It is a total rewrite of [Riot-Android](https://github.com/vector-im/riot-androi
|
|||
[<img src="resources/img/google-play-badge.png" alt="Get it on Google Play" height="60">](https://play.google.com/store/apps/details?id=im.vector.app)
|
||||
[<img src="resources/img/f-droid-badge.png" alt="Get it on F-Droid" height="60">](https://f-droid.org/app/im.vector.app)
|
||||
|
||||
Nightly build: [![Buildkite](https://badge.buildkite.com/ad0065c1b70f557cd3b1d3d68f9c2154010f83c4d6f71706a9.svg?branch=develop)](https://buildkite.com/matrix-dot-org/element-android/builds?branch=develop) Nightly test status: [![allScreensTest](https://github.com/vector-im/element-android/actions/workflows/nightly.yml/badge.svg)](https://github.com/vector-im/element-android/actions/workflows/nightly.yml)
|
||||
Build of develop branch: [![GitHub Action](https://github.com/vector-im/element-android/actions/workflows/build.yml/badge.svg?query=branch%3Adevelop)](https://github.com/vector-im/element-android/actions/workflows/build.yml?query=branch%3Adevelop) Nightly test status: [![allScreensTest](https://github.com/vector-im/element-android/actions/workflows/nightly.yml/badge.svg)](https://github.com/vector-im/element-android/actions/workflows/nightly.yml)
|
||||
|
||||
|
||||
# New Android SDK
|
||||
|
@ -40,7 +40,7 @@ If you would like to receive releases more quickly (bearing in mind that they ma
|
|||
|
||||
1. [Sign up to receive beta releases](https://play.google.com/apps/testing/im.vector.app) via the Google Play Store.
|
||||
2. Install a [release APK](https://github.com/vector-im/element-android/releases) directly - download the relevant .apk file and allow installing from untrusted sources in your device settings. Note: these releases are the Google Play version, which depend on some Google services. If you prefer to avoid that, try the latest dev builds, and choose the F-Droid version.
|
||||
3. If you're really brave, install the [very latest dev build](https://buildkite.com/matrix-dot-org/element-android/builds/latest?branch=develop&state=passed) - click on *Assemble (GPlay or FDroid) Debug version* then on *Artifacts*.
|
||||
3. If you're really brave, install the [very latest dev build](https://github.com/vector-im/element-android/actions/workflows/build.yml?query=branch%3Adevelop) - pick a build, then click on `Summary` to download the APKs from there: `vector-Fdroid-debug` and `vector-Gplay-debug` contains the APK for the desired store. Each file contains 5 APKs. 4 APKs for every supported specific architecture of device. In doubt you can install the `universal` APK.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ buildscript {
|
|||
classpath libs.gradle.gradlePlugin
|
||||
classpath libs.gradle.kotlinPlugin
|
||||
classpath libs.gradle.hiltPlugin
|
||||
classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.3'
|
||||
classpath 'com.google.firebase:firebase-appdistribution-gradle:3.1.1'
|
||||
classpath 'com.google.gms:google-services:4.3.14'
|
||||
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730'
|
||||
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5'
|
||||
|
@ -43,12 +43,12 @@ plugins {
|
|||
// ktlint Plugin
|
||||
id "org.jlleitschuh.gradle.ktlint" version "11.0.0"
|
||||
// Detekt
|
||||
id "io.gitlab.arturbosch.detekt" version "1.21.0"
|
||||
id "io.gitlab.arturbosch.detekt" version "1.22.0"
|
||||
// Ksp
|
||||
id "com.google.devtools.ksp" version "1.7.21-1.0.8"
|
||||
|
||||
// Dependency Analysis
|
||||
id 'com.autonomousapps.dependency-analysis' version "1.13.1"
|
||||
id 'com.autonomousapps.dependency-analysis' version "1.16.0"
|
||||
// Gradle doctor
|
||||
id "com.osacky.doctor" version "0.8.1"
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ def gradle = "7.3.1"
|
|||
// Ref: https://kotlinlang.org/releases.html
|
||||
def kotlin = "1.7.21"
|
||||
def kotlinCoroutines = "1.6.4"
|
||||
def dagger = "2.44"
|
||||
def dagger = "2.44.2"
|
||||
def appDistribution = "16.0.0-beta05"
|
||||
def retrofit = "2.9.0"
|
||||
def markwon = "4.6.2"
|
||||
|
@ -84,7 +84,7 @@ ext.libs = [
|
|||
//'appdistributionApi' : "com.google.firebase:firebase-appdistribution-api-ktx:$appDistribution",
|
||||
//'appdistribution' : "com.google.firebase:firebase-appdistribution:$appDistribution",
|
||||
// Phone number https://github.com/google/libphonenumber
|
||||
'phonenumber' : "com.googlecode.libphonenumber:libphonenumber:8.13.0"
|
||||
'phonenumber' : "com.googlecode.libphonenumber:libphonenumber:8.13.1"
|
||||
],
|
||||
dagger : [
|
||||
'dagger' : "com.google.dagger:dagger:$dagger",
|
||||
|
@ -99,7 +99,7 @@ ext.libs = [
|
|||
],
|
||||
element : [
|
||||
'opusencoder' : "io.element.android:opusencoder:1.1.0",
|
||||
'wysiwyg' : "io.element.android:wysiwyg:0.4.0"
|
||||
'wysiwyg' : "io.element.android:wysiwyg:0.7.0.1"
|
||||
],
|
||||
squareup : [
|
||||
'moshi' : "com.squareup.moshi:moshi:$moshi",
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
## Installing from CI
|
||||
|
||||
<!--- TOC -->
|
||||
|
||||
* [Installing from Buildkite](#installing-from-buildkite)
|
||||
* [Installing from GitHub](#installing-from-github)
|
||||
* [Create a GitHub token](#create-a-github-token)
|
||||
* [Provide artifact URL](#provide-artifact-url)
|
||||
* [Next steps](#next-steps)
|
||||
* [Future improvement](#future-improvement)
|
||||
|
||||
<!--- END -->
|
||||
|
||||
Installing APK build by the CI is possible
|
||||
|
||||
### Installing from Buildkite
|
||||
|
||||
The script `./tools/install/installFromBuildkite.sh` can be used, but Builkite will be removed soon. See next section.
|
||||
|
||||
### Installing from GitHub
|
||||
|
||||
To install an APK built by a GitHub action, run the script `./tools/install/installFromGitHub.sh`. You will need to pass a GitHub token to do so.
|
||||
|
||||
#### Create a GitHub token
|
||||
|
||||
You can create a GitHub token going to your Github account, at this page: [https://github.com/settings/tokens](https://github.com/settings/tokens).
|
||||
|
||||
You need to create a token (classic) with the scope `repo/public_repo`. So just check the corresponding checkbox.
|
||||
Validity can be long since the scope of this token is limited. You will still be able to delete the token and generate a new one.
|
||||
Click on Generate token and save the token locally.
|
||||
|
||||
### Provide artifact URL
|
||||
|
||||
The script will ask for an artifact URL. You can get this artifact URL by following these steps:
|
||||
|
||||
- open the pull request
|
||||
- in the check at the bottom, click on `APK Build / Build debug APKs`
|
||||
- click on `Summary`
|
||||
- scroll to the bottom of the page
|
||||
- copy the link `vector-Fdroid-debug` if you want the F-Droid variant or `vector-Gplay-debug` if you want the Gplay variant.
|
||||
|
||||
The copied link can be provided to the script.
|
||||
|
||||
### Next steps
|
||||
|
||||
The script will download the artifact, unzip it and install the correct version (regarding arch) on your device.
|
||||
|
||||
Files will be added to the folder `./tmp/DebugApks`. Feel free to cleanup this folder from time to time, the script will not delete files.
|
||||
|
||||
### Future improvement
|
||||
|
||||
The script could ask the user for a Pull Request number and Gplay/Fdroid choice like it was done with Buildkite script. Using GitHub API may be possible to do that.
|
|
@ -0,0 +1,2 @@
|
|||
Hlavní změny v této verzi: opravy různých chyb a vylepšení.
|
||||
Úplný seznam změn: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Die wichtigsten Änderungen in dieser Version: Fehlerbehebungen und Verbesserungen.
|
||||
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Main changes in this version: New implementation of the full screen mode for the Rich Text Editor and bugfixes.
|
||||
Full changelog: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Põhilised muutused selles versioonis: erinevate vigade parandused ja kohendused.
|
||||
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
تغییرات عمده در این نگارش: رفع اشکالها و بهبود.
|
||||
گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Principaux changements pour cette version : corrections de bugs et améliorations.
|
||||
Intégralité des changements : https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Perubahan utama dalam versi ini: perbaikan kutu dan fitur
|
||||
Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Modifiche principali in questa versione: nuova interfaccia utente per selezionare un allegato!
|
||||
Cronologia completa: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Modifiche principali in questa versione: nuova interfaccia utente per selezionare un allegato.
|
||||
Cronologia completa: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Modifiche principali in questa versione: correzione di errori e miglioramenti.
|
||||
Cronologia completa: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Principais mudanças nesta versão: consertos de bugs e melhorias.
|
||||
Changelog completo: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: Использование UnifiedPush и разрешение пользователям получать push-оповещения без FCM.
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: Исправления различных багов и улучшения стабильности работы.
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: Исправления различных багов и улучшения стабильности работы.
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: Улучшены вход и регистрация
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: Улучшены вход и регистрация
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: Исправления различных багов и улучшения стабильности работы
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: отложённые личные сообщения включены по умолчанию
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: новый интерфейс для выбора прикреплённых файлов
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Основные изменения в этой версии: новый интерфейс для выбора прикреплённых файлов
|
||||
Полный список изменений: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Hlavné zmeny v tejto verzii: opravy chýb a vylepšenia.
|
||||
Úplný zoznam zmien: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Huvudsakliga ändringar i den här versionen: nytt gränssnitt för val av bilaga.
|
||||
Full ändringslogg: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
Huvudsakliga ändringar i den här versionen: nytt gränssnitt för val av bilaga.
|
||||
Full ändringslogg: https://github.com/vector-im/element-android/releases
|
|
@ -1,2 +1,2 @@
|
|||
Основні зміни в цій версії: Нові можливості в налаштуваннях лабораторії: Текстовий редактор, нове керування пристроями, голосові повідомлення. Досі в активній розробці!
|
||||
Основні зміни в цій версії: Нові можливості в налаштуваннях лабораторії: Текстовий редактор, нове керування пристроями, голосові трансляції. Досі в активній розробці!
|
||||
Список усіх змін: https://github.com/vector-im/element-android/releases
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Основні зміни в цій версії: усування вад і вдосконалення.
|
||||
Перелік усіх змін: https://github.com/vector-im/element-android/releases
|
|
@ -0,0 +1,2 @@
|
|||
此版本中的主要變動:臭蟲修復與改善。
|
||||
完整的變更紀錄:https://github.com/vector-im/element-android/releases
|
|
@ -2837,4 +2837,6 @@
|
|||
<string name="attachment_type_selector_sticker">Adhesius</string>
|
||||
<string name="attachment_type_selector_gallery">Galeria</string>
|
||||
<string name="attachment_type_selector_text_formatting">Format de text</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Enrere 30 segons</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Avança 30 segons</string>
|
||||
</resources>
|
|
@ -2899,4 +2899,27 @@
|
|||
<string name="error_voice_broadcast_unauthorized_title">Nelze zahájit nové hlasové vysílání</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Přetočení o 30 sekund zpět</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Přetočení o 30 sekund dopředu</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Ověřené relace jsou všude tam, kde tento účet používáte po zadání přístupové fráze nebo po potvrzení své totožnosti jinou ověřenou relací.
|
||||
\n
|
||||
\nTo znamená, že máte všechny klíče potřebné k odemknutí zašifrovaných zpráv a potvrzení ostatním uživatelům, že této relaci důvěřujete.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Odhlásit se z %1$d relace</item>
|
||||
<item quantity="few">Odhlásit se ze %1$d relací</item>
|
||||
<item quantity="other">Odhlásit se z %1$d relací</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Odhlásit se</string>
|
||||
<string name="voice_broadcast_recording_time_left">zbývá %1$s</string>
|
||||
<string name="message_reply_to_sender_created_poll">vytvořil hlasování.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">poslal nálepku.</string>
|
||||
<string name="message_reply_to_sender_sent_video">poslal video.</string>
|
||||
<string name="message_reply_to_sender_sent_image">poslal obrázek.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">poslal hlasovou zprávu.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">poslal zvukový soubor.</string>
|
||||
<string name="message_reply_to_sender_sent_file">odeslal soubor.</string>
|
||||
<string name="message_reply_to_prefix">V odpovědi na</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Skrýt IP adresu</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Zobrazit IP adresu</string>
|
||||
<string name="quoting">Citace</string>
|
||||
<string name="replying_to">Odpovídám na %s</string>
|
||||
<string name="editing">Úpravy</string>
|
||||
</resources>
|
|
@ -2232,13 +2232,13 @@
|
|||
<item quantity="other">%1$s weitere Optionen benötigt</item>
|
||||
</plurals>
|
||||
<string name="create_poll_empty_question_error">Frage darf nicht leer sein</string>
|
||||
<string name="create_poll_button">ABSTIMMUNG ERSTELLEN</string>
|
||||
<string name="create_poll_button">Umfrage erstellen</string>
|
||||
<string name="create_poll_add_option">NEUE OPTION</string>
|
||||
<string name="create_poll_options_hint">Option %1$d</string>
|
||||
<string name="create_poll_options_title">Optionen hinzufügen</string>
|
||||
<string name="create_poll_question_hint">Frage oder Thema</string>
|
||||
<string name="create_poll_question_title">Abstimmungsthema oder Frage</string>
|
||||
<string name="create_poll_title">Abstimmung erstellen</string>
|
||||
<string name="create_poll_title">Umfrage erstellen</string>
|
||||
<string name="attachment_type_poll">Umfrage</string>
|
||||
<string name="open_discovery_settings">Auffindungseinstellungen öffnen</string>
|
||||
<string name="shortcut_disabled_reason_sign_out">Sitzung abgemeldet!</string>
|
||||
|
@ -2306,21 +2306,21 @@
|
|||
<string name="legals_identity_server_title">Richtlinie deines Identitäts-Servers</string>
|
||||
<string name="legals_home_server_title">Richtlinie deines Heim-Servers</string>
|
||||
<string name="legals_application_title">Richtlinie von ${app_name}</string>
|
||||
<string name="tooltip_attachment_poll">Abstimmung erstellen</string>
|
||||
<string name="tooltip_attachment_poll">Umfrage erstellen</string>
|
||||
<string name="tooltip_attachment_contact">Kontakte öffnen</string>
|
||||
<string name="tooltip_attachment_sticker">Sticker verschicken</string>
|
||||
<string name="tooltip_attachment_file">Datei hochladen</string>
|
||||
<string name="tooltip_attachment_gallery">Verschicke Fotos und Videos</string>
|
||||
<string name="tooltip_attachment_photo">Kamera öffnen</string>
|
||||
<string name="delete_poll_dialog_content">Willst du diese Abstimmung wirklich entfernen\? Du wirst sie nicht wiederherstellen können.</string>
|
||||
<string name="delete_poll_dialog_title">Abstimmung entfernen</string>
|
||||
<string name="poll_end_room_list_preview">Abstimmung beendet</string>
|
||||
<string name="delete_poll_dialog_content">Willst du diese Umfrage wirklich entfernen\? Du wirst sie nicht wiederherstellen können.</string>
|
||||
<string name="delete_poll_dialog_title">Umfrage entfernen</string>
|
||||
<string name="poll_end_room_list_preview">Umfrage beendet</string>
|
||||
<string name="poll_response_room_list_preview">Stimme abgegeben</string>
|
||||
<string name="end_poll_confirmation_approve_button">Abstimmung beenden</string>
|
||||
<string name="end_poll_confirmation_approve_button">Umfrage beenden</string>
|
||||
<string name="end_poll_confirmation_description">Dies verhindert, dass andere Personen abstimmen können, und zeigt die Endergebnisse der Umfrage an.</string>
|
||||
<string name="end_poll_confirmation_title">Diese Abstimmung beenden\?</string>
|
||||
<string name="end_poll_confirmation_title">Diese Umfrage beenden\?</string>
|
||||
<string name="a11y_poll_winner_option">Gewinneroption</string>
|
||||
<string name="poll_end_action">Abstimmung beenden</string>
|
||||
<string name="poll_end_action">Umfrage beenden</string>
|
||||
<plurals name="poll_total_vote_count_after_ended">
|
||||
<item quantity="one">Endgültiges Ergebnis basiert auf %1$d Stimme</item>
|
||||
<item quantity="other">Endgültiges Ergebnis basiert auf %1$d Stimmen</item>
|
||||
|
@ -2333,11 +2333,11 @@
|
|||
<string name="location_not_available_dialog_title">${app_name} konnte nicht auf deinen Standort zugreifen</string>
|
||||
<string name="location_activity_title_preview">Standort</string>
|
||||
<string name="closed_poll_option_description">Die Ergebnisse werden erst sichtbar, sobald du die Umfrage beendest</string>
|
||||
<string name="closed_poll_option_title">Abgeschlossene Abstimmung</string>
|
||||
<string name="closed_poll_option_title">Versteckte Umfrage</string>
|
||||
<string name="open_poll_option_description">Abstimmende können die Ergebnisse nach Stimmabgabe sehen</string>
|
||||
<string name="open_poll_option_title">Laufende Abstimmung</string>
|
||||
<string name="poll_type_title">Abstimmungsart</string>
|
||||
<string name="edit_poll_title">Abstimmung bearbeiten</string>
|
||||
<string name="open_poll_option_title">Offene Umfrage</string>
|
||||
<string name="poll_type_title">Umfragetyp</string>
|
||||
<string name="edit_poll_title">Umfrage bearbeiten</string>
|
||||
<string name="poll_no_votes_cast">Keine Stimmen abgegeben</string>
|
||||
<string name="login_splash_create_account">Konto erstellen</string>
|
||||
<string name="ftue_auth_carousel_workplace_title">Kommunikation für dein Team.</string>
|
||||
|
@ -2527,7 +2527,7 @@
|
|||
<string name="ftue_auth_terms_title">Server-Richtlinien</string>
|
||||
<string name="ftue_auth_email_verification_subtitle">Folge den Anweisungen, die an %s gesendet wurden</string>
|
||||
<string name="ftue_auth_email_verification_title">E-Mail bestätigen</string>
|
||||
<string name="poll_undisclosed_not_ended">Ergebnisse werden nach Abschluss der Abstimmung sichtbar sein</string>
|
||||
<string name="poll_undisclosed_not_ended">Ergebnisse werden nach Abschluss der Umfrage sichtbar sein</string>
|
||||
<string name="ftue_auth_reset_password_breaker_title">Prüfe deine E-Mails.</string>
|
||||
<string name="ftue_auth_reset_password">Passwort zurücksetzen</string>
|
||||
<string name="ftue_auth_new_password_subtitle">Gib mindestens 8 Zeichen ein.</string>
|
||||
|
@ -2843,4 +2843,26 @@
|
|||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Jemand anderes nimmt bereits eine Sprachübertragung auf. Warte auf das Ende der Übertragung, bevor du eine neue startest.</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">30 Sekunden vorspulen</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">30 Sekunden zurückspulen</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Auf verifizierte Sitzungen kannst du überall mit deinem Konto zugreifen, wenn du deine Passphrase eingegeben oder Element mit einer anderen Sitzung verifiziert hast.
|
||||
\n
|
||||
\nDies bedeutet, dass du alle Schlüssel zum Entsperren deiner verschlüsselten Nachrichten hast und anderen bestätigst, dieser Sitzung zu vertrauen.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Von %1$d Sitzung abmelden</item>
|
||||
<item quantity="other">Von %1$d Sitzungen abmelden</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Abmelden</string>
|
||||
<string name="voice_broadcast_recording_time_left">%1$s übrig</string>
|
||||
<string name="quoting">Zitieren</string>
|
||||
<string name="editing">Bearbeiten</string>
|
||||
<string name="message_reply_to_sender_created_poll">erstellte eine Umfrage.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">sandte einen Sticker.</string>
|
||||
<string name="message_reply_to_sender_sent_video">sandte ein Video.</string>
|
||||
<string name="message_reply_to_sender_sent_image">sandte ein Bild.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">sandte eine Sprachnachricht.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">sandte eine Audiodatei.</string>
|
||||
<string name="message_reply_to_sender_sent_file">sandte eine Datei.</string>
|
||||
<string name="message_reply_to_prefix">Als Antwort auf</string>
|
||||
<string name="replying_to">%s antworten</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">IP-Adresse ausblenden</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">IP-Adresse anzeigen</string>
|
||||
</resources>
|
|
@ -2649,4 +2649,10 @@
|
|||
<string name="create_room">Crear sala</string>
|
||||
<string name="start_chat">Iniciar conversación</string>
|
||||
<string name="all_chats">Todas las conversaciones</string>
|
||||
</resources>
|
||||
<string name="action_select_all">Seleccionar todo</string>
|
||||
<string name="action_got_it">De acuerdo</string>
|
||||
<plurals name="x_selected">
|
||||
<item quantity="one">%1$d seleccionado</item>
|
||||
<item quantity="other">%1$d seleccionados</item>
|
||||
</plurals>
|
||||
</resources>
|
|
@ -2835,4 +2835,26 @@
|
|||
<string name="error_voice_broadcast_unauthorized_title">Uue ringhäälingukõne alustamine pole võimalik</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Keri tagasi 30 sekundi kaupa</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Keri edasi 30 sekundi kaupa</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Verifitseeritud sessioonideks loetakse Element\'is või mõnes muus Matrix\'i rakenduses selliseid sessioone, kus sa kas oled sisestanud oma salafraasi või tuvastanud end mõne teise oma verifitseeritud sessiooni abil.
|
||||
\n
|
||||
\nSee tähendab, et selles sessioonis on ka kõik vajalikud võtmed krüptitud sõnumite lugemiseks ja teistele kasutajatele kinnitamiseks, et sa usaldad seda sessiooni.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Logi välja %1$d\'st sessioonist</item>
|
||||
<item quantity="other">Logi välja %1$d\'st sessioonist</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Logi välja</string>
|
||||
<string name="voice_broadcast_recording_time_left">jäänud %1$s</string>
|
||||
<string name="editing">Muudan sõnumit</string>
|
||||
<string name="replying_to">Vastan sõnumile %s</string>
|
||||
<string name="quoting">Tsiteerides</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Näita IP-aadressi</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Peida IP-aadress</string>
|
||||
<string name="message_reply_to_prefix">Vastuseks kasutajale</string>
|
||||
<string name="message_reply_to_sender_sent_file">saatis faili.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">saatis helifaili.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">saatis häälsõnumi.</string>
|
||||
<string name="message_reply_to_sender_sent_image">saatis pildi.</string>
|
||||
<string name="message_reply_to_sender_sent_video">saatis video.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">saatis kleepsu.</string>
|
||||
<string name="message_reply_to_sender_created_poll">koostas küsitluse.</string>
|
||||
</resources>
|
|
@ -2825,4 +2825,23 @@
|
|||
<string name="a11y_voice_broadcast_fast_forward">۳۰ ثانیه پیشروی</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">۳۰ ثانیه پسروی</string>
|
||||
<string name="attachment_type_selector_text_formatting">قالببندی متن</string>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">خروج</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">خروج از ۱ نشست</item>
|
||||
<item quantity="other">خروج از %1$d نشست</item>
|
||||
</plurals>
|
||||
<string name="voice_broadcast_recording_time_left">%1$s مانده</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">پیام صوتیای فرستاد.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">پروندهٔ صوتیای فرستاد.</string>
|
||||
<string name="message_reply_to_sender_created_poll">نظرسنجیای ایجاد کرد.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">عکسبرگردانی فرستاد.</string>
|
||||
<string name="message_reply_to_sender_sent_video">ویدیویی فرستاد.</string>
|
||||
<string name="message_reply_to_sender_sent_image">تصویری فرستاد.</string>
|
||||
<string name="message_reply_to_sender_sent_file">پروندهای فرستاد.</string>
|
||||
<string name="message_reply_to_prefix">در پاسخ به</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">نهفتن نشانی آیپی</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">نمایش نشانی آیپی</string>
|
||||
<string name="quoting">نقل کردن</string>
|
||||
<string name="replying_to">پاسخ دادن به %s</string>
|
||||
<string name="editing">ویرایش کردن</string>
|
||||
</resources>
|
|
@ -2844,4 +2844,26 @@
|
|||
<string name="error_voice_broadcast_unauthorized_title">Impossible de commencer une nouvelle diffusion audio</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Avance rapide de 30 secondes</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Retour rapide de 30 secondes</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Les sessions vérifiées sont toutes celles qui utilisent ce compte après avoir saisie la phrase de sécurité ou confirmé votre identité à l’aide d’une autre session vérifiée.
|
||||
\n
|
||||
\nCela veut dire qu’elles disposent de toutes les clés nécessaires pour lire les messages chiffrés, et confirment aux autres utilisateurs que vous faites confiance à cette session.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Déconnecter %1$d session</item>
|
||||
<item quantity="other">Déconnecter %1$d sessions</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Déconnecter</string>
|
||||
<string name="voice_broadcast_recording_time_left">%1$s restant</string>
|
||||
<string name="message_reply_to_sender_created_poll">a créé un sondage.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">a envoyé un autocollant.</string>
|
||||
<string name="message_reply_to_sender_sent_video">a envoyé une vidéo.</string>
|
||||
<string name="message_reply_to_sender_sent_image">a envoyé une image.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">envoyer un message vocal.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">a envoyé un fichier audio.</string>
|
||||
<string name="message_reply_to_sender_sent_file">a envoyé un fichier.</string>
|
||||
<string name="message_reply_to_prefix">En réponse à</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Masquer l’adresse IP</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Afficher l’adresse IP</string>
|
||||
<string name="quoting">Citation de</string>
|
||||
<string name="replying_to">Réponse à %s</string>
|
||||
<string name="editing">Modification</string>
|
||||
</resources>
|
|
@ -2836,4 +2836,34 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
|
|||
<item quantity="one">%1$d kiválasztva</item>
|
||||
<item quantity="other">%1$d kiválasztva</item>
|
||||
</plurals>
|
||||
<string name="rich_text_editor_full_screen_toggle">Teljes képernyő váltás</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Mindenhol ellenőrzött munkamenetek vannak ahol ezt a fiókot használva megadtad a jelmondatodat vagy egy másik már hitelesített munkamenetből megerősítetted az identitásodat.
|
||||
\n
|
||||
\nEz azt jelenti, hogy a titkosított üzenetek visszafejtéséhez rendelkezel a kulcsokkal és megerősíted a többiek felé, hogy megbízol a munkamenetben.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Kijelentkezés %1$d munkamenetből</item>
|
||||
<item quantity="other">Kijelentkezés %1$d munkamenetből</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Kijelentkezés</string>
|
||||
<string name="attachment_type_selector_text_formatting">Szöveg formázás</string>
|
||||
<string name="error_voice_broadcast_already_in_progress_message">Egy hang közvetítés már folyamatban van. Először fejezze be a jelenlegi közvetítést egy új indításához.</string>
|
||||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Valaki már elindított egy hang közvetítést. Várd meg a közvetítés végét az új indításához.</string>
|
||||
<string name="error_voice_broadcast_permission_denied_message">Nincs jogosultságod hang közvetítést indítani ebben a szobában. Vedd fel a kapcsolatot a szoba adminisztrátorával a szükséges jogosultság megszerzéséhez.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Az új hang közvetítés nem indítható el</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">30 másodperccel előre</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">30 másodperccel vissza</string>
|
||||
<string name="voice_broadcast_recording_time_left">visszavan: %1$s</string>
|
||||
<string name="message_reply_to_sender_created_poll">szavazás elkészítve.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">matrica elküldve.</string>
|
||||
<string name="message_reply_to_sender_sent_video">videót küldött.</string>
|
||||
<string name="message_reply_to_sender_sent_image">kép elküldve.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">hang üzenet elküldve.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">hangfájl elküldve.</string>
|
||||
<string name="message_reply_to_sender_sent_file">fájl elküldve.</string>
|
||||
<string name="message_reply_to_prefix">Válaszolva erre</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">IP címek elrejtése</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">IP címek megjelenítése</string>
|
||||
<string name="quoting">Idézet</string>
|
||||
<string name="replying_to">Válasz erre: %s</string>
|
||||
<string name="editing">Szerkesztés</string>
|
||||
</resources>
|
|
@ -2791,4 +2791,25 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
|
|||
<string name="error_voice_broadcast_unauthorized_title">Tidak dapat memulai siaran suara baru</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Maju cepat 30 detik</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Mundur cepat 30 detik</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Sesi terverifikasi ada di mana pun Anda menggunakan Element setelah memasukkan frasa sandi atau mengonfirmasi identitas Anda dengan sesi terverifikasi lainnya.
|
||||
\n
|
||||
\nIni berarti Anda memiliki semua kunci yang diperlukan untuk membuka kunci pesan terenkripsi dan mengonfirmasi kepada pengguna lain bahwa Anda memercayai sesi ini.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="other">Keluarkan %1$d sesi</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Keluarkan</string>
|
||||
<string name="voice_broadcast_recording_time_left">%1$s tersisa</string>
|
||||
<string name="message_reply_to_sender_created_poll">membuat pemungutan suara.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">mengirim stiker.</string>
|
||||
<string name="message_reply_to_sender_sent_video">mengirim video.</string>
|
||||
<string name="message_reply_to_sender_sent_image">mengirim gambar.</string>
|
||||
<string name="message_reply_to_sender_sent_file">mengirim file.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">mengirim file audio.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">mengirim pesan suara.</string>
|
||||
<string name="message_reply_to_prefix">Membalas ke</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Sembunyikan alamat IP</string>
|
||||
<string name="quoting">Mengutip</string>
|
||||
<string name="editing">Mengedit</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Tampilkan alamat IP</string>
|
||||
<string name="replying_to">Membalas ke %s</string>
|
||||
</resources>
|
|
@ -2827,4 +2827,34 @@
|
|||
<item quantity="one">%1$d selezionato</item>
|
||||
<item quantity="other">%1$d selezionati</item>
|
||||
</plurals>
|
||||
<string name="rich_text_editor_full_screen_toggle">Attiva/disattiva schermo intero</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Le sessioni verificate sono ovunque usi questo account dopo l\'inserimento della password o la conferma della tua identità con un\'altra sessione verificata.
|
||||
\n
|
||||
\nCiò significa che hai tutte le chiavi necessarie per sbloccare i tuoi messaggi cifrati e per confermare agli altri utenti che ti fidi di questa sessione.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Disconnetti da %1$d sessione</item>
|
||||
<item quantity="other">Disconnetti da %1$d sessioni</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Disconnetti</string>
|
||||
<string name="attachment_type_selector_text_formatting">Formattazione testo</string>
|
||||
<string name="error_voice_broadcast_already_in_progress_message">Stai già registrando una trasmissione vocale. Termina quella in corso per iniziarne una nuova.</string>
|
||||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Qualcun altro sta già registrando una trasmissione vocale. Aspetta che finisca prima di iniziarne una nuova.</string>
|
||||
<string name="error_voice_broadcast_permission_denied_message">Non hai l\'autorizzazione necessaria per iniziare una trasmissione vocale in questa stanza. Contatta un amministratore della stanza per aggiornare le tue autorizzazioni.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Impossibile iniziare una nuova trasmissione vocale</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Manda avanti di 30 secondi</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Manda indietro di 30 secondi</string>
|
||||
<string name="voice_broadcast_recording_time_left">%1$s rimasti</string>
|
||||
<string name="message_reply_to_sender_created_poll">creato un sondaggio.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">inviato un adesivo.</string>
|
||||
<string name="message_reply_to_sender_sent_video">inviato un video.</string>
|
||||
<string name="message_reply_to_sender_sent_image">inviata un\'immagine.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">inviato un messaggio vocale.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">inviato un file audio.</string>
|
||||
<string name="message_reply_to_sender_sent_file">inviato un file.</string>
|
||||
<string name="message_reply_to_prefix">In risposta a</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Nascondi indirizzo IP</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Mostra indirizzo IP</string>
|
||||
<string name="quoting">Citazione</string>
|
||||
<string name="replying_to">Risposta a %s</string>
|
||||
<string name="editing">Modifica</string>
|
||||
</resources>
|
|
@ -2715,7 +2715,7 @@
|
|||
<string name="home_layout_preferences">Preferencje interfejsu</string>
|
||||
<string name="explore_rooms">Przeglądaj pokoje</string>
|
||||
<string name="create_room">Utwórz pokój</string>
|
||||
<string name="start_chat">Zacznij rozmawiać</string>
|
||||
<string name="start_chat">Rozpocznij czat</string>
|
||||
<string name="all_chats">Wszystkie rozmowy</string>
|
||||
<string name="device_manager_other_sessions_description_unverified">Nie zweryfikowano · Ostatnia aktywność %1$s</string>
|
||||
<string name="device_manager_other_sessions_description_verified">Zweryfikowano · Ostatnia aktywność %1$s</string>
|
||||
|
@ -2743,4 +2743,4 @@
|
|||
<string name="home_empty_space_no_rooms_title">%s
|
||||
\nwygląda nieco pusto.</string>
|
||||
<string name="space_list_empty_title">Brak przestrzeni.</string>
|
||||
</resources>
|
||||
</resources>
|
|
@ -2844,4 +2844,26 @@
|
|||
<string name="error_voice_broadcast_unauthorized_title">Não dá pra começar um novo broadcast de voz</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Avançar rápido 30 segundos</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Retroceder 30 segundos</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Sessões verificadas são onde quer que você está usando esta conta depois de entrar sua frasepasse ou confirmar sua identidade com uma outra sessão verificada.
|
||||
\n
|
||||
\nIsto significa que você tem todas as chaves necessitadas para destrancar suas mensagens encriptadas e confirmar a outras(os) usuárias(os) que você confia nesta sessão.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Fazer signout de %1$d sessão</item>
|
||||
<item quantity="other">Fazer signout de %1$d sessões</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Fazer signout</string>
|
||||
<string name="voice_broadcast_recording_time_left">%1$s restando</string>
|
||||
<string name="message_reply_to_sender_created_poll">criou uma sondagem.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">enviou um sticker.</string>
|
||||
<string name="message_reply_to_sender_sent_video">enviou um vídeo.</string>
|
||||
<string name="message_reply_to_sender_sent_image">enviou uma imagem.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">enviou uma mensagem de voz.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">enviou um arquivo de áudio.</string>
|
||||
<string name="message_reply_to_sender_sent_file">enviou um arquivo.</string>
|
||||
<string name="message_reply_to_prefix">Em resposta a</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Esconder endereço de IP</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Mostrar endereço de IP</string>
|
||||
<string name="quoting">Citando</string>
|
||||
<string name="replying_to">Respondendo a %s</string>
|
||||
<string name="editing">Editando</string>
|
||||
</resources>
|
|
@ -930,7 +930,7 @@
|
|||
<string name="settings_security_and_privacy">Безопасность</string>
|
||||
<string name="settings_push_rules">Правила push-уведомлений</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_push_key">Ключ Push:</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>
|
||||
|
@ -1000,10 +1000,10 @@
|
|||
<string name="settings_discovery_bad_identity_server">Не удалось подключиться к серверу обнаружения</string>
|
||||
<string name="settings_discovery_please_enter_server">Пожалуйста, введите URL сервера обнаружения</string>
|
||||
<string name="settings_discovery_no_terms_title">Сервер обнаружения не имеет условий использования</string>
|
||||
<string name="settings_discovery_no_mails">Параметры обнаружения появятся после добавления электронной почты.</string>
|
||||
<string name="settings_discovery_no_mails">Параметры обнаружения появятся после добавления адреса электронной почты.</string>
|
||||
<string name="settings_discovery_no_msisdn">Параметры поиска появятся после добавления номера телефона.</string>
|
||||
<string name="settings_discovery_disconnect_identity_server_info">Отключение от сервера обнаружения будет означать, что другие пользователи не смогут обнаружить вас, и вы не сможете приглашать других по электронной почте или по телефону.</string>
|
||||
<string name="settings_discovery_confirm_mail">Мы отправили вам электронное письмо с подтверждением на %s, проверьте вашу электронную почту и нажмите на ссылку для подтверждения</string>
|
||||
<string name="settings_discovery_confirm_mail">Мы отправили вам электронное письмо на %s, проверьте вашу электронную почту и нажмите на ссылку для подтверждения</string>
|
||||
<string name="settings_discovery_no_terms">Выбранный сервер обнаружения не имеет условий использования. Продолжайте, только если вы доверяете его владельцу</string>
|
||||
<string name="settings_text_message_sent">Текстовое сообщение отправлено %s. Введите код проверки, который он содержит.</string>
|
||||
<string name="settings_discovery_disconnect_with_bound_pid">В настоящее время вы делитесь адресами электронной почты или телефонными номерами на сервере обнаружения %1$s. Вам нужно повторно подключиться к %2$s, чтобы прекратить делиться ими.</string>
|
||||
|
@ -1102,7 +1102,7 @@
|
|||
<string name="login_reset_password_warning_title">Предупреждение!</string>
|
||||
<string name="login_reset_password_warning_content">Смена пароля приведёт к сбросу всех сквозных ключей шифрования во всех ваших сессиях, что сделает зашифрованную историю разговоров нечитаемой. Настройте резервное копирование ключей или экспортируйте ключи от комнаты из другой сессии, прежде чем сбрасывать пароль.</string>
|
||||
<string name="login_reset_password_warning_submit">Продолжить</string>
|
||||
<string name="login_reset_password_error_not_found">Данный электронный ящик не связан ни с одним аккаунтом</string>
|
||||
<string name="login_reset_password_error_not_found">Данный адрес электронной почты не связан ни с одним аккаунтом</string>
|
||||
<string name="login_reset_password_mail_confirmation_title">Проверьте свою почту</string>
|
||||
<string name="login_reset_password_mail_confirmation_notice">Письмо с подтверждением было отправлено на %1$s.</string>
|
||||
<string name="login_reset_password_mail_confirmation_notice_2">Нажмите на ссылку, чтобы подтвердить свой новый пароль. Как только вы перейдете по ссылке нажмите ниже.</string>
|
||||
|
@ -1241,7 +1241,7 @@
|
|||
<string name="notification_ticker_text_group">%1$s: %2$s %3$s</string>
|
||||
<string name="settings_show_redacted">Удалённые сообщения</string>
|
||||
<string name="settings_show_redacted_summary">Показывать заглушку на месте удалённых сообщений</string>
|
||||
<string name="settings_discovery_confirm_mail_not_clicked">Мы отправили письмо для подтверждения на %s, проверьте почту и нажмите на ссылку для подтверждения</string>
|
||||
<string name="settings_discovery_confirm_mail_not_clicked">Мы отправили письмо на %s, пожалуйста проверьте почту и нажмите на ссылку для подтверждения</string>
|
||||
<string name="settings_text_message_sent_wrong_code">Код подтверждения неверный.</string>
|
||||
<string name="error_terms_not_accepted">Попробуйте снова после принятия условий обслуживания на вашем домашнем сервере.</string>
|
||||
<string name="error_network_timeout">Похоже, сервер долгое время не отвечает, что может быть вызвано плохим соединением или ошибкой на сервере. Попробуйте снова через некоторое время.</string>
|
||||
|
@ -1351,7 +1351,7 @@
|
|||
<string name="login_server_url_form_common_notice">Введите адрес сервера, который вы хотите использовать</string>
|
||||
<string name="login_reset_password_notice">На ваш почтовый ящик будет отправлено письмо для подтверждения установки нового пароля.</string>
|
||||
<string name="login_reset_password_mail_confirmation_submit">Я подтвердил свою электронную почту</string>
|
||||
<string name="login_set_email_notice">Установите адрес электронной почты для восстановления вашей учетной записи. Позже вы можете дополнительно разрешить людям, которых вы знаете, обнаружить вас по электронной почте.</string>
|
||||
<string name="login_set_email_notice">Укажите адрес электронной почты для восстановления вашей учетной записи. Потом вы сможете, при желании, разрешить людям, которых вы знаете, обнаружить вас по адресу электронной почты.</string>
|
||||
<string name="login_validation_code_is_not_correct">Введенный код неверен. Пожалуйста, проверьте.</string>
|
||||
<string name="login_connect_using_matrix_id_submit">Войти с Matrix ID</string>
|
||||
<string name="login_signin_matrix_id_title">Войти с Matrix ID</string>
|
||||
|
@ -1482,7 +1482,7 @@
|
|||
<string name="not_trusted">Незаверенная</string>
|
||||
<string name="verification_profile_device_verified_because">Эта сессия является доверенной для безопасного обмена сообщениями, так как %1$s (%2$s) проверил(а) его:</string>
|
||||
<string name="verification_profile_device_new_signing">%1$s (%2$s) вошел(ла), используя новую сессию:</string>
|
||||
<string name="verification_profile_device_untrust_info">Пока этот пользователь не доверяет этой сессии, сообщения, отправленные в обе стороны, помечаются предупреждениями. Кроме того, вы можете подтвердить сессию вручную.</string>
|
||||
<string name="verification_profile_device_untrust_info">Пока этот пользователь не доверяет этой сессии, сообщения, отправленные в обе стороны, помечаются предупреждениями. Вы также можете подтвердить эту сессию вручную.</string>
|
||||
<string name="initialize_cross_signing">Начать перекрестную подпись</string>
|
||||
<string name="reset_cross_signing">Сбросить ключи</string>
|
||||
<string name="qr_code_scanned_by_other_notice">Почти готово! Показывает ли %s галочку\?</string>
|
||||
|
@ -1606,7 +1606,7 @@
|
|||
<string name="identity_server_error_outdated_home_server">Эта операция невозможна. Домашний сервер устарел.</string>
|
||||
<string name="identity_server_error_no_identity_server_configured">Пожалуйста, настройте сначала сервер идентификации.</string>
|
||||
<string name="identity_server_error_terms_not_signed">Пожалуйста, примите сначала условия сервера идентификации в настройках.</string>
|
||||
<string name="identity_server_error_bulk_sha256_not_supported">Для вашей приватности, ${app_name} поддерживает отправку адреса электронной почты и номера телефона только в хэшированном виде.</string>
|
||||
<string name="identity_server_error_bulk_sha256_not_supported">Для вашей приватности, ${app_name} поддерживает отправку адреса электронной почты и номеров телефонов только в хэшированном виде.</string>
|
||||
<string name="identity_server_error_binding_error">Привязка не удалась.</string>
|
||||
<string name="identity_server_error_no_current_binding_error">Текущая взаимосвязь с этим идентификатором отсутствует.</string>
|
||||
<string name="identity_server_set_default_notice">Ваш домашний сервер (%1$s) предлагает использовать %2$s для вашего сервера обнаружения</string>
|
||||
|
@ -1793,7 +1793,7 @@
|
|||
<string name="attachment_type_dialog_title">Добавить изображение из</string>
|
||||
<string name="create_room_topic_hint">Тема</string>
|
||||
<string name="create_room_name_section">Название комнаты</string>
|
||||
<string name="settings_discovery_consent_notice_on">Вы дали свое согласие на отправку электронных писем и телефонных номеров на этот сервер обнаружения для обнаружения других пользователей из ваших контактов.</string>
|
||||
<string name="settings_discovery_consent_notice_on">Вы дали свое согласие на отправку адресов электронных почт и телефонных номеров на этот сервер идентификации для обнаружения других пользователей из ваших контактов.</string>
|
||||
<string name="add_by_qr_code">Добавить по QR-коду</string>
|
||||
<string name="permissions_denied_add_contact">Разрешить доступ к вашим контактам.</string>
|
||||
<string name="permissions_denied_qr_code">Чтобы отсканировать QR-код, вам нужно разрешить доступ к камере.</string>
|
||||
|
@ -2396,7 +2396,7 @@
|
|||
<string name="attachment_type_location">Местоположение</string>
|
||||
<string name="identity_server_consent_dialog_content_question">Вы согласны отправить эту информацию\?</string>
|
||||
<string name="identity_server_consent_dialog_content_3">Чтобы обнаружить существующие контакты, необходимо отправить контактную информацию (электронную почту и номера телефонов) на сервер обнаружения. Мы хешируем ваши данные перед отправкой для обеспечения конфиденциальности.</string>
|
||||
<string name="identity_server_consent_dialog_title_2">Отправить электронные адреса и номера телефонов %s</string>
|
||||
<string name="identity_server_consent_dialog_title_2">Отправить адреса электронных почт и номера телефонов %s</string>
|
||||
<string name="settings_discovery_consent_notice_off_2">Ваши контакты приватны. Чтобы обнаружить пользователей из ваших контактов, нам необходимо ваше разрешение на отправку контактной информации на ваш сервер обнаружения.</string>
|
||||
<string name="preference_system_settings">Системные настройки</string>
|
||||
<string name="preference_versions">Версии</string>
|
||||
|
@ -2805,4 +2805,162 @@
|
|||
<string name="attachment_type_selector_location">Местоположение</string>
|
||||
<string name="attachment_type_selector_camera">Камера</string>
|
||||
<string name="attachment_type_selector_contact">Контакт</string>
|
||||
<string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} нуждается в разрешении для отображения оповещений.
|
||||
\nПожалуйста, дайте разрешение.</string>
|
||||
<plurals name="search_space_multiple_parents">
|
||||
<item quantity="one">%1$s и %2$d другой</item>
|
||||
<item quantity="few">%1$s и %2$d другие</item>
|
||||
<item quantity="many">%1$s и %2$d других</item>
|
||||
<item quantity="other">%1$s и %2$d других</item>
|
||||
</plurals>
|
||||
<string name="permissions_rationale_msg_notification">${app_name} нуждается в резрешении для отображения оповещений. Оповещения могут показывать ваши сообщения, приглашения и тому подобное.
|
||||
\n
|
||||
\nПожалуйста разрешите доступ при следующем всплывающем сообщении, чтобы иметь возможность видеть оповещения.</string>
|
||||
<string name="invites_empty_message">Здесь будут появляться новые запросы и приглашения.</string>
|
||||
<string name="invites_title">Приглашения</string>
|
||||
<string name="labs_enable_rich_text_editor_summary">Попробуйте расширенный текстовый редактор (режим набора обычного текста скоро появится)</string>
|
||||
<string name="labs_enable_deferred_dm_summary">Создавать личные сообщения только при отправке первого сообщения</string>
|
||||
<string name="labs_enable_deferred_dm_title">Включить отложенные личные сообщения</string>
|
||||
<string name="action_deselect_all">Отменить выбор всего</string>
|
||||
<string name="action_select_all">Выбрать всё</string>
|
||||
<string name="a11y_collapse_space_children">Свернуть дочерние элементы %s</string>
|
||||
<string name="a11y_expand_space_children">Развернуть дочерние элементы %s</string>
|
||||
<plurals name="x_selected">
|
||||
<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="rich_text_editor_full_screen_toggle">Войти в полноэкранный режим</string>
|
||||
<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="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-код</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_show_qr_code_instruction_1">Начните с экрана входа</string>
|
||||
<string name="qr_code_login_link_a_device_scan_qr_code_instruction_2">Выберите «Войти при помощи QR-кода»</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">Откройте приложение с другого устройства</string>
|
||||
<string name="qr_code_login_header_failed_homeserver_is_not_supported_description">Домашний сервер не поддерживает вход при помощи QR-кода.</string>
|
||||
<string name="qr_code_login_header_failed_user_cancelled_description">Вход был отменён с другого устройства.</string>
|
||||
<string name="qr_code_login_header_failed_invalid_qr_code_description">Этот QR-код не работает.</string>
|
||||
<string name="qr_code_login_header_failed_other_device_not_signed_in_description">Другое устройство должно войти в учётную запись.</string>
|
||||
<string name="qr_code_login_header_failed_other_device_already_signed_in_description">Другое устройство уже выполнило вход.</string>
|
||||
<string name="qr_code_login_header_failed_e2ee_security_issue_description">Во время установки безопасной переписки возникла проблема с безопасностью. Одно из следующего является скомпроментированным: Ваш домашний сервер; Ваше интернет-соединение; Ваше устройство;</string>
|
||||
<string name="qr_code_login_header_failed_other_description">Запрос не выполнен.</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="qr_code_login_header_scan_qr_code_title">Сканировать QR-код</string>
|
||||
<string name="three">3</string>
|
||||
<string name="two">2</string>
|
||||
<string name="one">1</string>
|
||||
<string name="onboarding_new_app_layout_feedback_message">Нажмите слева сверху, чтобы увидеть опцию отзыва.</string>
|
||||
<string name="onboarding_new_app_layout_welcome_message">Чтобы упростить ${app_name}, вкладки теперь опциональные. Управляйте ими при помощи меню справа сверху.</string>
|
||||
<string name="home_empty_no_rooms_message">Универсальное безопасное приложение для переписок с командами, друзьями и организациями. Создайте переписку или присоеденитесь к уже существующей, чтобы начать.</string>
|
||||
<string name="home_empty_space_no_rooms_message">Пространства — новый способ групировать комнаты и людей. Добавьте существующую комнату или создайте новую, используя кнопку слева снизу.</string>
|
||||
<string name="labs_enable_voice_broadcast_summary">Возможность записывать и отправлять голосовые трансляции в ленту комнаты.</string>
|
||||
<string name="labs_enable_session_manager_summary">Получите лучший надзор и контроль над всеми вашими сессиями.</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Подтверждённые сессии есть везде, где вы используете эту учётную запись, после введения вашего пароля или подтверждения вашей личности при помощи другой подтверждённой сессии.
|
||||
\n
|
||||
\nЭто значит, что у вас есть все нужные ключи, чтобы разблокировать зашифрованные сообщения и даёте другим пользователям знать, что вы доверяете этой сессии.</string>
|
||||
<string name="device_manager_learn_more_sessions_verified" tools:ignore="UnusedResources">Подтверждённые сессии вошли при помощи ваших учётных данных и были подтверждены, либо при помощи вашего безопасного пароля, либо при помощи подтверждения с другого устройства.
|
||||
\n
|
||||
\nЭто значит, что на них находятся ключи шифрования для ваших предыдущих сообщений и дают другим пользователям знать, что эти сессии действительно принадлежат вам.</string>
|
||||
<string name="device_manager_learn_more_sessions_unverified">Неподтверждённые сессии — это сессии, которые вошли при помощи ваших учётных данных, но не были подтверждены.
|
||||
\n
|
||||
\nВы должны удостовериться, что узнаёте эти сессии, так как они могут быть несанкционированным входом в вашу учётную запись.</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="device_manager_session_rename_description">Собственные названия сессий помогут вам легче распознать свои девайсы.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<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="device_manager_other_sessions_multi_signout_selection">Выйти</string>
|
||||
<string name="device_manager_other_sessions_select">Выбрать сессии</string>
|
||||
<string name="a11y_device_manager_filter">Фильтр</string>
|
||||
<plurals name="device_manager_other_sessions_description_inactive">
|
||||
<item quantity="one">Неактивен %1$d+ день (%2$s)</item>
|
||||
<item quantity="few">Неактивен %1$d+ дней (%2$s)</item>
|
||||
<item quantity="many">Неактивен %1$d+ дня (%2$s)</item>
|
||||
<item quantity="other">Неактивен %1$d+ дня (%2$s)</item>
|
||||
</plurals>
|
||||
<string name="device_manager_verification_status_detail_other_session_unknown">Подтвердите текущую сессию, чтобы посмотреть её состояние подтверждения.</string>
|
||||
<string name="device_manager_verification_status_unknown">Неизвестное состояние проверки</string>
|
||||
<string name="labs_enable_element_call_permission_shortcuts_summary">Автоматически принимать виджеты Element Call и давать доступ к микрофону/камере</string>
|
||||
<string name="labs_enable_element_call_permission_shortcuts">Включить ярлыки разрешений Element Call</string>
|
||||
<string name="attachment_type_selector_text_formatting">Форматирование текста</string>
|
||||
<string name="tooltip_attachment_voice_broadcast">Начать новую голосовую трансляцию</string>
|
||||
<string name="live_location_not_enough_permission_dialog_description">Вам необходимо иметь нужные разрешения, чтобы делиться местоположением в реальном времени в этой комнате.</string>
|
||||
<string name="live_location_not_enough_permission_dialog_title">У вас нет разрешения делиться местоположением в реальном времени</string>
|
||||
<string name="labs_enable_msc3061_share_history_desc">При приглашении кого-то в зашифрованную комнату, которая делится историей, зашифрованная история будет видимой.</string>
|
||||
<string name="error_voice_broadcast_already_in_progress_message">Вы уже записываете голосовую трансляцию. Пожалуйста закончите текущую голосовую трансляцию, чтобы начать новую.</string>
|
||||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Кто-то другой уже записывает голосовую трансляцию. Подождите пока их голосовая трансляция закончится, чтобы начать новую.</string>
|
||||
<string name="error_voice_broadcast_permission_denied_message">У вас нет необходимых разрешений для начала голосовой трансляции в этой комнате. Свяжитесь с администратором комнаты, чтобы получить разрешения.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Не получилось начать новую голосовую трансляцию</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Перемотать вперёд на 30 секунд</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Перемотать назад на 30 секунд</string>
|
||||
<string name="a11y_voice_broadcast_buffering">Буферизация</string>
|
||||
<string name="a11y_pause_voice_broadcast">Приостановить голосовую трансляцию</string>
|
||||
<string name="a11y_play_voice_broadcast">Проиграть или продолжить голосовую трансляцию</string>
|
||||
<string name="a11y_stop_voice_broadcast_record">Остановить запись голосовой трансляции</string>
|
||||
<string name="a11y_pause_voice_broadcast_record">Приостановить запись голосовой трансляции</string>
|
||||
<string name="a11y_resume_voice_broadcast_record">Продолжить запись голосовой трансляции</string>
|
||||
<string name="voice_broadcast_live">Прямая трансляция</string>
|
||||
<string name="key_authenticity_not_guaranteed">Подлинность этого зашифрованного сообщения не может быть гарантирована на этом устройстве.</string>
|
||||
<string name="login_scan_qr_code">Сканировать QR-код</string>
|
||||
<string name="send_your_first_msg_to_invite">Отправьте ваше первое сообщение, чтобы пригласить %s в переписку</string>
|
||||
<string name="verify_invalid_qr_notice">Этот QR-код выглядит неправильно. Пожалуйста, попробуйте подтвердить другим способом.</string>
|
||||
<string name="crosssigning_cannot_verify_this_session_desc">Вы не сможете получить доступ к истории зашифрованных сообщений. Сбросьте вашу защищённую резевную копию и ключи подтверждения, чтобы начать заново.</string>
|
||||
<string name="ftue_auth_password_reset_confirmation">Сброс пароля</string>
|
||||
<string name="ftue_auth_new_password_title">Выберите новый пароль</string>
|
||||
<string name="ftue_auth_reset_password_email_subtitle">%s пришлёт вам ссылку для подтверждения</string>
|
||||
<string name="ftue_auth_phone_subtitle">%s нуждается в подтверждении вашей учётной записи</string>
|
||||
<string name="ftue_auth_email_subtitle">%s нуждается в подтверждении вашей учётной записи</string>
|
||||
<string name="ftue_auth_choose_server_ems_cta">Связаться</string>
|
||||
<string name="ftue_auth_choose_server_ems_subtitle">Element Matrix Services (EMS) — надёжная хостинговая служба для быстрой и безопасной связи в режиме реального времени. Узнайте больше на <a href=\"${ftue_ems_url}\">element.io/ems</a></string>
|
||||
<string name="a11y_open_spaces">Открыть список пространств</string>
|
||||
<string name="push_gateway_item_enabled">Включено:</string>
|
||||
<string name="error_check_network" tools:ignore="UnusedResources">Что-то пошло не так. Пожалуйста, проверьте соединение и попробуйте ещё раз.</string>
|
||||
<string name="command_description_devtools">Открыть экран инструментов для разработчика</string>
|
||||
<string name="timeline_error_room_not_found">Простите, эта комната не была найдена.
|
||||
\nПожалуйста, попробуйте снова позже.%s</string>
|
||||
<string name="some_devices_will_not_be_able_to_decrypt">⚠ В этой комнате есть неподтверждённые устройства, они не смогут расшифровывать сообщения, отправленные вами.</string>
|
||||
<string name="grant_permission">Дать разрешение</string>
|
||||
<string name="ftue_auth_create_account_username_entry_footer">Другие пользователи могут найти вас по %s</string>
|
||||
<string name="voice_broadcast_recording_time_left">Осталось %1$s</string>
|
||||
<string name="message_reply_to_sender_created_poll">создал опрос.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">отправил наклейку.</string>
|
||||
<string name="message_reply_to_sender_sent_video">отправил видео.</string>
|
||||
<string name="message_reply_to_sender_sent_image">отправил изображение.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">отправил голосовое сообщение.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">отправил аудиофайл.</string>
|
||||
<string name="message_reply_to_sender_sent_file">отправил файл.</string>
|
||||
<string name="message_reply_to_prefix">В ответ на</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Скрыть IP-адрес</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Показать IP-адрес</string>
|
||||
<string name="quoting">Цитируя</string>
|
||||
<string name="replying_to">В ответ на %s</string>
|
||||
<string name="editing">Редактирование</string>
|
||||
</resources>
|
|
@ -2765,7 +2765,7 @@
|
|||
<string name="labs_enable_new_app_layout_title">Zapnúť nové usporiadanie</string>
|
||||
<string name="device_manager_learn_more_session_rename">Ostatní používatelia v priamych správach a miestnostiach, do ktorých sa pripojíte, si môžu pozrieť úplný zoznam vašich relácií.
|
||||
\n
|
||||
\nTo im poskytuje istotu, že sa s vami naozaj rozprávajú, ale zároveň to znamená, že vidia názov relácie, ktorý sem zadáte.</string>
|
||||
\nTo im poskytuje istotu, že sa komunikujú naozaj s vami, ale zároveň to znamená, že vidia názov relácie, ktorý sem zadáte.</string>
|
||||
<string name="device_manager_learn_more_session_rename_title">Premenovanie relácií</string>
|
||||
<string name="device_manager_learn_more_sessions_verified">Overené relácie, do ktorých ste sa prihlásili pomocou svojich prihlasovacích údajov a ktoré boli následne overené buď pomocou vašej bezpečnostnej prístupovej frázy, alebo krížovým overením.
|
||||
\n
|
||||
|
@ -2899,4 +2899,27 @@
|
|||
<string name="error_voice_broadcast_unauthorized_title">Nie je možné spustiť nové hlasové vysielanie</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Rýchle posunutie dozadu o 30 sekúnd</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Rýchle posunutie dopredu o 30 sekúnd</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Overené relácie sú všade tam, kde používate toto konto po zadaní svojho prístupového hesla alebo po potvrdení svojej totožnosti inou overenou reláciou.
|
||||
\n
|
||||
\nTo znamená, že máte všetky kľúče potrebné na odomknutie zašifrovaných správ a potvrdenie pre ostatných používateľov, že tejto relácii dôverujete.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Odhlásiť sa z %1$d relácie</item>
|
||||
<item quantity="few">Odhlásiť sa z %1$d relácií</item>
|
||||
<item quantity="other">Odhlásiť sa z %1$d relácií</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Odhlásiť sa</string>
|
||||
<string name="voice_broadcast_recording_time_left">Ostáva %1$s</string>
|
||||
<string name="quoting">Cituje</string>
|
||||
<string name="message_reply_to_sender_created_poll">vytvoril/a anketu.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">poslal/a nálepku.</string>
|
||||
<string name="message_reply_to_sender_sent_video">poslal/a video.</string>
|
||||
<string name="message_reply_to_sender_sent_image">poslal/a obrázok.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">poslal/a zvukovú správu.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">poslal/a zvukový súbor.</string>
|
||||
<string name="message_reply_to_sender_sent_file">poslal súbor.</string>
|
||||
<string name="message_reply_to_prefix">V odpovedi na</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Skryť IP adresu</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Zobraziť IP adresu</string>
|
||||
<string name="replying_to">Odpoveď na %s</string>
|
||||
<string name="editing">Úprava</string>
|
||||
</resources>
|
|
@ -2822,4 +2822,33 @@
|
|||
<string name="verify_invalid_qr_notice">Ky kod QR duket i formuar keq. Ju lutemi, provoni ta verifikoni me tjetër metodë.</string>
|
||||
<string name="room_settings_global_block_unverified_info_text">🔒 Keni aktivizuar fshehtëzim për sesionie të verifikuar vetëm për krejt dhomat, që nga Rregullime Sigurie.</string>
|
||||
<string name="settings_autoplay_animated_images_summary">Luaj figura të animuara te rrjedha kohora sapo zënë të duken</string>
|
||||
<string name="message_reply_to_sender_created_poll">krijoi një pyetësor.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">dërgoi një ngjitës.</string>
|
||||
<string name="message_reply_to_sender_sent_video">dërgoi një video.</string>
|
||||
<string name="message_reply_to_sender_sent_image">dërgoi një figurë.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">dërgoi një mesazh zanor.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">dërgoi një kartelë audio.</string>
|
||||
<string name="message_reply_to_sender_sent_file">dërgoi një kartelë.</string>
|
||||
<string name="message_reply_to_prefix">Në përgjigje të</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">Hyni/Dilni nga mënyra “Sa krejt ekrani”</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Sesionet e verifikuar janë kudo ku përdorni këtë llogari pas dhënies së frazëkalimit tuaj, apo ripohimit të identitetit tuaj me një sesion tjetër të verifikuar.
|
||||
\n
|
||||
\nKjo do të thotë se keni krejt kyçet e nevojshëm për të shkyçur mesazhet tuaj të fshehtëzuar dhe për të ripohuar se e besoni këtë sesion.</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Fshihe adresën IP</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Shfaq adresë IP</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Dilni nga %1$d sesion</item>
|
||||
<item quantity="other">Dilni nga %1$d sesione</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Dilni</string>
|
||||
<string name="attachment_type_selector_text_formatting">Formatim teksti</string>
|
||||
<string name="voice_broadcast_recording_time_left">Edhe %1$s</string>
|
||||
<string name="error_voice_broadcast_already_in_progress_message">Jeni duke incizuar tashmë një transmetim zanor. Ju lutemi, që të nisni një të ri, përfundoni transmetimin tuaj aktual zanor.</string>
|
||||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Dikush tjetër është tashmë duke incizuar një transmetim zanor. Prisni që të përfundojë transmetimi zanor i tij, pa të filloni një të ri.</string>
|
||||
<string name="error_voice_broadcast_permission_denied_message">S’keni lejet e domosdoshme për të nisur një transmetim zanor në këtë dhomë. Lidhuni me një përgjegjës dhome që të përmirësojë lejet tuaja.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">S’mund të niset një transmetim i ri zanor</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Shtyrje përpara 30 sekonda</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Kthim prapa 30 sekonda</string>
|
||||
<string name="replying_to">Si përgjigje për %s</string>
|
||||
<string name="labs_enable_deferred_dm_title">Aktivizo MD të lënë për më vonë</string>
|
||||
</resources>
|
|
@ -2836,4 +2836,20 @@
|
|||
<item quantity="one">%1$d vald</item>
|
||||
<item quantity="other">%1$d valda</item>
|
||||
</plurals>
|
||||
<string name="rich_text_editor_full_screen_toggle">Växla fullskärmsläge</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Verifierade sessioner är alla ställen där du använder det här kontot efter att ha angett din lösenfras eller bekräftat din identitet med en annan verifierad session.
|
||||
\n
|
||||
\nDetta betyder att du har alla nycklar som krävs för att låsa upp dina krypterade meddelanden att bekräfta för andra användare att du litar på den här sessionen.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="one">Logga ut ur %1$d session</item>
|
||||
<item quantity="other">Logga ut ur %1$d sessioner</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">Logga ut</string>
|
||||
<string name="attachment_type_selector_text_formatting">Textformatering</string>
|
||||
<string name="error_voice_broadcast_already_in_progress_message">Du spelar redan in en röstsändning. Avsluta din nuvarande röstsändning för att starta en ny.</string>
|
||||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Någon annan spelar redan in en röstsändning. Vänta på att deras röstsändning avslutas för att starta en ny.</string>
|
||||
<string name="error_voice_broadcast_permission_denied_message">Du är inte behörig att starta en ny röstsändning i det här rummet. Kontakta en rumsadministratör för att uppgradera dina behörigheter.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Kan inte starta en ny röstsändning</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Spola framåt 30 sekunder</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Spola tillbaka 30 sekunder</string>
|
||||
</resources>
|
|
@ -2839,12 +2839,12 @@
|
|||
<string name="device_manager_session_rename">Перейменувати сеанс</string>
|
||||
<string name="device_manager_session_overview_signout">Вийти з цього сеансу</string>
|
||||
<string name="device_manager_other_sessions_description_unverified_current_session">Не звірений - Ваш поточний сеанс</string>
|
||||
<string name="tooltip_attachment_voice_broadcast">Розпочати трансляцію голосового повідомлення</string>
|
||||
<string name="tooltip_attachment_voice_broadcast">Розпочати голосову трансляцію</string>
|
||||
<string name="key_authenticity_not_guaranteed">Справжність цього зашифрованого повідомлення не може бути гарантована на цьому пристрої.</string>
|
||||
<string name="settings_security_incognito_keyboard_summary">Заборонити клавіатурі оновлювати будь-які персоналізовані дані, як-от історію набору тексту та словник, на основі того, що ви набрали в розмовах. Зверніть увагу, що деякі клавіатури можуть не дотримуватися цього налаштування.</string>
|
||||
<string name="settings_security_incognito_keyboard_title">Клавіатура інкогніто</string>
|
||||
<string name="command_description_table_flip">Надсилає (╯°□°)╯︵ ┻━┻ на початку текстового повідомлення</string>
|
||||
<string name="attachment_type_voice_broadcast">Голосові повідомлення</string>
|
||||
<string name="attachment_type_voice_broadcast">Голосові трансляції</string>
|
||||
<string name="command_description_devtools">Відкрийте інструменти розробника</string>
|
||||
<string name="room_settings_global_block_unverified_info_text">🔒 Ви увімкнули шифрування лише для перевірених сеансів для всіх кімнат у налаштуваннях безпеки.</string>
|
||||
<string name="some_devices_will_not_be_able_to_decrypt">⚠ У цій кімнаті є неперевірені пристрої, вони не зможуть розшифрувати повідомлення, які ви надсилаєте.</string>
|
||||
|
@ -2920,21 +2920,21 @@
|
|||
<string name="qr_code_login_header_failed_other_device_already_signed_in_description">Вхід з іншого пристрою вже виконано.</string>
|
||||
<string name="qr_code_login_header_failed_e2ee_security_issue_description">Під час налаштування захищеного обміну повідомленнями виникла проблема з безпекою. Можливо, порушено одне з таких налаштувань: Ваш домашній сервер; Ваше інтернет-з\'єднання; Ваш пристрій;</string>
|
||||
<string name="qr_code_login_header_failed_other_description">Запит не виконаний.</string>
|
||||
<string name="labs_enable_voice_broadcast_summary">Можливість записувати та надсилати голосові повідомлення до стрічки кімнати.</string>
|
||||
<string name="labs_enable_voice_broadcast_title">Увімкнути голосові повідомлення (в активній розробці)</string>
|
||||
<string name="labs_enable_voice_broadcast_summary">Можливість записувати та надсилати голосові трансляції до стрічки кімнати.</string>
|
||||
<string name="labs_enable_voice_broadcast_title">Увімкнути голосові трансляції (в активній розробці)</string>
|
||||
<string name="a11y_voice_broadcast_buffering">Буферизація</string>
|
||||
<string name="a11y_pause_voice_broadcast">Призупинити голосове повідомлення</string>
|
||||
<string name="a11y_play_voice_broadcast">Відтворити або поновити відтворення голосового повідомлення</string>
|
||||
<string name="a11y_stop_voice_broadcast_record">Припинити запис голосового повідомлення</string>
|
||||
<string name="a11y_pause_voice_broadcast_record">Призупинити запис голосового повідомлення</string>
|
||||
<string name="a11y_resume_voice_broadcast_record">Відновити запис голосового повідомлення</string>
|
||||
<string name="a11y_pause_voice_broadcast">Призупинити голосову трансляцію</string>
|
||||
<string name="a11y_play_voice_broadcast">Відтворити або поновити відтворення голосової трансляції</string>
|
||||
<string name="a11y_stop_voice_broadcast_record">Припинити запис голосової трансляції</string>
|
||||
<string name="a11y_pause_voice_broadcast_record">Призупинити запис голосової трансляції</string>
|
||||
<string name="a11y_resume_voice_broadcast_record">Відновити запис голосової трансляції</string>
|
||||
<string name="voice_broadcast_live">Наживо</string>
|
||||
<string name="device_manager_other_sessions_select">Вибрати сеанси</string>
|
||||
<string name="attachment_type_selector_contact">Контакт</string>
|
||||
<string name="attachment_type_selector_camera">Камера</string>
|
||||
<string name="attachment_type_selector_location">Місце перебування</string>
|
||||
<string name="attachment_type_selector_poll">Опитування</string>
|
||||
<string name="attachment_type_selector_voice_broadcast">Голосові повідомлення</string>
|
||||
<string name="attachment_type_selector_voice_broadcast">Голосові трансляції</string>
|
||||
<string name="attachment_type_selector_file">Вкладення</string>
|
||||
<string name="attachment_type_selector_sticker">Наліпки</string>
|
||||
<string name="attachment_type_selector_gallery">Фотобібліотека</string>
|
||||
|
@ -2948,10 +2948,34 @@
|
|||
<string name="action_select_all">Вибрати все</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">Перемкнути повноекранний режим</string>
|
||||
<string name="attachment_type_selector_text_formatting">Форматування тексту</string>
|
||||
<string name="error_voice_broadcast_already_in_progress_message">Ви вже записуєте голосове повідомлення. Завершіть поточну трансляцію, щоб розпочати нову.</string>
|
||||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Хтось інший вже записує голосове повідомлення. Зачекайте, поки закінчиться трансляція, щоб розпочати нову.</string>
|
||||
<string name="error_voice_broadcast_permission_denied_message">Ви не маєте необхідних дозволів для початку передавання голосового повідомлення в цю кімнату. Зверніться до адміністратора кімнати, щоб оновити ваші дозволи.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Не вдалося розпочати передавання нового голосового повідомлення</string>
|
||||
<string name="error_voice_broadcast_already_in_progress_message">Ви вже записуєте голосову трансляцію. Завершіть поточну трансляцію, щоб розпочати нову.</string>
|
||||
<string name="error_voice_broadcast_blocked_by_someone_else_message">Хтось інший вже записує голосову трансляцію. Зачекайте, поки вона завершиться, щоб розпочати нову.</string>
|
||||
<string name="error_voice_broadcast_permission_denied_message">Ви не маєте необхідних дозволів для початку голосової трансляції в цю кімнату. Зверніться до адміністратора кімнати, щоб оновити ваші дозволи.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Не вдалося розпочати нову голосову трансляцію</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Перемотати вперед на 30 секунд</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">Перемотати назад на 30 секунд</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">Звірені сеанси — це будь-який пристрій, на якому ви використовуєте цей обліковий запис після введення парольної фрази або підтвердження вашої особи за допомогою іншого звіреного сеансу.
|
||||
\n
|
||||
\nЦе означає, що ви маєте всі ключі, необхідні для розблокування ваших зашифрованих повідомлень і підтвердження іншим користувачам, що ви довіряєте цьому сеансу.</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<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="device_manager_other_sessions_multi_signout_selection">Вийти</string>
|
||||
<string name="voice_broadcast_recording_time_left">Залишилося %1$s</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">надсилає аудіофайл.</string>
|
||||
<string name="message_reply_to_sender_sent_file">відправив файл.</string>
|
||||
<string name="message_reply_to_prefix">У відповідь на</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Сховати IP-адресу</string>
|
||||
<string name="message_reply_to_sender_created_poll">створив голосування.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">відправив наліпку.</string>
|
||||
<string name="message_reply_to_sender_sent_video">відправив відео.</string>
|
||||
<string name="message_reply_to_sender_sent_image">відправив зображення.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">відправив голосове повідомлення.</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Показати IP-адресу</string>
|
||||
<string name="quoting">Цитуючи</string>
|
||||
<string name="replying_to">У відповідь на %s</string>
|
||||
<string name="editing">Редагування</string>
|
||||
</resources>
|
|
@ -2789,4 +2789,25 @@
|
|||
<string name="error_voice_broadcast_unauthorized_title">無法開始新的語音廣播</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">快轉30秒</string>
|
||||
<string name="a11y_voice_broadcast_fast_backward">快退30秒</string>
|
||||
<string name="device_manager_learn_more_sessions_verified_description">已驗證的工作階段是您輸入通關密語或透過另一個已驗證工作階段確認您的身份後使用此帳號的任何地方。
|
||||
\n
|
||||
\n這代表了您擁有解鎖加密訊息並向其他使用者確認您信任此工作階段所需的所有金鑰。</string>
|
||||
<plurals name="device_manager_other_sessions_multi_signout_all">
|
||||
<item quantity="other">登出 %1$d 個工作階段</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_multi_signout_selection">登出</string>
|
||||
<string name="voice_broadcast_recording_time_left">剩餘 %1$s</string>
|
||||
<string name="message_reply_to_sender_created_poll">已建立投票。</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">已傳送貼圖。</string>
|
||||
<string name="message_reply_to_sender_sent_video">已傳送影片。</string>
|
||||
<string name="message_reply_to_sender_sent_image">已傳送圖片。</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">已傳送語音訊息。</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">已傳送音訊檔。</string>
|
||||
<string name="message_reply_to_sender_sent_file">已傳送檔案。</string>
|
||||
<string name="message_reply_to_prefix">回覆給</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">隱藏 IP 位置</string>
|
||||
<string name="device_manager_other_sessions_show_ip_address">顯示 IP 位置</string>
|
||||
<string name="quoting">引用</string>
|
||||
<string name="replying_to">回覆給 %s</string>
|
||||
<string name="editing">正在編輯</string>
|
||||
</resources>
|
|
@ -1032,6 +1032,8 @@
|
|||
<string name="settings_chat_effects_description">Use /confetti command or send a message containing ❄️ or 🎉</string>
|
||||
<string name="settings_autoplay_animated_images_title">Autoplay animated images</string>
|
||||
<string name="settings_autoplay_animated_images_summary">Play animated images in the timeline as soon as they are visible</string>
|
||||
<string name="settings_enable_direct_share_title">Enable direct share</string>
|
||||
<string name="settings_enable_direct_share_summary">Show recent chats in the system share menu</string>
|
||||
<string name="settings_show_join_leave_messages">Show join and leave events</string>
|
||||
<string name="settings_show_join_leave_messages_summary">Invites, removes, and bans are unaffected.</string>
|
||||
<string name="settings_show_avatar_display_name_changes_messages">Show account events</string>
|
||||
|
@ -1642,7 +1644,10 @@
|
|||
<string name="error_user_already_logged_in">It looks like you’re trying to connect to another homeserver. Do you want to sign out?</string>
|
||||
|
||||
<string name="edit">Edit</string>
|
||||
<string name="editing">Editing</string>
|
||||
<string name="reply">Reply</string>
|
||||
<string name="replying_to">Replying to %s</string>
|
||||
<string name="quoting">Quoting</string>
|
||||
<string name="reply_in_thread">Reply in thread</string>
|
||||
<string name="view_in_room">View In Room</string>
|
||||
|
||||
|
@ -3089,12 +3094,13 @@
|
|||
<string name="audio_message_file_size">(%1$s)</string>
|
||||
|
||||
<string name="voice_broadcast_live">Live</string>
|
||||
<!-- TODO Rename id to voice_broadcast_buffering -->
|
||||
<string name="a11y_voice_broadcast_buffering">Buffering…</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="a11y_voice_broadcast_fast_backward">Fast backward 30 seconds</string>
|
||||
<string name="a11y_voice_broadcast_fast_forward">Fast forward 30 seconds</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Can’t start a new voice broadcast</string>
|
||||
|
@ -3353,6 +3359,8 @@
|
|||
<item quantity="one">Sign out of %1$d session</item>
|
||||
<item quantity="other">Sign out of %1$d sessions</item>
|
||||
</plurals>
|
||||
<string name="device_manager_other_sessions_show_ip_address">Show IP address</string>
|
||||
<string name="device_manager_other_sessions_hide_ip_address">Hide IP address</string>
|
||||
<string name="device_manager_session_overview_signout">Sign out of this session</string>
|
||||
<string name="device_manager_session_details_title">Session details</string>
|
||||
<string name="device_manager_session_details_description">Application, device, and activity information.</string>
|
||||
|
@ -3461,4 +3469,13 @@
|
|||
<string name="rich_text_editor_format_underline">Apply underline format</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">Toggle full screen mode</string>
|
||||
|
||||
<!-- ReplyTo events -->
|
||||
<string name="message_reply_to_prefix">In reply to</string>
|
||||
<string name="message_reply_to_sender_sent_file">sent a file.</string>
|
||||
<string name="message_reply_to_sender_sent_audio_file">sent an audio file.</string>
|
||||
<string name="message_reply_to_sender_sent_voice_message">sent a voice message.</string>
|
||||
<string name="message_reply_to_sender_sent_image">sent an image.</string>
|
||||
<string name="message_reply_to_sender_sent_video">sent a video.</string>
|
||||
<string name="message_reply_to_sender_sent_sticker">sent a sticker.</string>
|
||||
<string name="message_reply_to_sender_created_poll">created a poll.</string>
|
||||
</resources>
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
<dimen name="composer_attachment_margin">1dp</dimen>
|
||||
<dimen name="rich_text_composer_corner_radius_single_line">28dp</dimen>
|
||||
<dimen name="rich_text_composer_corner_radius_expanded">14dp</dimen>
|
||||
<dimen name="rich_text_composer_menu_item_size">44dp</dimen>
|
||||
|
||||
<dimen name="chat_bubble_margin_start">28dp</dimen>
|
||||
<dimen name="chat_bubble_margin_end">6dp</dimen>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<style name="Widget.Vector.EditText.Composer" parent="Widget.AppCompat.EditText">
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
<item name="android:inputType">textCapSentences|textMultiLine</item>
|
||||
<item name="android:maxLines">12</item>
|
||||
<item name="android:maxLines">10</item>
|
||||
<item name="android:minHeight">48dp</item>
|
||||
<item name="android:padding">8dp</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
|
@ -14,9 +14,12 @@
|
|||
<style name="Widget.Vector.EditText.RichTextComposer" parent="Widget.AppCompat.EditText">
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
<item name="android:inputType">textCapSentences|textMultiLine</item>
|
||||
<item name="android:maxLines">12</item>
|
||||
<item name="android:minHeight">20dp</item>
|
||||
<item name="android:padding">0dp</item>
|
||||
<item name="android:maxLines">10</item>
|
||||
<item name="android:minHeight">40dp</item>
|
||||
<item name="android:paddingTop">10dp</item>
|
||||
<item name="android:paddingBottom">10dp</item>
|
||||
<item name="paddingStart">12dp</item>
|
||||
<item name="android:clipToPadding">false</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="android:textColor">?vctr_message_text_color</item>
|
||||
</style>
|
||||
|
|
|
@ -100,8 +100,8 @@ class FlowRoom(private val room: Room) {
|
|||
return room.readService().getReadMarkerLive().asFlow()
|
||||
}
|
||||
|
||||
fun liveReadReceipt(): Flow<Optional<String>> {
|
||||
return room.readService().getMyReadReceiptLive().asFlow()
|
||||
fun liveReadReceipt(threadId: String?): Flow<Optional<String>> {
|
||||
return room.readService().getMyReadReceiptLive(threadId).asFlow()
|
||||
}
|
||||
|
||||
fun liveEventReadReceipts(eventId: String): Flow<List<ReadReceipt>> {
|
||||
|
|
|
@ -62,7 +62,7 @@ android {
|
|||
// that the app's state is completely cleared between tests.
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
|
||||
buildConfigField "String", "SDK_VERSION", "\"1.5.8\""
|
||||
buildConfigField "String", "SDK_VERSION", "\"1.5.10\""
|
||||
|
||||
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
|
||||
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""
|
||||
|
|
Binary file not shown.
|
@ -50,6 +50,7 @@ import org.matrix.android.sdk.api.session.room.send.SendState
|
|||
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
@ -346,6 +347,10 @@ class CommonTestHelper internal constructor(context: Context, val cryptoConfig:
|
|||
assertTrue(registrationResult is RegistrationResult.Success)
|
||||
val session = (registrationResult as RegistrationResult.Success).session
|
||||
session.open()
|
||||
session.filterService().setSyncFilter(
|
||||
SyncFilterBuilder()
|
||||
.lazyLoadMembersForStateEvents(true)
|
||||
)
|
||||
if (sessionTestParams.withInitialSync) {
|
||||
syncSession(session, 120_000)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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.internal.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import io.realm.Realm
|
||||
import org.amshove.kluent.fail
|
||||
import org.amshove.kluent.shouldBe
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.amshove.kluent.shouldNotBe
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
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.internal.database.mapper.EventMapper
|
||||
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.SessionRealmModule
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.util.Normalizer
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class RealmSessionStoreMigration43Test {
|
||||
|
||||
@get:Rule val configurationFactory = TestRealmConfigurationFactory()
|
||||
|
||||
lateinit var context: Context
|
||||
var realm: Realm? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context = InstrumentationRegistry.getInstrumentation().context
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
realm?.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrationShouldBeNeeed() {
|
||||
val realmName = "session_42.realm"
|
||||
val realmConfiguration = configurationFactory.createConfiguration(
|
||||
realmName,
|
||||
"efa9ab2c77ae06b0e767ffdb1c45b12be3c77d48d94f1ac41a7cd1d637fc59ac41f869a250453074e21ce13cfe7ed535593e7d150c08ce2bad7a2ab8c7b841f0",
|
||||
SessionRealmModule(),
|
||||
43,
|
||||
null
|
||||
)
|
||||
configurationFactory.copyRealmFromAssets(context, realmName, realmName)
|
||||
|
||||
try {
|
||||
realm = Realm.getInstance(realmConfiguration)
|
||||
fail("Should need a migration")
|
||||
} catch (failure: Throwable) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
// Database key for alias `session_db_e00482619b2597069b1f192b86de7da9`: efa9ab2c77ae06b0e767ffdb1c45b12be3c77d48d94f1ac41a7cd1d637fc59ac41f869a250453074e21ce13cfe7ed535593e7d150c08ce2bad7a2ab8c7b841f0
|
||||
// $WEJ8U6Zsx3TDZx3qmHIOKh-mXe5kqL_MnPcIkStEwwI
|
||||
// $11EtAQ8RYcudJVtw7e6B5Vm4ufCqKTOWKblY2U_wrpo
|
||||
@Test
|
||||
fun testMigration43() {
|
||||
val realmName = "session_42.realm"
|
||||
val migration = RealmSessionStoreMigration(Normalizer())
|
||||
val realmConfiguration = configurationFactory.createConfiguration(
|
||||
realmName,
|
||||
"efa9ab2c77ae06b0e767ffdb1c45b12be3c77d48d94f1ac41a7cd1d637fc59ac41f869a250453074e21ce13cfe7ed535593e7d150c08ce2bad7a2ab8c7b841f0",
|
||||
SessionRealmModule(),
|
||||
43,
|
||||
migration
|
||||
)
|
||||
configurationFactory.copyRealmFromAssets(context, realmName, realmName)
|
||||
|
||||
realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
// assert that the edit from 42 are migrated
|
||||
val editions = EventAnnotationsSummaryEntity
|
||||
.where(realm!!, "\$WEJ8U6Zsx3TDZx3qmHIOKh-mXe5kqL_MnPcIkStEwwI")
|
||||
.findFirst()
|
||||
?.editSummary
|
||||
?.editions
|
||||
|
||||
editions shouldNotBe null
|
||||
editions!!.size shouldBe 1
|
||||
val firstEdition = editions.first()
|
||||
firstEdition?.eventId shouldBeEqualTo "\$DvOyA8vJxwGfTaJG3OEJVcL4isShyaVDnprihy38W28"
|
||||
firstEdition?.isLocalEcho shouldBeEqualTo false
|
||||
|
||||
val editEvent = EventMapper.map(firstEdition!!.event!!)
|
||||
val body = editEvent.content.toModel<MessageContent>()?.body
|
||||
body shouldBeEqualTo "* Message 2 with edit"
|
||||
|
||||
// assert that the edit from 42 are migrated
|
||||
val editionsOfE2E = EventAnnotationsSummaryEntity
|
||||
.where(realm!!, "\$11EtAQ8RYcudJVtw7e6B5Vm4ufCqKTOWKblY2U_wrpo")
|
||||
.findFirst()
|
||||
?.editSummary
|
||||
?.editions
|
||||
|
||||
editionsOfE2E shouldNotBe null
|
||||
editionsOfE2E!!.size shouldBe 1
|
||||
val firstEditionE2E = editionsOfE2E.first()
|
||||
firstEditionE2E?.eventId shouldBeEqualTo "\$HUwJOQRCJwfPv7XSKvBPcvncjM0oR3q2tGIIIdv9Zts"
|
||||
firstEditionE2E?.isLocalEcho shouldBeEqualTo false
|
||||
|
||||
val editEventE2E = EventMapper.map(firstEditionE2E!!.event!!)
|
||||
val body2 = editEventE2E.getClearContent().toModel<MessageContent>()?.body
|
||||
body2 shouldBeEqualTo "* Message 2, e2e edit"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2020 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.internal.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import io.realm.Realm
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.matrix.android.sdk.internal.database.model.SessionRealmModule
|
||||
import org.matrix.android.sdk.internal.util.Normalizer
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SessionSanityMigrationTest {
|
||||
|
||||
@get:Rule val configurationFactory = TestRealmConfigurationFactory()
|
||||
|
||||
lateinit var context: Context
|
||||
var realm: Realm? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context = InstrumentationRegistry.getInstrumentation().context
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
realm?.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sessionDatabaseShouldMigrateGracefully() {
|
||||
val realmName = "session_42.realm"
|
||||
val migration = RealmSessionStoreMigration(Normalizer())
|
||||
val realmConfiguration = configurationFactory.createConfiguration(
|
||||
realmName,
|
||||
"efa9ab2c77ae06b0e767ffdb1c45b12be3c77d48d94f1ac41a7cd1d637fc59ac41f869a250453074e21ce13cfe7ed535593e7d150c08ce2bad7a2ab8c7b841f0",
|
||||
SessionRealmModule(),
|
||||
migration.schemaVersion,
|
||||
migration
|
||||
)
|
||||
configurationFactory.copyRealmFromAssets(context, realmName, realmName)
|
||||
|
||||
realm = Realm.getInstance(realmConfiguration)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* 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.internal.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmMigration
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.lang.IllegalStateException
|
||||
import java.util.Collections
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.Throws
|
||||
|
||||
/**
|
||||
* Based on https://github.com/realm/realm-java/blob/master/realm/realm-library/src/testUtils/java/io/realm/TestRealmConfigurationFactory.java
|
||||
*/
|
||||
class TestRealmConfigurationFactory : TemporaryFolder() {
|
||||
private val map: Map<RealmConfiguration, Boolean> = ConcurrentHashMap()
|
||||
private val configurations = Collections.newSetFromMap(map)
|
||||
@get:Synchronized private var isUnitTestFailed = false
|
||||
private var testName = ""
|
||||
private var tempFolder: File? = null
|
||||
|
||||
override fun apply(base: Statement, description: Description): Statement {
|
||||
return object : Statement() {
|
||||
@Throws(Throwable::class)
|
||||
override fun evaluate() {
|
||||
setTestName(description)
|
||||
before()
|
||||
try {
|
||||
base.evaluate()
|
||||
} catch (throwable: Throwable) {
|
||||
setUnitTestFailed()
|
||||
throw throwable
|
||||
} finally {
|
||||
after()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
override fun before() {
|
||||
Realm.init(InstrumentationRegistry.getInstrumentation().targetContext)
|
||||
super.before()
|
||||
}
|
||||
|
||||
override fun after() {
|
||||
try {
|
||||
for (configuration in configurations) {
|
||||
Realm.deleteRealm(configuration)
|
||||
}
|
||||
} catch (e: IllegalStateException) {
|
||||
// Only throws the exception caused by deleting the opened Realm if the test case itself doesn't throw.
|
||||
if (!isUnitTestFailed) {
|
||||
throw e
|
||||
}
|
||||
} finally {
|
||||
// This will delete the temp directory.
|
||||
super.after()
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun create() {
|
||||
super.create()
|
||||
tempFolder = File(super.getRoot(), testName)
|
||||
check(!(tempFolder!!.exists() && !tempFolder!!.delete())) { "Could not delete folder: " + tempFolder!!.absolutePath }
|
||||
check(tempFolder!!.mkdir()) { "Could not create folder: " + tempFolder!!.absolutePath }
|
||||
}
|
||||
|
||||
override fun getRoot(): File {
|
||||
checkNotNull(tempFolder) { "the temporary folder has not yet been created" }
|
||||
return tempFolder!!
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called in the [.apply].
|
||||
*/
|
||||
protected fun setTestName(description: Description) {
|
||||
testName = description.displayName
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun setUnitTestFailed() {
|
||||
isUnitTestFailed = true
|
||||
}
|
||||
|
||||
// This builder creates a configuration that is *NOT* managed.
|
||||
// You have to delete it yourself.
|
||||
private fun createConfigurationBuilder(): RealmConfiguration.Builder {
|
||||
return RealmConfiguration.Builder().directory(root)
|
||||
}
|
||||
|
||||
fun String.decodeHex(): ByteArray {
|
||||
check(length % 2 == 0) { "Must have an even length" }
|
||||
return chunked(2)
|
||||
.map { it.toInt(16).toByte() }
|
||||
.toByteArray()
|
||||
}
|
||||
|
||||
fun createConfiguration(
|
||||
name: String,
|
||||
key: String?,
|
||||
module: Any,
|
||||
schemaVersion: Long,
|
||||
migration: RealmMigration?
|
||||
): RealmConfiguration {
|
||||
val builder = createConfigurationBuilder()
|
||||
builder
|
||||
.directory(root)
|
||||
.name(name)
|
||||
.apply {
|
||||
if (key != null) {
|
||||
encryptionKey(key.decodeHex())
|
||||
}
|
||||
}
|
||||
.modules(module)
|
||||
// Allow writes on UI
|
||||
.allowWritesOnUiThread(true)
|
||||
.schemaVersion(schemaVersion)
|
||||
.apply {
|
||||
migration?.let { migration(it) }
|
||||
}
|
||||
val configuration = builder.build()
|
||||
configurations.add(configuration)
|
||||
return configuration
|
||||
}
|
||||
|
||||
// Copies a Realm file from assets to temp dir
|
||||
@Throws(IOException::class)
|
||||
fun copyRealmFromAssets(context: Context, realmPath: String, newName: String) {
|
||||
val config = RealmConfiguration.Builder()
|
||||
.directory(root)
|
||||
.name(newName)
|
||||
.build()
|
||||
copyRealmFromAssets(context, realmPath, config)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun copyRealmFromAssets(context: Context, realmPath: String, config: RealmConfiguration) {
|
||||
check(!File(config.path).exists()) { String.format(Locale.ENGLISH, "%s exists!", config.path) }
|
||||
val outFile = File(config.realmDirectory, config.realmFileName)
|
||||
copyFileFromAssets(context, realmPath, outFile)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun copyFileFromAssets(context: Context, assetPath: String?, outFile: File?) {
|
||||
var stream: InputStream? = null
|
||||
var os: FileOutputStream? = null
|
||||
try {
|
||||
stream = context.assets.open(assetPath!!)
|
||||
os = FileOutputStream(outFile)
|
||||
val buf = ByteArray(1024)
|
||||
var bytesRead: Int
|
||||
while (stream.read(buf).also { bytesRead = it } > -1) {
|
||||
os.write(buf, 0, bytesRead)
|
||||
}
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close()
|
||||
} catch (ignore: IOException) {
|
||||
}
|
||||
}
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close()
|
||||
} catch (ignore: IOException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,7 +66,7 @@ class PollAggregationTest : InstrumentedTest {
|
|||
|
||||
val aliceEventsListener = object : Timeline.Listener {
|
||||
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
|
||||
snapshot.firstOrNull { it.root.getClearType() in EventType.POLL_START }?.let { pollEvent ->
|
||||
snapshot.firstOrNull { it.root.getClearType() in EventType.POLL_START.values }?.let { pollEvent ->
|
||||
val pollEventId = pollEvent.eventId
|
||||
val pollContent = pollEvent.root.content?.toModel<MessagePollContent>()
|
||||
val pollSummary = pollEvent.annotations?.pollResponseSummary
|
||||
|
|
|
@ -38,5 +38,4 @@ data class AggregatedAnnotation(
|
|||
override val limited: Boolean? = false,
|
||||
override val count: Int? = 0,
|
||||
val chunk: List<RelationChunkInfo>? = null
|
||||
|
||||
) : UnsignedRelationInfo
|
||||
|
|
|
@ -19,7 +19,8 @@ import com.squareup.moshi.Json
|
|||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* <code>
|
||||
* Server side relation aggregation.
|
||||
* ```
|
||||
* {
|
||||
* "m.annotation": {
|
||||
* "chunk": [
|
||||
|
@ -43,12 +44,13 @@ import com.squareup.moshi.JsonClass
|
|||
* "count": 1
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* ```
|
||||
*/
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class AggregatedRelations(
|
||||
@Json(name = "m.annotation") val annotations: AggregatedAnnotation? = null,
|
||||
@Json(name = "m.reference") val references: DefaultUnsignedRelationInfo? = null,
|
||||
@Json(name = "m.replace") val replaces: AggregatedReplace? = null,
|
||||
@Json(name = RelationType.THREAD) val latestThread: LatestThreadUnsignedRelation? = null
|
||||
)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.events.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* Note that there can be multiple events with an m.replace relationship to a given event (for example, if an event is edited multiple times).
|
||||
* These should be aggregated by the homeserver.
|
||||
* https://spec.matrix.org/v1.4/client-server-api/#server-side-aggregation-of-mreplace-relationships
|
||||
*
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class AggregatedReplace(
|
||||
@Json(name = "event_id") val eventId: String? = null,
|
||||
@Json(name = "origin_server_ts") val originServerTs: Long? = null,
|
||||
@Json(name = "sender") val senderId: String? = null,
|
||||
)
|
|
@ -26,13 +26,12 @@ import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
|
|||
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||
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.isReply
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.shouldRenderInThread
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.api.session.threads.ThreadDetails
|
||||
|
@ -228,11 +227,14 @@ data class Event(
|
|||
return when {
|
||||
isReplyRenderedInThread() || isQuote() -> ContentUtils.extractUsefulTextFromReply(text)
|
||||
isFileMessage() -> "sent a file."
|
||||
isVoiceMessage() -> "sent a voice message."
|
||||
isAudioMessage() -> "sent an audio file."
|
||||
isImageMessage() -> "sent an image."
|
||||
isVideoMessage() -> "sent a video."
|
||||
isSticker() -> "sent a sticker"
|
||||
isSticker() -> "sent a sticker."
|
||||
isPoll() -> getPollQuestion() ?: "created a poll."
|
||||
isLiveLocation() -> "Live location."
|
||||
isLocationMessage() -> "has shared their location."
|
||||
else -> text
|
||||
}
|
||||
}
|
||||
|
@ -386,24 +388,18 @@ fun Event.isLocationMessage(): Boolean {
|
|||
}
|
||||
}
|
||||
|
||||
fun Event.isPoll(): Boolean = getClearType() in EventType.POLL_START || getClearType() in EventType.POLL_END
|
||||
fun Event.isPoll(): Boolean = getClearType() in EventType.POLL_START.values || getClearType() in EventType.POLL_END.values
|
||||
|
||||
fun Event.isSticker(): Boolean = getClearType() == EventType.STICKER
|
||||
|
||||
fun Event.isLiveLocation(): Boolean = getClearType() in EventType.STATE_ROOM_BEACON_INFO
|
||||
fun Event.isLiveLocation(): Boolean = getClearType() in EventType.STATE_ROOM_BEACON_INFO.values
|
||||
|
||||
fun Event.getRelationContent(): RelationDefaultContent? {
|
||||
return if (isEncrypted()) {
|
||||
content.toModel<EncryptedEventContent>()?.relatesTo
|
||||
} else {
|
||||
content.toModel<MessageContent>()?.relatesTo ?: run {
|
||||
// Special cases when there is only a local msgtype for some event types
|
||||
when (getClearType()) {
|
||||
EventType.STICKER -> getClearContent().toModel<MessageStickerContent>()?.relatesTo
|
||||
in EventType.BEACON_LOCATION_DATA -> getClearContent().toModel<MessageBeaconLocationDataContent>()?.relatesTo
|
||||
else -> getClearContent()?.get("m.relates_to")?.toContent().toModel()
|
||||
}
|
||||
}
|
||||
content.toModel<MessageContent>()?.relatesTo
|
||||
?: getClearContent()?.get("m.relates_to")?.toContent().toModel() // Special cases when there is only a local msgtype for some event types
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,7 +416,7 @@ fun Event.getRelationContentForType(type: String): RelationDefaultContent? =
|
|||
getRelationContent()?.takeIf { it.type == type }
|
||||
|
||||
fun Event.isReply(): Boolean {
|
||||
return getRelationContent()?.inReplyTo?.eventId != null
|
||||
return getRelationContent().isReply()
|
||||
}
|
||||
|
||||
fun Event.isReplyRenderedInThread(): Boolean {
|
||||
|
@ -443,11 +439,11 @@ fun Event.isInvitation(): Boolean = type == EventType.STATE_ROOM_MEMBER &&
|
|||
content?.toModel<RoomMemberContent>()?.membership == Membership.INVITE
|
||||
|
||||
fun Event.getPollContent(): MessagePollContent? {
|
||||
return content.toModel<MessagePollContent>()
|
||||
return getClearContent().toModel<MessagePollContent>()
|
||||
}
|
||||
|
||||
fun Event.supportsNotification() =
|
||||
this.getClearType() in EventType.MESSAGE + EventType.POLL_START + EventType.STATE_ROOM_BEACON_INFO
|
||||
this.getClearType() in EventType.MESSAGE + EventType.POLL_START.values + EventType.STATE_ROOM_BEACON_INFO.values
|
||||
|
||||
fun Event.isContentReportable() =
|
||||
this.getClearType() in EventType.MESSAGE + EventType.STATE_ROOM_BEACON_INFO
|
||||
this.getClearType() in EventType.MESSAGE + EventType.STATE_ROOM_BEACON_INFO.values
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.events.model
|
||||
|
||||
fun Event.toValidDecryptedEvent(): ValidDecryptedEvent? {
|
||||
if (!this.isEncrypted()) return null
|
||||
val decryptedContent = this.getDecryptedContent() ?: return null
|
||||
val eventId = this.eventId ?: return null
|
||||
val roomId = this.roomId ?: return null
|
||||
val type = this.getDecryptedType() ?: return null
|
||||
val senderKey = this.getSenderKey() ?: return null
|
||||
val algorithm = this.content?.get("algorithm") as? String ?: return null
|
||||
|
||||
// copy the relation as it's in clear in the encrypted content
|
||||
val updatedContent = this.content.get("m.relates_to")?.let {
|
||||
decryptedContent.toMutableMap().apply {
|
||||
put("m.relates_to", it)
|
||||
}
|
||||
} ?: decryptedContent
|
||||
return ValidDecryptedEvent(
|
||||
type = type,
|
||||
eventId = eventId,
|
||||
clearContent = updatedContent,
|
||||
prevContent = this.prevContent,
|
||||
originServerTs = this.originServerTs ?: 0,
|
||||
cryptoSenderKey = senderKey,
|
||||
roomId = roomId,
|
||||
unsignedData = this.unsignedData,
|
||||
redacts = this.redacts,
|
||||
algorithm = algorithm
|
||||
)
|
||||
}
|
|
@ -49,11 +49,10 @@ object EventType {
|
|||
const val STATE_ROOM_JOIN_RULES = "m.room.join_rules"
|
||||
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
|
||||
const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels"
|
||||
val STATE_ROOM_BEACON_INFO = listOf("org.matrix.msc3672.beacon_info", "m.beacon_info")
|
||||
val BEACON_LOCATION_DATA = listOf("org.matrix.msc3672.beacon", "m.beacon")
|
||||
val STATE_ROOM_BEACON_INFO = StableUnstableId(stable = "m.beacon_info", unstable = "org.matrix.msc3672.beacon_info")
|
||||
val BEACON_LOCATION_DATA = StableUnstableId(stable = "m.beacon", unstable = "org.matrix.msc3672.beacon")
|
||||
|
||||
const val STATE_SPACE_CHILD = "m.space.child"
|
||||
|
||||
const val STATE_SPACE_PARENT = "m.space.parent"
|
||||
|
||||
/**
|
||||
|
@ -81,8 +80,7 @@ object EventType {
|
|||
const val CALL_NEGOTIATE = "m.call.negotiate"
|
||||
const val CALL_REJECT = "m.call.reject"
|
||||
const val CALL_HANGUP = "m.call.hangup"
|
||||
const val CALL_ASSERTED_IDENTITY = "m.call.asserted_identity"
|
||||
const val CALL_ASSERTED_IDENTITY_PREFIX = "org.matrix.call.asserted_identity"
|
||||
val CALL_ASSERTED_IDENTITY = StableUnstableId(stable = "m.call.asserted_identity", unstable = "org.matrix.call.asserted_identity")
|
||||
|
||||
// This type is not processed by the client, just sent to the server
|
||||
const val CALL_REPLACES = "m.call.replaces"
|
||||
|
@ -90,10 +88,7 @@ object EventType {
|
|||
// Key share events
|
||||
const val ROOM_KEY_REQUEST = "m.room_key_request"
|
||||
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"
|
||||
val ROOM_KEY_WITHHELD = StableUnstableId(
|
||||
stable = "m.room_key.withheld",
|
||||
unstable = "org.matrix.room_key.withheld"
|
||||
)
|
||||
val ROOM_KEY_WITHHELD = StableUnstableId(stable = "m.room_key.withheld", unstable = "org.matrix.room_key.withheld")
|
||||
|
||||
const val REQUEST_SECRET = "m.secret.request"
|
||||
const val SEND_SECRET = "m.secret.send"
|
||||
|
@ -111,9 +106,9 @@ object EventType {
|
|||
const val REACTION = "m.reaction"
|
||||
|
||||
// Poll
|
||||
val POLL_START = listOf("org.matrix.msc3381.poll.start", "m.poll.start")
|
||||
val POLL_RESPONSE = listOf("org.matrix.msc3381.poll.response", "m.poll.response")
|
||||
val POLL_END = listOf("org.matrix.msc3381.poll.end", "m.poll.end")
|
||||
val POLL_START = StableUnstableId(stable = "m.poll.start", unstable = "org.matrix.msc3381.poll.start")
|
||||
val POLL_RESPONSE = StableUnstableId(stable = "m.poll.response", unstable = "org.matrix.msc3381.poll.response")
|
||||
val POLL_END = StableUnstableId(stable = "m.poll.end", unstable = "org.matrix.msc3381.poll.end")
|
||||
|
||||
// Emotes
|
||||
const val ROOM_EMOTES = "im.ponies.room_emotes"
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.events.model
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||
|
||||
data class ValidDecryptedEvent(
|
||||
val type: String,
|
||||
val eventId: String,
|
||||
val clearContent: Content,
|
||||
val prevContent: Content? = null,
|
||||
val originServerTs: Long,
|
||||
val cryptoSenderKey: String,
|
||||
val roomId: String,
|
||||
val unsignedData: UnsignedData? = null,
|
||||
val redacts: String? = null,
|
||||
val algorithm: String,
|
||||
)
|
||||
|
||||
fun ValidDecryptedEvent.getRelationContent(): RelationDefaultContent? {
|
||||
return clearContent.toModel<MessageRelationContent?>()?.relatesTo
|
||||
}
|
|
@ -47,10 +47,9 @@ interface LocationSharingService {
|
|||
/**
|
||||
* Starts sharing live location in the room.
|
||||
* @param timeoutMillis timeout of the live in milliseconds
|
||||
* @param description description of the live for text fallback
|
||||
* @return the result of the update of the live
|
||||
*/
|
||||
suspend fun startLiveLocationShare(timeoutMillis: Long, description: String): UpdateLiveLocationShareResult
|
||||
suspend fun startLiveLocationShare(timeoutMillis: Long): UpdateLiveLocationShareResult
|
||||
|
||||
/**
|
||||
* Stops sharing live location in the room.
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
package org.matrix.android.sdk.api.session.room.model
|
||||
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
|
||||
data class EditAggregatedSummary(
|
||||
val latestContent: Content? = null,
|
||||
val latestEdit: Event? = null,
|
||||
// The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk)
|
||||
val sourceEvents: List<String>,
|
||||
val localEchos: List<String>,
|
||||
|
|
|
@ -18,5 +18,6 @@ package org.matrix.android.sdk.api.session.room.model
|
|||
|
||||
data class ReadReceipt(
|
||||
val roomMember: RoomMemberSummary,
|
||||
val originServerTs: Long
|
||||
val originServerTs: Long,
|
||||
val threadId: String?
|
||||
)
|
||||
|
|
|
@ -34,7 +34,7 @@ data class MessageStickerContent(
|
|||
* Required. A textual representation of the image. This could be the alt text of the image, the filename of the image,
|
||||
* or some kind of content description for accessibility e.g. 'image attachment'.
|
||||
*/
|
||||
@Json(name = "body") override val body: String,
|
||||
@Json(name = "body") override val body: String = "",
|
||||
|
||||
/**
|
||||
* Metadata about the image referred to in url.
|
||||
|
|
|
@ -28,3 +28,5 @@ data class RelationDefaultContent(
|
|||
) : RelationContent
|
||||
|
||||
fun RelationDefaultContent.shouldRenderInThread(): Boolean = isFallingBack == false
|
||||
|
||||
fun RelationDefaultContent?.isReply(): Boolean = this?.inReplyTo?.eventId != null
|
||||
|
|
|
@ -34,12 +34,14 @@ interface ReadService {
|
|||
/**
|
||||
* Force the read marker to be set on the latest event.
|
||||
*/
|
||||
suspend fun markAsRead(params: MarkAsReadParams = MarkAsReadParams.BOTH)
|
||||
suspend fun markAsRead(params: MarkAsReadParams = MarkAsReadParams.BOTH, mainTimeLineOnly: Boolean = true)
|
||||
|
||||
/**
|
||||
* Set the read receipt on the event with provided eventId.
|
||||
* @param eventId the id of the event where read receipt will be set
|
||||
* @param threadId the id of the thread in which read receipt will be set. For main thread use [ReadService.THREAD_ID_MAIN] constant
|
||||
*/
|
||||
suspend fun setReadReceipt(eventId: String)
|
||||
suspend fun setReadReceipt(eventId: String, threadId: String)
|
||||
|
||||
/**
|
||||
* Set the read marker on the event with provided eventId.
|
||||
|
@ -69,10 +71,10 @@ interface ReadService {
|
|||
/**
|
||||
* Returns a live read receipt id for the room.
|
||||
*/
|
||||
fun getMyReadReceiptLive(): LiveData<Optional<String>>
|
||||
fun getMyReadReceiptLive(threadId: String?): LiveData<Optional<String>>
|
||||
|
||||
/**
|
||||
* Get the eventId where the read receipt for the provided user is.
|
||||
* Get the eventId from the main timeline where the read receipt for the provided user is.
|
||||
* @param userId the id of the user to look for
|
||||
*
|
||||
* @return the eventId where the read receipt for the provided user is attached, or null if not found
|
||||
|
@ -84,4 +86,8 @@ interface ReadService {
|
|||
* @param eventId the event
|
||||
*/
|
||||
fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>>
|
||||
|
||||
companion object {
|
||||
const val THREAD_ID_MAIN = "main"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,9 @@ object RoomSummaryConstants {
|
|||
EventType.ENCRYPTED,
|
||||
EventType.STICKER,
|
||||
EventType.REACTION,
|
||||
) + EventType.POLL_START + EventType.STATE_ROOM_BEACON_INFO
|
||||
) +
|
||||
EventType.POLL_START.values +
|
||||
EventType.STATE_ROOM_BEACON_INFO.values
|
||||
|
||||
// SC addition | this is the Element behaviour previous to Element v1.0.7
|
||||
val PREVIEWABLE_TYPES_ALL = listOf(
|
||||
|
@ -53,7 +55,9 @@ object RoomSummaryConstants {
|
|||
EventType.STICKER,
|
||||
EventType.REACTION,
|
||||
EventType.STATE_ROOM_CREATE
|
||||
) + EventType.POLL_START + EventType.STATE_ROOM_BEACON_INFO
|
||||
) +
|
||||
EventType.POLL_START.values +
|
||||
EventType.STATE_ROOM_BEACON_INFO.values
|
||||
|
||||
// SC addition | no reactions in here
|
||||
val PREVIEWABLE_ORIGINAL_CONTENT_TYPES = listOf(
|
||||
|
@ -64,5 +68,7 @@ object RoomSummaryConstants {
|
|||
EventType.CALL_ANSWER,
|
||||
EventType.ENCRYPTED,
|
||||
EventType.STICKER
|
||||
) + EventType.POLL_START + EventType.STATE_ROOM_BEACON_INFO
|
||||
) +
|
||||
EventType.POLL_START.values +
|
||||
EventType.STATE_ROOM_BEACON_INFO.values
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.room.timeline
|
|||
|
||||
import org.matrix.android.sdk.BuildConfig
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
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.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.RelationType
|
||||
|
@ -143,13 +144,21 @@ fun TimelineEvent.getEditedEventId(): String? {
|
|||
fun TimelineEvent.getLastMessageContent(): MessageContent? {
|
||||
return when (root.getClearType()) {
|
||||
EventType.STICKER -> root.getClearContent().toModel<MessageStickerContent>()
|
||||
in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>()
|
||||
in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconInfoContent>()
|
||||
in EventType.BEACON_LOCATION_DATA -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconLocationDataContent>()
|
||||
else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
|
||||
// XXX
|
||||
// Polls/Beacon are not message contents like others as there is no msgtype subtype to discriminate moshi parsing
|
||||
// so toModel<MessageContent> won't parse them correctly
|
||||
// It's discriminated on event type instead. Maybe it shouldn't be MessageContent at all to avoid confusion?
|
||||
in EventType.POLL_START.values -> (getLastEditNewContent() ?: root.getClearContent()).toModel<MessagePollContent>()
|
||||
in EventType.STATE_ROOM_BEACON_INFO.values -> (getLastEditNewContent() ?: root.getClearContent()).toModel<MessageBeaconInfoContent>()
|
||||
in EventType.BEACON_LOCATION_DATA.values -> (getLastEditNewContent() ?: root.getClearContent()).toModel<MessageBeaconLocationDataContent>()
|
||||
else -> (getLastEditNewContent() ?: root.getClearContent()).toModel()
|
||||
}
|
||||
}
|
||||
|
||||
fun TimelineEvent.getLastEditNewContent(): Content? {
|
||||
return annotations?.editSummary?.latestEdit?.getClearContent()?.toModel<MessageContent>()?.newContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if it's a reply.
|
||||
*/
|
||||
|
|
|
@ -16,19 +16,12 @@
|
|||
|
||||
package org.matrix.android.sdk.api.session.sync
|
||||
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
|
||||
interface FilterService {
|
||||
|
||||
enum class FilterPreset {
|
||||
NoFilter,
|
||||
|
||||
/**
|
||||
* Filter for Element, will include only known event type.
|
||||
*/
|
||||
ElementFilter
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the filter for the sync.
|
||||
*/
|
||||
fun setFilter(filterPreset: FilterPreset)
|
||||
suspend fun setSyncFilter(filterBuilder: SyncFilterBuilder)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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.sync.filter
|
||||
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
import org.matrix.android.sdk.internal.session.filter.Filter
|
||||
import org.matrix.android.sdk.internal.session.filter.RoomEventFilter
|
||||
import org.matrix.android.sdk.internal.session.filter.RoomFilter
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
|
||||
class SyncFilterBuilder {
|
||||
private var lazyLoadMembersForStateEvents: Boolean? = null
|
||||
private var lazyLoadMembersForMessageEvents: Boolean? = null
|
||||
private var useThreadNotifications: Boolean? = null
|
||||
private var listOfSupportedEventTypes: List<String>? = null
|
||||
private var listOfSupportedStateEventTypes: List<String>? = null
|
||||
|
||||
fun lazyLoadMembersForStateEvents(lazyLoadMembersForStateEvents: Boolean) = apply { this.lazyLoadMembersForStateEvents = lazyLoadMembersForStateEvents }
|
||||
|
||||
fun lazyLoadMembersForMessageEvents(lazyLoadMembersForMessageEvents: Boolean) =
|
||||
apply { this.lazyLoadMembersForMessageEvents = lazyLoadMembersForMessageEvents }
|
||||
|
||||
fun useThreadNotifications(useThreadNotifications: Boolean) =
|
||||
apply { this.useThreadNotifications = useThreadNotifications }
|
||||
|
||||
fun listOfSupportedStateEventTypes(listOfSupportedStateEventTypes: List<String>) =
|
||||
apply { this.listOfSupportedStateEventTypes = listOfSupportedStateEventTypes }
|
||||
|
||||
fun listOfSupportedTimelineEventTypes(listOfSupportedEventTypes: List<String>) =
|
||||
apply { this.listOfSupportedEventTypes = listOfSupportedEventTypes }
|
||||
|
||||
internal fun with(currentFilterParams: SyncFilterParams?) =
|
||||
apply {
|
||||
currentFilterParams?.let {
|
||||
useThreadNotifications = currentFilterParams.useThreadNotifications
|
||||
lazyLoadMembersForMessageEvents = currentFilterParams.lazyLoadMembersForMessageEvents
|
||||
lazyLoadMembersForStateEvents = currentFilterParams.lazyLoadMembersForStateEvents
|
||||
listOfSupportedEventTypes = currentFilterParams.listOfSupportedEventTypes?.toList()
|
||||
listOfSupportedStateEventTypes = currentFilterParams.listOfSupportedStateEventTypes?.toList()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun extractParams(): SyncFilterParams {
|
||||
return SyncFilterParams(
|
||||
useThreadNotifications = useThreadNotifications,
|
||||
lazyLoadMembersForMessageEvents = lazyLoadMembersForMessageEvents,
|
||||
lazyLoadMembersForStateEvents = lazyLoadMembersForStateEvents,
|
||||
listOfSupportedEventTypes = listOfSupportedEventTypes,
|
||||
listOfSupportedStateEventTypes = listOfSupportedStateEventTypes,
|
||||
)
|
||||
}
|
||||
|
||||
internal fun build(homeServerCapabilities: HomeServerCapabilities): Filter {
|
||||
return Filter(
|
||||
room = buildRoomFilter(homeServerCapabilities)
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildRoomFilter(homeServerCapabilities: HomeServerCapabilities): RoomFilter {
|
||||
return RoomFilter(
|
||||
timeline = buildTimelineFilter(homeServerCapabilities),
|
||||
state = buildStateFilter()
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildTimelineFilter(homeServerCapabilities: HomeServerCapabilities): RoomEventFilter? {
|
||||
val resolvedUseThreadNotifications = if (homeServerCapabilities.canUseThreadReadReceiptsAndNotifications) {
|
||||
useThreadNotifications
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return RoomEventFilter(
|
||||
enableUnreadThreadNotifications = resolvedUseThreadNotifications,
|
||||
lazyLoadMembers = lazyLoadMembersForMessageEvents
|
||||
).orNullIfEmpty()
|
||||
}
|
||||
|
||||
private fun buildStateFilter(): RoomEventFilter? =
|
||||
RoomEventFilter(
|
||||
lazyLoadMembers = lazyLoadMembersForStateEvents,
|
||||
types = listOfSupportedStateEventTypes
|
||||
).orNullIfEmpty()
|
||||
|
||||
private fun RoomEventFilter.orNullIfEmpty(): RoomEventFilter? {
|
||||
return if (hasData()) {
|
||||
this
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as SyncFilterBuilder
|
||||
|
||||
if (lazyLoadMembersForStateEvents != other.lazyLoadMembersForStateEvents) return false
|
||||
if (lazyLoadMembersForMessageEvents != other.lazyLoadMembersForMessageEvents) return false
|
||||
if (useThreadNotifications != other.useThreadNotifications) return false
|
||||
if (listOfSupportedEventTypes != other.listOfSupportedEventTypes) return false
|
||||
if (listOfSupportedStateEventTypes != other.listOfSupportedStateEventTypes) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = lazyLoadMembersForStateEvents?.hashCode() ?: 0
|
||||
result = 31 * result + (lazyLoadMembersForMessageEvents?.hashCode() ?: 0)
|
||||
result = 31 * result + (useThreadNotifications?.hashCode() ?: 0)
|
||||
result = 31 * result + (listOfSupportedEventTypes?.hashCode() ?: 0)
|
||||
result = 31 * result + (listOfSupportedStateEventTypes?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -83,9 +83,7 @@ internal class CrossSigningOlm @Inject constructor(
|
|||
val signaturesMadeByMyKey = signatures[myUserID] // Signatures made by me
|
||||
?.get("ed25519:$pubKey")
|
||||
|
||||
if (signaturesMadeByMyKey.isNullOrBlank()) {
|
||||
throw IllegalArgumentException("Not signed with my key $type")
|
||||
}
|
||||
require(signaturesMadeByMyKey.orEmpty().isNotBlank()) { "Not signed with my key $type" }
|
||||
|
||||
// Check that Alice USK signature of Bob MSK is valid
|
||||
olmUtility.verifyEd25519Signature(signaturesMadeByMyKey, pubKey, JsonCanonicalizer.getCanonicalJson(Map::class.java, signable))
|
||||
|
|
|
@ -47,9 +47,8 @@ internal class DefaultEncryptEventTask @Inject constructor(
|
|||
// don't want to wait for any query
|
||||
// if (!params.crypto.isRoomEncrypted(params.roomId)) return params.event
|
||||
val localEvent = params.event
|
||||
if (localEvent.eventId == null || localEvent.type == null) {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
require(localEvent.eventId != null)
|
||||
require(localEvent.type != null)
|
||||
|
||||
localEchoRepository.updateSendState(localEvent.eventId, localEvent.roomId, SendState.ENCRYPTING)
|
||||
|
||||
|
|
|
@ -1140,28 +1140,25 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
override fun beginKeyVerification(method: VerificationMethod, otherUserId: String, otherDeviceId: String, transactionId: String?): String? {
|
||||
val txID = transactionId?.takeIf { it.isNotEmpty() } ?: createUniqueIDForTransaction(otherUserId, otherDeviceId)
|
||||
// should check if already one (and cancel it)
|
||||
if (method == VerificationMethod.SAS) {
|
||||
val tx = DefaultOutgoingSASDefaultVerificationTransaction(
|
||||
setDeviceVerificationAction,
|
||||
userId,
|
||||
deviceId,
|
||||
cryptoStore,
|
||||
crossSigningService,
|
||||
outgoingKeyRequestManager,
|
||||
secretShareManager,
|
||||
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
|
||||
txID,
|
||||
otherUserId,
|
||||
otherDeviceId
|
||||
)
|
||||
tx.transport = verificationTransportToDeviceFactory.createTransport(tx)
|
||||
addTransaction(tx)
|
||||
require(method == VerificationMethod.SAS) { "Unknown verification method" }
|
||||
val tx = DefaultOutgoingSASDefaultVerificationTransaction(
|
||||
setDeviceVerificationAction,
|
||||
userId,
|
||||
deviceId,
|
||||
cryptoStore,
|
||||
crossSigningService,
|
||||
outgoingKeyRequestManager,
|
||||
secretShareManager,
|
||||
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
|
||||
txID,
|
||||
otherUserId,
|
||||
otherDeviceId
|
||||
)
|
||||
tx.transport = verificationTransportToDeviceFactory.createTransport(tx)
|
||||
addTransaction(tx)
|
||||
|
||||
tx.start()
|
||||
return txID
|
||||
} else {
|
||||
throw IllegalArgumentException("Unknown verification method")
|
||||
}
|
||||
tx.start()
|
||||
return txID
|
||||
}
|
||||
|
||||
override fun requestKeyVerificationInDMs(
|
||||
|
@ -1343,28 +1340,25 @@ internal class DefaultVerificationService @Inject constructor(
|
|||
otherUserId: String,
|
||||
otherDeviceId: String
|
||||
): String {
|
||||
if (method == VerificationMethod.SAS) {
|
||||
val tx = DefaultOutgoingSASDefaultVerificationTransaction(
|
||||
setDeviceVerificationAction,
|
||||
userId,
|
||||
deviceId,
|
||||
cryptoStore,
|
||||
crossSigningService,
|
||||
outgoingKeyRequestManager,
|
||||
secretShareManager,
|
||||
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
|
||||
transactionId,
|
||||
otherUserId,
|
||||
otherDeviceId
|
||||
)
|
||||
tx.transport = verificationTransportRoomMessageFactory.createTransport(roomId, tx)
|
||||
addTransaction(tx)
|
||||
require(method == VerificationMethod.SAS) { "Unknown verification method" }
|
||||
val tx = DefaultOutgoingSASDefaultVerificationTransaction(
|
||||
setDeviceVerificationAction,
|
||||
userId,
|
||||
deviceId,
|
||||
cryptoStore,
|
||||
crossSigningService,
|
||||
outgoingKeyRequestManager,
|
||||
secretShareManager,
|
||||
myDeviceInfoHolder.get().myDevice.fingerprint()!!,
|
||||
transactionId,
|
||||
otherUserId,
|
||||
otherDeviceId
|
||||
)
|
||||
tx.transport = verificationTransportRoomMessageFactory.createTransport(roomId, tx)
|
||||
addTransaction(tx)
|
||||
|
||||
tx.start()
|
||||
return transactionId
|
||||
} else {
|
||||
throw IllegalArgumentException("Unknown verification method")
|
||||
}
|
||||
tx.start()
|
||||
return transactionId
|
||||
}
|
||||
|
||||
override fun readyPendingVerificationInDMs(
|
||||
|
|
|
@ -26,17 +26,17 @@ import kotlinx.coroutines.withContext
|
|||
import timber.log.Timber
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
internal fun <T> CoroutineScope.asyncTransaction(monarchy: Monarchy, transaction: suspend (realm: Realm) -> T) {
|
||||
internal fun <T> CoroutineScope.asyncTransaction(monarchy: Monarchy, transaction: (realm: Realm) -> T) {
|
||||
asyncTransaction(monarchy.realmConfiguration, transaction)
|
||||
}
|
||||
|
||||
internal fun <T> CoroutineScope.asyncTransaction(realmConfiguration: RealmConfiguration, transaction: suspend (realm: Realm) -> T) {
|
||||
internal fun <T> CoroutineScope.asyncTransaction(realmConfiguration: RealmConfiguration, transaction: (realm: Realm) -> T) {
|
||||
launch {
|
||||
awaitTransaction(realmConfiguration, transaction)
|
||||
}
|
||||
}
|
||||
|
||||
internal suspend fun <T> awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> T): T {
|
||||
internal suspend fun <T> awaitTransaction(config: RealmConfiguration, transaction: (realm: Realm) -> T): T {
|
||||
return withContext(Realm.WRITE_EXECUTOR.asCoroutineDispatcher()) {
|
||||
Realm.getInstance(config).use { bgRealm ->
|
||||
if (!bgRealm.isInTransaction) {
|
||||
|
|
|
@ -66,6 +66,9 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo039
|
|||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo040
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo041
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo042
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo043
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo044
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo045
|
||||
import org.matrix.android.sdk.internal.util.Normalizer
|
||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||
import timber.log.Timber
|
||||
|
@ -89,7 +92,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
private val scSchemaVersion = 7L
|
||||
private val scSchemaVersionOffset = (1L shl 12)
|
||||
|
||||
val schemaVersion = 42L +
|
||||
val schemaVersion = 45L +
|
||||
scSchemaVersion * scSchemaVersionOffset
|
||||
}
|
||||
|
||||
|
@ -148,6 +151,9 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
if (oldVersion < 40) MigrateSessionTo040(realm).perform()
|
||||
if (oldVersion < 41) MigrateSessionTo041(realm).perform()
|
||||
if (oldVersion < 42) MigrateSessionTo042(realm).perform()
|
||||
if (oldVersion < 43) MigrateSessionTo043(realm).perform()
|
||||
if (oldVersion < 44) MigrateSessionTo044(realm).perform()
|
||||
if (oldVersion < 45) MigrateSessionTo045(realm).perform()
|
||||
|
||||
if (oldScVersion <= 0) MigrateScSessionTo001(realm).perform()
|
||||
if (oldScVersion <= 1) MigrateScSessionTo002(realm).perform()
|
||||
|
|
|
@ -84,7 +84,6 @@ internal fun ChunkEntity.addTimelineEvent(
|
|||
this.eventId = eventId
|
||||
this.roomId = roomId
|
||||
this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst()
|
||||
?.also { it.cleanUp(eventEntity.sender) }
|
||||
this.readReceipts = readReceiptsSummaryEntity
|
||||
this.displayIndex = displayIndex
|
||||
this.ownedByThreadChunk = ownedByThreadChunk
|
||||
|
@ -134,7 +133,7 @@ private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventE
|
|||
val originServerTs = eventEntity.originServerTs
|
||||
if (originServerTs != null) {
|
||||
val timestampOfEvent = originServerTs.toDouble()
|
||||
val readReceiptOfSender = ReadReceiptEntity.getOrCreate(realm, roomId = roomId, userId = senderId)
|
||||
val readReceiptOfSender = ReadReceiptEntity.getOrCreate(realm, roomId = roomId, userId = senderId, threadId = eventEntity.rootThreadEventId)
|
||||
// If the synced RR is older, update
|
||||
if (timestampOfEvent > readReceiptOfSender.originServerTs) {
|
||||
val previousReceiptsSummary = ReadReceiptsSummaryEntity.where(realm, eventId = readReceiptOfSender.eventId).findFirst()
|
||||
|
|
|
@ -65,11 +65,11 @@ internal fun Map<String, EventEntity>.updateThreadSummaryIfNeeded(
|
|||
inThreadMessages = inThreadMessages,
|
||||
latestMessageTimelineEventEntity = latestEventInThread
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldUpdateNotifications) {
|
||||
updateNotificationsNew(roomId, realm, currentUserId)
|
||||
if (shouldUpdateNotifications) {
|
||||
updateThreadNotifications(roomId, realm, currentUserId, rootThreadEventId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,8 +273,8 @@ internal fun TimelineEventEntity.Companion.isUserMentionedInThread(realm: Realm,
|
|||
/**
|
||||
* Find the read receipt for the current user.
|
||||
*/
|
||||
internal fun findMyReadReceipt(realm: Realm, roomId: String, userId: String): String? =
|
||||
ReadReceiptEntity.where(realm, roomId = roomId, userId = userId)
|
||||
internal fun findMyReadReceipt(realm: Realm, roomId: String, userId: String, threadId: String?): String? =
|
||||
ReadReceiptEntity.where(realm, roomId = roomId, userId = userId, threadId = threadId)
|
||||
.findFirst()
|
||||
?.eventId
|
||||
|
||||
|
@ -293,28 +293,29 @@ internal fun isUserMentioned(currentUserId: String, timelineEventEntity: Timelin
|
|||
* Important: It will work only with the latest chunk, while read marker will be changed
|
||||
* immediately so we should not display wrong notifications
|
||||
*/
|
||||
internal fun updateNotificationsNew(roomId: String, realm: Realm, currentUserId: String) {
|
||||
val readReceipt = findMyReadReceipt(realm, roomId, currentUserId) ?: return
|
||||
internal fun updateThreadNotifications(roomId: String, realm: Realm, currentUserId: String, rootThreadEventId: String) {
|
||||
val readReceipt = findMyReadReceipt(realm, roomId, currentUserId, threadId = rootThreadEventId) ?: return
|
||||
|
||||
val readReceiptChunk = ChunkEntity
|
||||
.findIncludingEvent(realm, readReceipt) ?: return
|
||||
|
||||
val readReceiptChunkTimelineEvents = readReceiptChunk
|
||||
val readReceiptChunkThreadEvents = readReceiptChunk
|
||||
.timelineEvents
|
||||
.where()
|
||||
.equalTo(TimelineEventEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(TimelineEventEntityFields.ROOT.ROOT_THREAD_EVENT_ID, rootThreadEventId)
|
||||
.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING)
|
||||
.findAll() ?: return
|
||||
|
||||
val readReceiptChunkPosition = readReceiptChunkTimelineEvents.indexOfFirst { it.eventId == readReceipt }
|
||||
val readReceiptChunkPosition = readReceiptChunkThreadEvents.indexOfFirst { it.eventId == readReceipt }
|
||||
|
||||
if (readReceiptChunkPosition == -1) return
|
||||
|
||||
if (readReceiptChunkPosition < readReceiptChunkTimelineEvents.lastIndex) {
|
||||
if (readReceiptChunkPosition < readReceiptChunkThreadEvents.lastIndex) {
|
||||
// If the read receipt is found inside the chunk
|
||||
|
||||
val threadEventsAfterReadReceipt = readReceiptChunkTimelineEvents
|
||||
.slice(readReceiptChunkPosition..readReceiptChunkTimelineEvents.lastIndex)
|
||||
val threadEventsAfterReadReceipt = readReceiptChunkThreadEvents
|
||||
.slice(readReceiptChunkPosition..readReceiptChunkThreadEvents.lastIndex)
|
||||
.filter { it.root?.isThread() == true }
|
||||
|
||||
// In order for the below code to work for old events, we should save the previous read receipt
|
||||
|
@ -343,26 +344,21 @@ internal fun updateNotificationsNew(roomId: String, realm: Realm, currentUserId:
|
|||
it.root?.rootThreadEventId
|
||||
}
|
||||
|
||||
// Find the root events in the new thread events
|
||||
val rootThreads = threadEventsAfterReadReceipt.distinctBy { it.root?.rootThreadEventId }.mapNotNull { it.root?.rootThreadEventId }
|
||||
// Update root thread event only if the user have participated in
|
||||
val isUserParticipating = TimelineEventEntity.isUserParticipatingInThread(
|
||||
realm = realm,
|
||||
roomId = roomId,
|
||||
rootThreadEventId = rootThreadEventId,
|
||||
senderId = currentUserId
|
||||
)
|
||||
val rootThreadEventEntity = EventEntity.where(realm, rootThreadEventId).findFirst()
|
||||
|
||||
// Update root thread events only if the user have participated in
|
||||
rootThreads.forEach { eventId ->
|
||||
val isUserParticipating = TimelineEventEntity.isUserParticipatingInThread(
|
||||
realm = realm,
|
||||
roomId = roomId,
|
||||
rootThreadEventId = eventId,
|
||||
senderId = currentUserId
|
||||
)
|
||||
val rootThreadEventEntity = EventEntity.where(realm, eventId).findFirst()
|
||||
if (isUserParticipating) {
|
||||
rootThreadEventEntity?.threadNotificationState = ThreadNotificationState.NEW_MESSAGE
|
||||
}
|
||||
|
||||
if (isUserParticipating) {
|
||||
rootThreadEventEntity?.threadNotificationState = ThreadNotificationState.NEW_MESSAGE
|
||||
}
|
||||
|
||||
if (userMentionsList.contains(eventId)) {
|
||||
rootThreadEventEntity?.threadNotificationState = ThreadNotificationState.NEW_HIGHLIGHTED_MESSAGE
|
||||
}
|
||||
if (userMentionsList.contains(rootThreadEventId)) {
|
||||
rootThreadEventEntity?.threadNotificationState = ThreadNotificationState.NEW_HIGHLIGHTED_MESSAGE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.database.helper
|
|||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.Sort
|
||||
import io.realm.kotlin.createObject
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.matrix.android.sdk.api.session.crypto.CryptoService
|
||||
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
|
||||
|
@ -103,32 +102,6 @@ internal fun ThreadSummaryEntity.updateThreadSummaryLatestEvent(
|
|||
}
|
||||
}
|
||||
|
||||
private fun EventEntity.toTimelineEventEntity(roomMemberContentsByUser: HashMap<String, RoomMemberContent?>): TimelineEventEntity {
|
||||
val roomId = roomId
|
||||
val eventId = eventId
|
||||
val localId = TimelineEventEntity.nextId(realm)
|
||||
val senderId = sender ?: ""
|
||||
|
||||
val timelineEventEntity = realm.createObject<TimelineEventEntity>().apply {
|
||||
this.localId = localId
|
||||
this.root = this@toTimelineEventEntity
|
||||
this.eventId = eventId
|
||||
this.roomId = roomId
|
||||
this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst()
|
||||
?.also { it.cleanUp(sender) }
|
||||
this.ownedByThreadChunk = true // To skip it from the original event flow
|
||||
val roomMemberContent = roomMemberContentsByUser[senderId]
|
||||
this.senderAvatar = roomMemberContent?.avatarUrl
|
||||
this.senderName = roomMemberContent?.displayName
|
||||
isUniqueDisplayName = if (roomMemberContent?.displayName != null) {
|
||||
computeIsUnique(realm, roomId, false, roomMemberContent, roomMemberContentsByUser)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
return timelineEventEntity
|
||||
}
|
||||
|
||||
internal fun ThreadSummaryEntity.Companion.createOrUpdate(
|
||||
threadSummaryType: ThreadSummaryUpdateType,
|
||||
realm: Realm,
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2020 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.internal.database.mapper
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.EditAggregatedSummary
|
||||
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.EditionOfEvent
|
||||
|
||||
internal object EditAggregatedSummaryEntityMapper {
|
||||
|
||||
fun map(summary: EditAggregatedSummaryEntity?): EditAggregatedSummary? {
|
||||
summary ?: return null
|
||||
/**
|
||||
* The most recent event is determined by comparing origin_server_ts;
|
||||
* if two or more replacement events have identical origin_server_ts,
|
||||
* the event with the lexicographically largest event_id is treated as more recent.
|
||||
*/
|
||||
val latestEdition = summary.editions.sortedWith(compareBy<EditionOfEvent> { it.timestamp }.thenBy { it.eventId })
|
||||
.lastOrNull() ?: return null
|
||||
val editEvent = latestEdition.event
|
||||
|
||||
return EditAggregatedSummary(
|
||||
latestEdit = editEvent?.asDomain(),
|
||||
sourceEvents = summary.editions.filter { editionOfEvent -> !editionOfEvent.isLocalEcho }
|
||||
.map { editionOfEvent -> editionOfEvent.eventId },
|
||||
localEchos = summary.editions.filter { editionOfEvent -> editionOfEvent.isLocalEcho }
|
||||
.map { editionOfEvent -> editionOfEvent.eventId },
|
||||
lastEditTs = latestEdition.timestamp
|
||||
)
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.database.mapper
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.EditAggregatedSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.ReactionAggregatedSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedSummary
|
||||
|
@ -36,18 +35,7 @@ internal object EventAnnotationsSummaryMapper {
|
|||
it.sourceLocalEcho.toList()
|
||||
)
|
||||
},
|
||||
editSummary = annotationsSummary.editSummary
|
||||
?.let {
|
||||
val latestEdition = it.editions.maxByOrNull { editionOfEvent -> editionOfEvent.timestamp } ?: return@let null
|
||||
EditAggregatedSummary(
|
||||
latestContent = ContentMapper.map(latestEdition.content),
|
||||
sourceEvents = it.editions.filter { editionOfEvent -> !editionOfEvent.isLocalEcho }
|
||||
.map { editionOfEvent -> editionOfEvent.eventId },
|
||||
localEchos = it.editions.filter { editionOfEvent -> editionOfEvent.isLocalEcho }
|
||||
.map { editionOfEvent -> editionOfEvent.eventId },
|
||||
lastEditTs = latestEdition.timestamp
|
||||
)
|
||||
},
|
||||
editSummary = EditAggregatedSummaryEntityMapper.map(annotationsSummary.editSummary),
|
||||
referencesAggregatedSummary = annotationsSummary.referencesSummaryEntity?.let {
|
||||
ReferencesAggregatedSummary(
|
||||
ContentMapper.map(it.content),
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.internal.database.mapper
|
||||
|
||||
import io.realm.RealmList
|
||||
import org.matrix.android.sdk.internal.database.model.SyncFilterParamsEntity
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class FilterParamsMapper @Inject constructor() {
|
||||
|
||||
fun map(entity: SyncFilterParamsEntity): SyncFilterParams {
|
||||
val eventTypes = if (entity.listOfSupportedEventTypesHasBeenSet) {
|
||||
entity.listOfSupportedEventTypes?.toList()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val stateEventTypes = if (entity.listOfSupportedStateEventTypesHasBeenSet) {
|
||||
entity.listOfSupportedStateEventTypes?.toList()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return SyncFilterParams(
|
||||
useThreadNotifications = entity.useThreadNotifications,
|
||||
lazyLoadMembersForMessageEvents = entity.lazyLoadMembersForMessageEvents,
|
||||
lazyLoadMembersForStateEvents = entity.lazyLoadMembersForStateEvents,
|
||||
listOfSupportedEventTypes = eventTypes,
|
||||
listOfSupportedStateEventTypes = stateEventTypes,
|
||||
)
|
||||
}
|
||||
|
||||
fun map(params: SyncFilterParams): SyncFilterParamsEntity {
|
||||
return SyncFilterParamsEntity(
|
||||
useThreadNotifications = params.useThreadNotifications,
|
||||
lazyLoadMembersForMessageEvents = params.lazyLoadMembersForMessageEvents,
|
||||
lazyLoadMembersForStateEvents = params.lazyLoadMembersForStateEvents,
|
||||
listOfSupportedEventTypes = params.listOfSupportedEventTypes.toRealmList(),
|
||||
listOfSupportedEventTypesHasBeenSet = params.listOfSupportedEventTypes != null,
|
||||
listOfSupportedStateEventTypes = params.listOfSupportedStateEventTypes.toRealmList(),
|
||||
listOfSupportedStateEventTypesHasBeenSet = params.listOfSupportedStateEventTypes != null,
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<String>?.toRealmList(): RealmList<String>? {
|
||||
return this?.toTypedArray()?.let { RealmList(*it) }
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ internal class ReadReceiptsSummaryMapper @Inject constructor(
|
|||
.mapNotNull {
|
||||
val roomMember = RoomMemberSummaryEntity.where(realm, roomId = it.roomId, userId = it.userId).findFirst()
|
||||
?: return@mapNotNull null
|
||||
ReadReceipt(roomMember.asDomain(), it.originServerTs.toLong())
|
||||
ReadReceipt(roomMember.asDomain(), it.originServerTs.toLong(), it.threadId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ internal class MigrateSessionTo008(realm: DynamicRealm) : RealmMigrator(realm, 8
|
|||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
val editionOfEventSchema = realm.schema.create("EditionOfEvent")
|
||||
.addField(EditionOfEventFields.CONTENT, String::class.java)
|
||||
.addField("content", String::class.java)
|
||||
.addField(EditionOfEventFields.EVENT_ID, String::class.java)
|
||||
.setRequired(EditionOfEventFields.EVENT_ID, true)
|
||||
.addField(EditionOfEventFields.SENDER_ID, String::class.java)
|
||||
.setRequired(EditionOfEventFields.SENDER_ID, true)
|
||||
.addField("senderId", String::class.java)
|
||||
.setRequired("senderId", true)
|
||||
.addField(EditionOfEventFields.TIMESTAMP, Long::class.java)
|
||||
.addField(EditionOfEventFields.IS_LOCAL_ECHO, Boolean::class.java)
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 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.internal.database.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.database.model.EditionOfEventFields
|
||||
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
internal class MigrateSessionTo043(realm: DynamicRealm) : RealmMigrator(realm, 43) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
// content(string) & senderId(string) have been removed and replaced by a link to the actual event
|
||||
realm.schema.get("EditionOfEvent")
|
||||
?.addRealmObjectField(EditionOfEventFields.EVENT.`$`, realm.schema.get("EventEntity")!!)
|
||||
?.transform { dynamicObject ->
|
||||
realm.where("EventEntity")
|
||||
.equalTo(EventEntityFields.EVENT_ID, dynamicObject.getString(EditionOfEventFields.EVENT_ID))
|
||||
.equalTo(EventEntityFields.SENDER, dynamicObject.getString("senderId"))
|
||||
.findFirst()
|
||||
.let {
|
||||
dynamicObject.setObject(EditionOfEventFields.EVENT.`$`, it)
|
||||
}
|
||||
}
|
||||
?.removeField("senderId")
|
||||
?.removeField("content")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 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.internal.database.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
internal class MigrateSessionTo044(realm: DynamicRealm) : RealmMigrator(realm, 44) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.get("ReadReceiptEntity")
|
||||
?.addField(ReadReceiptEntityFields.THREAD_ID, String::class.java)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 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.internal.database.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.database.model.SyncFilterParamsEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
internal class MigrateSessionTo045(realm: DynamicRealm) : RealmMigrator(realm, 45) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.create("SyncFilterParamsEntity")
|
||||
.addField(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_STATE_EVENTS, Boolean::class.java)
|
||||
.setNullable(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_STATE_EVENTS, true)
|
||||
.addField(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_MESSAGE_EVENTS, Boolean::class.java)
|
||||
.setNullable(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_MESSAGE_EVENTS, true)
|
||||
.addField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_EVENT_TYPES_HAS_BEEN_SET, Boolean::class.java)
|
||||
.addField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_STATE_EVENT_TYPES_HAS_BEEN_SET, Boolean::class.java)
|
||||
.addField(SyncFilterParamsEntityFields.USE_THREAD_NOTIFICATIONS, Boolean::class.java)
|
||||
.setNullable(SyncFilterParamsEntityFields.USE_THREAD_NOTIFICATIONS, true)
|
||||
.addRealmListField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_EVENT_TYPES.`$`, String::class.java)
|
||||
.addRealmListField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_STATE_EVENT_TYPES.`$`, String::class.java)
|
||||
}
|
||||
}
|
|
@ -32,9 +32,8 @@ internal open class EditAggregatedSummaryEntity(
|
|||
|
||||
@RealmClass(embedded = true)
|
||||
internal open class EditionOfEvent(
|
||||
var senderId: String = "",
|
||||
var eventId: String = "",
|
||||
var content: String? = null,
|
||||
var timestamp: Long = 0,
|
||||
var isLocalEcho: Boolean = false
|
||||
var isLocalEcho: Boolean = false,
|
||||
var event: EventEntity? = null,
|
||||
) : RealmObject()
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue