Merge branch 'develop' into renovate/core

This commit is contained in:
Benoit Marty
2024-05-29 14:48:56 +02:00
committed by GitHub
1446 changed files with 18763 additions and 7190 deletions

View File

@@ -11,7 +11,7 @@ jobs:
- run: |
npm install --save-dev @babel/plugin-transform-flow-strip-types
- name: Danger
uses: danger/danger-js@12.1.0
uses: danger/danger-js@12.3.0
with:
args: "--dangerfile ./tools/danger/dangerfile.js"
env:

View File

@@ -22,10 +22,10 @@ jobs:
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: 3.12
- name: Run World screenshots generation script
run: |
./tools/test/generateWorldScreenshots.py

View File

@@ -12,12 +12,10 @@ env:
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 8 --no-daemon
jobs:
maestro-cloud:
name: Maestro test suite
build-apk:
name: Build APK
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'Run-Maestro'
strategy:
fail-fast: false
# Allow one per PR.
concurrency:
group: ${{ format('maestro-{0}', github.ref) }}
@@ -41,19 +39,49 @@ jobs:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Assemble debug APK
run: ./gradlew :app:assembleDebug $CI_GRADLE_ARG_PROPERTIES
run: ./gradlew :app:assembleGplayDebug $CI_GRADLE_ARG_PROPERTIES
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
- name: Upload APK as artifact
uses: actions/upload-artifact@v4
with:
name: elementx-apk-maestro
path: |
app/build/outputs/apk/gplay/debug/app-gplay-x86_64-debug.apk
retention-days: 5
overwrite: true
if-no-files-found: error
maestro-cloud:
name: Maestro test suite
runs-on: ubuntu-latest
needs: build-apk
if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'Run-Maestro'
# Allow one per PR.
concurrency:
group: ${{ format('maestro-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Download APK artifact from previous job
uses: actions/download-artifact@v4
with:
name: elementx-apk-maestro
- uses: mobile-dev-inc/action-maestro-cloud@v1.8.1
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
with:
api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
# Doc says (https://github.com/mobile-dev-inc/action-maestro-cloud#android):
# app-file should point to an x86 compatible APK file, so upload the x86_64 one (much smaller than the universal APK).
app-file: app/build/outputs/apk/gplay/debug/app-gplay-x86_64-debug.apk
app-file: app-gplay-x86_64-debug.apk
env: |
MAESTRO_USERNAME=maestroelement
MAESTRO_PASSWORD=${{ secrets.MATRIX_MAESTRO_ACCOUNT_PASSWORD }}

View File

@@ -33,7 +33,7 @@ jobs:
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
- name: 📈 Generate kover report and verify coverage
run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyGplayDebug $CI_GRADLE_ARG_PROPERTIES
run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
- name: ✅ Upload kover report
if: always()

View File

@@ -10,7 +10,7 @@ on:
# Enrich gradle.properties for CI/CD
env:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx6g -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.incremental=false -XX:+UseParallelGC
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 8 --no-daemon --warn
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 8 --no-daemon
jobs:
checkScript:
@@ -26,19 +26,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: 3.12
- name: Search for invalid screenshot files
run: ./tools/test/checkInvalidScreenshots.py
check:
name: Project Check Suite
# Code checks
konsist:
name: Konsist tests
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('check-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-develop-{0}', github.sha) || format('check-{0}', github.ref) }}
group: ${{ github.ref == 'refs/heads/main' && format('check-konsist-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-konsist-develop-{0}', github.sha) || format('check-konsist-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
@@ -55,8 +56,40 @@ jobs:
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run code quality check suite
run: ./gradlew runQualityChecks $CI_GRADLE_ARG_PROPERTIES
- name: Run Konsist tests
run: ./gradlew :tests:konsist:testDebugUnitTest $CI_GRADLE_ARG_PROPERTIES --no-daemon
- name: Upload reports
if: always()
uses: actions/upload-artifact@v4
with:
name: konsist-report
path: |
**/build/reports/**/*.*
lint:
name: Android lint check
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('check-lint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-lint-develop-{0}', github.sha) || format('check-lint-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run lint
run: ./gradlew :app:lintGplayDebug :app:lintFdroidDebug $CI_GRADLE_ARG_PROPERTIES
- name: Upload reports
if: always()
uses: actions/upload-artifact@v4
@@ -64,6 +97,108 @@ jobs:
name: linting-report
path: |
**/build/reports/**/*.*
detekt:
name: Detekt checks
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('check-detekt-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-detekt-develop-{0}', github.sha) || format('check-detekt-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run Detekt
run: ./gradlew detekt $CI_GRADLE_ARG_PROPERTIES --no-daemon
- name: Upload reports
if: always()
uses: actions/upload-artifact@v4
with:
name: detekt-report
path: |
**/build/reports/**/*.*
ktlint:
name: Ktlint checks
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('check-ktlint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-ktlint-develop-{0}', github.sha) || format('check-ktlint-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run Ktlint check
run: ./gradlew ktlintCheck $CI_GRADLE_ARG_PROPERTIES
- name: Upload reports
if: always()
uses: actions/upload-artifact@v4
with:
name: ktlint-report
path: |
**/build/reports/**/*.*
knit:
name: Knit checks
runs-on: ubuntu-latest
# Allow all jobs on main and develop. Just one per PR.
concurrency:
group: ${{ github.ref == 'refs/heads/main' && format('check-knit-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-knit-develop-{0}', github.sha) || format('check-knit-{0}', github.ref) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Run Knit
run: ./gradlew knitCheck $CI_GRADLE_ARG_PROPERTIES
upload_reports:
name: Project Check Suite
runs-on: ubuntu-latest
needs: [konsist, lint, ktlint, detekt]
steps:
- uses: actions/checkout@v4
with:
# Ensure we are building the branch and not the branch after being merged on develop
# https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Download reports from previous jobs
uses: actions/download-artifact@v4
- name: Prepare Danger
if: always()
run: |
@@ -72,7 +207,7 @@ jobs:
yarn add danger-plugin-lint-report --dev
- name: Danger lint
if: always()
uses: danger/danger-js@12.1.0
uses: danger/danger-js@12.3.0
with:
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
env:

View File

@@ -1,4 +1,4 @@
name: Create release App Bundle
name: Create release App Bundle and APKs
on:
workflow_dispatch:
@@ -11,11 +11,11 @@ env:
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 8 --no-daemon
jobs:
release:
name: Create App Bundle
gplay:
name: Create App Bundle (Gplay)
runs-on: ubuntu-latest
concurrency:
group: ${{ github.ref == 'refs/head/main' && format('build-release-main-{0}', github.sha) }}
group: ${{ github.ref == 'refs/head/main' && format('build-release-main-gplay-{0}', github.sha) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
@@ -38,3 +38,31 @@ jobs:
name: elementx-app-gplay-bundle-unsigned
path: |
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
fdroid:
name: Create APKs (FDroid)
runs-on: ubuntu-latest
concurrency:
group: ${{ github.ref == 'refs/head/main' && format('build-release-main-fdroid-{0}', github.sha) }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
- name: Use JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Configure gradle
uses: gradle/actions/setup-gradle@v3
- name: Create APKs
env:
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
run: ./gradlew assembleFdroidRelease $CI_GRADLE_ARG_PROPERTIES
- name: Upload apks as artifact
uses: actions/upload-artifact@v4
with:
name: elementx-app-fdroid-apks-unsigned
path: |
app/build/outputs/apk/fdroid/release/*.apk

View File

@@ -21,10 +21,10 @@ jobs:
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: 3.12
- name: Setup Localazy
run: |
curl -sS https://dist.localazy.com/debian/pubkey.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/localazy.gpg
@@ -33,6 +33,7 @@ jobs:
- name: Run Localazy script
run: |
./tools/localazy/downloadStrings.sh --all
./tools/localazy/importSupportedLocalesFromLocalazy.py
./tools/test/generateAllScreenshots.py
- name: Create Pull Request for Strings
uses: peter-evans/create-pull-request@v6

View File

@@ -13,10 +13,10 @@ jobs:
# No concurrency required, runs every time on a schedule.
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.9
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: 3.12
- name: Install Prerequisite dependencies
run: |
pip install requests

View File

@@ -55,7 +55,7 @@ jobs:
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
- name: 📈Generate kover report and verify coverage
run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyGplayDebug $CI_GRADLE_ARG_PROPERTIES
run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
- name: 🚫 Upload kover failed coverage reports
if: failure()

1
.gitignore vendored
View File

@@ -45,6 +45,7 @@ captures/
.idea/assetWizardSettings.xml
.idea/compiler.xml
.idea/deploymentTargetDropDown.xml
.idea/deploymentTargetSelector.xml
.idea/gradle.xml
.idea/jarRepositories.xml
.idea/misc.xml

View File

@@ -3,7 +3,9 @@
<words>
<w>backstack</w>
<w>blurhash</w>
<w>fdroid</w>
<w>ftue</w>
<w>gplay</w>
<w>homeserver</w>
<w>konsist</w>
<w>kover</w>

2
.idea/kotlinc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.23" />
<option name="version" value="1.9.24" />
</component>
</project>

View File

@@ -16,7 +16,7 @@ appId: ${MAESTRO_APP_ID}
- tapOn: "Create"
- takeScreenshot: build/maestro/320-createAndDeleteRoom
- tapOn: "aRoomName"
- tapOn: "Invite people"
- tapOn: "Invite"
# assert there's 1 member and 1 invitee
- tapOn: "Search for someone"
- inputText: ${MAESTRO_INVITEE2_MXID}

View File

@@ -2,7 +2,7 @@ appId: ${MAESTRO_APP_ID}
---
- takeScreenshot: build/maestro/510-Timeline
- tapOn:
id: "rich_text_editor"
id: "text_editor"
- inputText: "Hello world!"
- tapOn: "Send"
- hideKeyboard

View File

@@ -34,7 +34,7 @@ appId: ${MAESTRO_APP_ID}
- tapOn:
text: "Advanced settings"
- assertVisible: "Rich text editor"
- assertVisible: "View source"
- back
- tapOn:

View File

@@ -1,3 +1,64 @@
Changes in Element X v0.4.13 (2024-05-22)
=========================================
Features ✨
----------
- Add plain text editor based on Markdown input. ([#2840](https://github.com/element-hq/element-x-android/issues/2840))
Bugfixes 🐛
----------
- Use members display names for their membership state events. ([#2286](https://github.com/element-hq/element-x-android/issues/2286))
- Make sure explicit links in messages take priority over links found by linkification (urls, emails, phone numbers, etc.) ([#2291](https://github.com/element-hq/element-x-android/issues/2291))
- Fix modal contents overlapping screen lock pin. ([#2692](https://github.com/element-hq/element-x-android/issues/2692))
- Fix a crash when trying to create an `EncryptedFile` in Android 6. ([#2846](https://github.com/element-hq/element-x-android/issues/2846))
- Session falsely displayed as 'verified' with no internet connection. ([#2884](https://github.com/element-hq/element-x-android/issues/2884))
Other changes
-------------
- Allow configuring push notification provider ([#2340](https://github.com/element-hq/element-x-android/issues/2340))
- UX cleanup: reorder text composer actions to prioritise camera ones. ([#2803](https://github.com/element-hq/element-x-android/issues/2803))
- Translation added into Portuguese and Simplified Chinese ([#2834](https://github.com/element-hq/element-x-android/issues/2834))
- Use via parameters when joining a room from permalink. ([#2843](https://github.com/element-hq/element-x-android/issues/2843))
Changes in Element X v0.4.12 (2024-05-13)
=========================================
Features ✨
----------
- Add support for expected decryption errors due to membership (UX and analytics). ([#2754](https://github.com/element-hq/element-x-android/issues/2754))
- Handle permalink navigation to Events. ([#2759](https://github.com/element-hq/element-x-android/issues/2759))
- Pretty-print event JSON in debug viewer ([#2771](https://github.com/element-hq/element-x-android/issues/2771))
- Add support for external permalinks. ([#2776](https://github.com/element-hq/element-x-android/issues/2776))
- Enable support for Android per-app language preferences ([#2795](https://github.com/element-hq/element-x-android/issues/2795))
Bugfixes 🐛
----------
- Fix session verification being asked again for already verified users. ([#2718](https://github.com/element-hq/element-x-android/issues/2718))
- Instead of displaying 'create new recovery key' on the session verification screen when there is no other session active, display it always under the 'enter recovery key' screen. ([#2740](https://github.com/element-hq/element-x-android/issues/2740))
- Adjust the typography used in the selected user component so a user's display name fits better. ([#2760](https://github.com/element-hq/element-x-android/issues/2760))
- User display name overflows in timeline messages when it's way too long. ([#2761](https://github.com/element-hq/element-x-android/issues/2761))
- Ensure the application open the room when a notification is clicked. ([#2778](https://github.com/element-hq/element-x-android/issues/2778))
- Enforce mandatory session verification only for new logins. ([#2810](https://github.com/element-hq/element-x-android/issues/2810))
- Make log less verbose, make sure we upload as many log files as possible before reaching the request size limit of the bug reporting service, discard older logs if they don't fit. ([#2825](https://github.com/element-hq/element-x-android/issues/2825))
- Remove 'Join' button in room directory search results. ([#2827](https://github.com/element-hq/element-x-android/issues/2827))
- Add missing `app_id` and `Version` properties to bug reports. ([#2829](https://github.com/element-hq/element-x-android/issues/2829))
Other changes
-------------
- RoomMember screen: fallback to userProfile data, if the member is not a user of the room. ([#2721](https://github.com/element-hq/element-x-android/issues/2721))
- Migrate application data. ([#2749](https://github.com/element-hq/element-x-android/issues/2749))
- Let the SDK manage the file log cleanup, and keep one week of log. ([#2758](https://github.com/element-hq/element-x-android/issues/2758))
- UX cleanup: reorder options in the main settings screen. ([#2801](https://github.com/element-hq/element-x-android/issues/2801))
- Analytics: Add support to report current session verification and recovery state ([#2806](https://github.com/element-hq/element-x-android/issues/2806))
- UX cleanup: room details screen, add new CTA buttons for Invite and Call actions. ([#2814](https://github.com/element-hq/element-x-android/issues/2814))
- UX cleanup: user profile. Move send DM to a call to action button, add 'Call' CTA too. ([#2818](https://github.com/element-hq/element-x-android/issues/2818))
- Add room badges to room details screen. ([#2822](https://github.com/element-hq/element-x-android/issues/2822))
Security
-------------
- Bump the Rust SDK to `v0.2.18` to remediate [CVE-2024-34353 / GHSA-9ggc-845v-gcgv](https://github.com/matrix-org/matrix-rust-sdk/security/advisories/GHSA-9ggc-845v-gcgv).
Changes in Element X v0.4.10 (2024-04-17)
=========================================
@@ -5,14 +66,14 @@ Matrix Rust SDK 0.2.14
Features ✨
----------
- Rework room navigation to handle unknown room and prepare work on permalink. ([#2695](https://github.com/element-hq/element-x-android/issues/2695))
- Rework room navigation to handle unknown room and prepare work on permalink. ([#2695](https://github.com/element-hq/element-x-android/issues/2695))
Other changes
-------------
- Encrypt new session data with a passphrase ([#2703](https://github.com/element-hq/element-x-android/issues/2703))
- Use sdk API to build permalinks ([#2708](https://github.com/element-hq/element-x-android/issues/2708))
- Parse permalink using parseMatrixEntityFrom from the SDK ([#2709](https://github.com/element-hq/element-x-android/issues/2709))
- Fix compile for forks that use the `noop` analytics module ([#2698](https://github.com/element-hq/element-x-android/issues/2698))
- Encrypt new session data with a passphrase ([#2703](https://github.com/element-hq/element-x-android/issues/2703))
- Use sdk API to build permalinks ([#2708](https://github.com/element-hq/element-x-android/issues/2708))
- Parse permalink using parseMatrixEntityFrom from the SDK ([#2709](https://github.com/element-hq/element-x-android/issues/2709))
- Fix compile for forks that use the `noop` analytics module ([#2698](https://github.com/element-hq/element-x-android/issues/2698))
Changes in Element X v0.4.9 (2024-04-12)
@@ -20,31 +81,35 @@ Changes in Element X v0.4.9 (2024-04-12)
- Synchronize Localazy Strings.
Security
----------
- Fix crash while processing a room message containing a malformed pill.
Changes in Element X v0.4.8 (2024-04-10)
========================================
Features ✨
----------
- Move session recovery to the login flow. ([#2579](https://github.com/element-hq/element-x-android/issues/2579))
- Move session verification to the after login flow and make it mandatory. ([#2580](https://github.com/element-hq/element-x-android/issues/2580))
- Add a notification troubleshoot screen ([#2601](https://github.com/element-hq/element-x-android/issues/2601))
- Add action to copy permalink ([#2650](https://github.com/element-hq/element-x-android/issues/2650))
- Move session recovery to the login flow. ([#2579](https://github.com/element-hq/element-x-android/issues/2579))
- Move session verification to the after login flow and make it mandatory. ([#2580](https://github.com/element-hq/element-x-android/issues/2580))
- Add a notification troubleshoot screen ([#2601](https://github.com/element-hq/element-x-android/issues/2601))
- Add action to copy permalink ([#2650](https://github.com/element-hq/element-x-android/issues/2650))
Bugfixes 🐛
----------
- Fix analytics issue around room considered as space by mistake. ([#2612](https://github.com/element-hq/element-x-android/issues/2612))
- Fix crash observed when going back to the room list. ([#2619](https://github.com/element-hq/element-x-android/issues/2619))
- Hide Event org.matrix.msc3401.call.member on the timeline. ([#2625](https://github.com/element-hq/element-x-android/issues/2625))
- Fall back to name-based generated avatars when image avatars don't load. ([#2667](https://github.com/element-hq/element-x-android/issues/2667))
- Fix analytics issue around room considered as space by mistake. ([#2612](https://github.com/element-hq/element-x-android/issues/2612))
- Fix crash observed when going back to the room list. ([#2619](https://github.com/element-hq/element-x-android/issues/2619))
- Hide Event org.matrix.msc3401.call.member on the timeline. ([#2625](https://github.com/element-hq/element-x-android/issues/2625))
- Fall back to name-based generated avatars when image avatars don't load. ([#2667](https://github.com/element-hq/element-x-android/issues/2667))
Other changes
-------------
- Improve UI for notification permission screen in onboarding. ([#2581](https://github.com/element-hq/element-x-android/issues/2581))
- Categorise members by role in change roles screen. ([#2593](https://github.com/element-hq/element-x-android/issues/2593))
- Make completed poll more clearly visible ([#2608](https://github.com/element-hq/element-x-android/issues/2608))
- Show users from last visited DM as suggestion when starting a Chat or when creating a Room. ([#2634](https://github.com/element-hq/element-x-android/issues/2634))
- Enable room moderation feature. ([#2678](https://github.com/element-hq/element-x-android/issues/2678))
- Improve analytics opt-in screen UI. ([#2684](https://github.com/element-hq/element-x-android/issues/2684))
- Improve UI for notification permission screen in onboarding. ([#2581](https://github.com/element-hq/element-x-android/issues/2581))
- Categorise members by role in change roles screen. ([#2593](https://github.com/element-hq/element-x-android/issues/2593))
- Make completed poll more clearly visible ([#2608](https://github.com/element-hq/element-x-android/issues/2608))
- Show users from last visited DM as suggestion when starting a Chat or when creating a Room. ([#2634](https://github.com/element-hq/element-x-android/issues/2634))
- Enable room moderation feature. ([#2678](https://github.com/element-hq/element-x-android/issues/2678))
- Improve analytics opt-in screen UI. ([#2684](https://github.com/element-hq/element-x-android/issues/2684))
Changes in Element X v0.4.7 (2024-03-26)
@@ -52,19 +117,19 @@ Changes in Element X v0.4.7 (2024-03-26)
Features ✨
----------
- Enable the feature "RoomList filters". ([#2603](https://github.com/element-hq/element-x-android/issues/2603))
- Enable the feature "Mark as unread" ([#2261](https://github.com/element-hq/element-x-android/issues/2261))
- Implement MSC2530 (Body field as media caption) ([#2521](https://github.com/element-hq/element-x-android/issues/2521))
- Enable the feature "RoomList filters". ([#2603](https://github.com/element-hq/element-x-android/issues/2603))
- Enable the feature "Mark as unread" ([#2261](https://github.com/element-hq/element-x-android/issues/2261))
- Implement MSC2530 (Body field as media caption) ([#2521](https://github.com/element-hq/element-x-android/issues/2521))
Bugfixes 🐛
----------
- Use user avatar from cache if available. ([#2488](https://github.com/element-hq/element-x-android/issues/2488))
- Update member list after changing member roles and when the room member list is opened. ([#2590](https://github.com/element-hq/element-x-android/issues/2590))
- Use user avatar from cache if available. ([#2488](https://github.com/element-hq/element-x-android/issues/2488))
- Update member list after changing member roles and when the room member list is opened. ([#2590](https://github.com/element-hq/element-x-android/issues/2590))
Other changes
-------------
- Compound: add `BigIcon`, `BigCheckmark` and `PageTitle` components. ([#2574](https://github.com/element-hq/element-x-android/issues/2574))
- Remove Welcome screen from the FTUE. ([#2584](https://github.com/element-hq/element-x-android/issues/2584))
- Compound: add `BigIcon`, `BigCheckmark` and `PageTitle` components. ([#2574](https://github.com/element-hq/element-x-android/issues/2574))
- Remove Welcome screen from the FTUE. ([#2584](https://github.com/element-hq/element-x-android/issues/2584))
Changes in Element X v0.4.6 (2024-03-15)
@@ -72,26 +137,26 @@ Changes in Element X v0.4.6 (2024-03-15)
Features ✨
----------
- Admins can now change user roles in rooms. ([#2257](https://github.com/element-hq/element-x-android/issues/2257))
- Room member moderation: remove, ban and unban users from a room. ([#2258](https://github.com/element-hq/element-x-android/issues/2258))
- Change a room's permissions power levels. ([#2259](https://github.com/element-hq/element-x-android/issues/2259))
- Add state timeline events and notifications for legacy call invites. ([#2485](https://github.com/element-hq/element-x-android/issues/2485))
- Admins can now change user roles in rooms. ([#2257](https://github.com/element-hq/element-x-android/issues/2257))
- Room member moderation: remove, ban and unban users from a room. ([#2258](https://github.com/element-hq/element-x-android/issues/2258))
- Change a room's permissions power levels. ([#2259](https://github.com/element-hq/element-x-android/issues/2259))
- Add state timeline events and notifications for legacy call invites. ([#2485](https://github.com/element-hq/element-x-android/issues/2485))
Bugfixes 🐛
----------
- Added empty state to banned member list. ([#+add-empty-state-to-banned-members-list](https://github.com/element-hq/element-x-android/issues/+add-empty-state-to-banned-members-list))
- Prevent sending empty messages. ([#995](https://github.com/element-hq/element-x-android/issues/995))
- Use the display name only once in display name change events. The user should be referenced by `userId` instead. ([#2125](https://github.com/element-hq/element-x-android/issues/2125))
- Hide blocked users list when there are no blocked users. ([#2198](https://github.com/element-hq/element-x-android/issues/2198))
- Fix timeline not showing sender info when room is marked as direct but not a 1:1 room. ([#2530](https://github.com/element-hq/element-x-android/issues/2530))
- Added empty state to banned member list. ([#+add-empty-state-to-banned-members-list](https://github.com/element-hq/element-x-android/issues/+add-empty-state-to-banned-members-list))
- Prevent sending empty messages. ([#995](https://github.com/element-hq/element-x-android/issues/995))
- Use the display name only once in display name change events. The user should be referenced by `userId` instead. ([#2125](https://github.com/element-hq/element-x-android/issues/2125))
- Hide blocked users list when there are no blocked users. ([#2198](https://github.com/element-hq/element-x-android/issues/2198))
- Fix timeline not showing sender info when room is marked as direct but not a 1:1 room. ([#2530](https://github.com/element-hq/element-x-android/issues/2530))
Other changes
-------------
- Add `local_time`, `utc_time` and `sdk_sha` params to bug reports so they're easier to investigate. ([#+add-time-and-sdk-sha-params-to-bugreports](https://github.com/element-hq/element-x-android/issues/+add-time-and-sdk-sha-params-to-bugreports))
- Improve room member list loading times, increase chunk size ([#2322](https://github.com/element-hq/element-x-android/issues/2322))
- Improve room member list loading UX. ([#2452](https://github.com/element-hq/element-x-android/issues/2452))
- Remove the special log level for the Rust SDK read receipts. ([#2511](https://github.com/element-hq/element-x-android/issues/2511))
- Track UTD errors. ([#2544](https://github.com/element-hq/element-x-android/issues/2544))
- Add `local_time`, `utc_time` and `sdk_sha` params to bug reports so they're easier to investigate. ([#+add-time-and-sdk-sha-params-to-bugreports](https://github.com/element-hq/element-x-android/issues/+add-time-and-sdk-sha-params-to-bugreports))
- Improve room member list loading times, increase chunk size ([#2322](https://github.com/element-hq/element-x-android/issues/2322))
- Improve room member list loading UX. ([#2452](https://github.com/element-hq/element-x-android/issues/2452))
- Remove the special log level for the Rust SDK read receipts. ([#2511](https://github.com/element-hq/element-x-android/issues/2511))
- Track UTD errors. ([#2544](https://github.com/element-hq/element-x-android/issues/2544))
Changes in Element X v0.4.5 (2024-02-28)
@@ -99,22 +164,22 @@ Changes in Element X v0.4.5 (2024-02-28)
Features ✨
----------
- Mark a room or dm as favourite. ([#2208](https://github.com/element-hq/element-x-android/issues/2208))
- Add moderation to rooms:
- Sort member in room member list by powerlevel, display their roles.
- Display banner users in room member list for users with enough power level to ban/unban. ([#2256](https://github.com/element-hq/element-x-android/issues/2256))
- MediaViewer : introduce fullscreen and flick to dismiss behavior. ([#2390](https://github.com/element-hq/element-x-android/issues/2390))
- Allow user-installed certificates to be used by the HTTP client ([#2992](https://github.com/element-hq/element-x-android/issues/2992))
- Mark a room or dm as favourite. ([#2208](https://github.com/element-hq/element-x-android/issues/2208))
- Add moderation to rooms:
- Sort member in room member list by powerlevel, display their roles.
- Display banner users in room member list for users with enough power level to ban/unban. ([#2256](https://github.com/element-hq/element-x-android/issues/2256))
- MediaViewer : introduce fullscreen and flick to dismiss behavior. ([#2390](https://github.com/element-hq/element-x-android/issues/2390))
- Allow user-installed certificates to be used by the HTTP client ([#2992](https://github.com/element-hq/element-x-android/issues/2992))
Bugfixes 🐛
----------
- Do not display empty room list state before the loading one when we still don't have any items ([#+do-not-display-empty-state-before-loading-roomlist](https://github.com/element-hq/element-x-android/issues/+do-not-display-empty-state-before-loading-roomlist))
- Improve how Talkback works with the timeline. Sadly, it's still not 100% working, but there is some issue with the `LazyColumn` using `reverseLayout` that only Google can fix. ([#+improve-accessibility-in-timeline](https://github.com/element-hq/element-x-android/issues/+improve-accessibility-in-timeline))
- Add ability to enter a recovery key to verify the session. Also fixes some refresh issues with the verification session state. ([#2421](https://github.com/element-hq/element-x-android/issues/2421))
- Do not display empty room list state before the loading one when we still don't have any items ([#+do-not-display-empty-state-before-loading-roomlist](https://github.com/element-hq/element-x-android/issues/+do-not-display-empty-state-before-loading-roomlist))
- Improve how Talkback works with the timeline. Sadly, it's still not 100% working, but there is some issue with the `LazyColumn` using `reverseLayout` that only Google can fix. ([#+improve-accessibility-in-timeline](https://github.com/element-hq/element-x-android/issues/+improve-accessibility-in-timeline))
- Add ability to enter a recovery key to verify the session. Also fixes some refresh issues with the verification session state. ([#2421](https://github.com/element-hq/element-x-android/issues/2421))
Other changes
-------------
- Provide the current system proxy setting to the Rust SDK. ([#2420](https://github.com/element-hq/element-x-android/issues/2420))
- Provide the current system proxy setting to the Rust SDK. ([#2420](https://github.com/element-hq/element-x-android/issues/2420))
Changes in Element X v0.4.4 (2024-02-15)
@@ -130,31 +195,31 @@ Changes in Element X v0.4.3 (2024-02-14)
Features ✨
----------
- Change "Read receipts" advanced setting used to send private Read Receipt to "Share presence" settings. When disabled, private Read Receipts will be sent, and no typing notification will be sent. Also Read Receipts and typing notifications will not be rendered in the timeline. ([#2241](https://github.com/element-hq/element-x-android/issues/2241))
- Render typing notifications. ([#2242](https://github.com/element-hq/element-x-android/issues/2242))
- Manually mark a room as unread. ([#2261](https://github.com/element-hq/element-x-android/issues/2261))
- Add empty state to the room list. ([#2330](https://github.com/element-hq/element-x-android/issues/2330))
- Allow joining unencrypted video calls in non encrypted rooms. ([#2333](https://github.com/element-hq/element-x-android/issues/2333))
- Change "Read receipts" advanced setting used to send private Read Receipt to "Share presence" settings. When disabled, private Read Receipts will be sent, and no typing notification will be sent. Also Read Receipts and typing notifications will not be rendered in the timeline. ([#2241](https://github.com/element-hq/element-x-android/issues/2241))
- Render typing notifications. ([#2242](https://github.com/element-hq/element-x-android/issues/2242))
- Manually mark a room as unread. ([#2261](https://github.com/element-hq/element-x-android/issues/2261))
- Add empty state to the room list. ([#2330](https://github.com/element-hq/element-x-android/issues/2330))
- Allow joining unencrypted video calls in non encrypted rooms. ([#2333](https://github.com/element-hq/element-x-android/issues/2333))
Bugfixes 🐛
----------
- Fix crash after unregistering UnifiedPush distributor ([#2304](https://github.com/element-hq/element-x-android/issues/2304))
- Add missing device id to settings screen. ([#2316](https://github.com/element-hq/element-x-android/issues/2316))
- Open the keyboard (and keep it opened) when creating a poll. ([#2329](https://github.com/element-hq/element-x-android/issues/2329))
- Fix message forwarding after SDK API change related to Timeline intitialization.
- Fix crash after unregistering UnifiedPush distributor ([#2304](https://github.com/element-hq/element-x-android/issues/2304))
- Add missing device id to settings screen. ([#2316](https://github.com/element-hq/element-x-android/issues/2316))
- Open the keyboard (and keep it opened) when creating a poll. ([#2329](https://github.com/element-hq/element-x-android/issues/2329))
- Fix message forwarding after SDK API change related to Timeline intitialization.
Other changes
-------------
- Adjusted the login flow buttons so the continue button is always at the same height ([#825](https://github.com/element-hq/element-x-android/issues/825))
- Move migration screen to within the room list ([#2310](https://github.com/element-hq/element-x-android/issues/2310))
- Render correctly in reply to data when Event cannot be decrypted or has been redacted ([#2318](https://github.com/element-hq/element-x-android/issues/2318))
- Remove Compose Foundation version pinning workaround. This was done to avoid a bug introduced in the default foundation version used by the material3 library, but that has already been fixed.
- Remove `FilterHiddenStateEventsProcessor`, as this is already handled by the Rust SDK.
- Remove session preferences on user log out.
- Adjusted the login flow buttons so the continue button is always at the same height ([#825](https://github.com/element-hq/element-x-android/issues/825))
- Move migration screen to within the room list ([#2310](https://github.com/element-hq/element-x-android/issues/2310))
- Render correctly in reply to data when Event cannot be decrypted or has been redacted ([#2318](https://github.com/element-hq/element-x-android/issues/2318))
- Remove Compose Foundation version pinning workaround. This was done to avoid a bug introduced in the default foundation version used by the material3 library, but that has already been fixed.
- Remove `FilterHiddenStateEventsProcessor`, as this is already handled by the Rust SDK.
- Remove session preferences on user log out.
Breaking changes 🚨
-------------------
- Update Compound icons in the project. Since the icon prefix changed to `ic_compound_` and the `CompoundIcons` helper now contains the vector icons as composable functions.
- Update Compound icons in the project. Since the icon prefix changed to `ic_compound_` and the `CompoundIcons` helper now contains the vector icons as composable functions.
Changes in Element X v0.4.2 (2024-01-31)
========================================
@@ -163,31 +228,31 @@ Matrix SDK 🦀 v0.1.95
Features ✨
----------
- Add 'send private read receipts' option in advanced settings ([#2204](https://github.com/element-hq/element-x-android/issues/2204))
- Send typing notification ([#2240](https://github.com/element-hq/element-x-android/issues/2240)). Disabling the sending of typing notification and rendering typing notification will come soon.
- Add 'send private read receipts' option in advanced settings ([#2204](https://github.com/element-hq/element-x-android/issues/2204))
- Send typing notification ([#2240](https://github.com/element-hq/element-x-android/issues/2240)). Disabling the sending of typing notification and rendering typing notification will come soon.
Bugfixes 🐛
----------
- Make the room settings screen update automatically when new room info (name, avatar, topic) is available. ([#921](https://github.com/element-hq/element-x-android/issues/921))
- Update timeline items' read receipts when the room members info is loaded. ([#2176](https://github.com/element-hq/element-x-android/issues/2176))
- Edited text message bubbles should resize when edited ([#2260](https://github.com/element-hq/element-x-android/issues/2260))
- Ensure login and password exclude `\n` ([#2263](https://github.com/element-hq/element-x-android/issues/2263))
- Room list Ensure the indicators stay grey if the global setting is set to mention only and a regular message is received. ([#2282](https://github.com/element-hq/element-x-android/issues/2282))
- Make the room settings screen update automatically when new room info (name, avatar, topic) is available. ([#921](https://github.com/element-hq/element-x-android/issues/921))
- Update timeline items' read receipts when the room members info is loaded. ([#2176](https://github.com/element-hq/element-x-android/issues/2176))
- Edited text message bubbles should resize when edited ([#2260](https://github.com/element-hq/element-x-android/issues/2260))
- Ensure login and password exclude `\n` ([#2263](https://github.com/element-hq/element-x-android/issues/2263))
- Room list Ensure the indicators stay grey if the global setting is set to mention only and a regular message is received. ([#2282](https://github.com/element-hq/element-x-android/issues/2282))
Other changes
-------------
- Add a special logging configuration for nightlies so we can get more detailed info for existing issues. ([#+add-special-tracing-configuration-for-nightlies](https://github.com/element-hq/element-x-android/issues/+add-special-tracing-configuration-for-nightlies))
- Try mitigating unexpected logouts by making getting/storing session data use a Mutex for synchronization.
- Add a special logging configuration for nightlies so we can get more detailed info for existing issues. ([#+add-special-tracing-configuration-for-nightlies](https://github.com/element-hq/element-x-android/issues/+add-special-tracing-configuration-for-nightlies))
- Try mitigating unexpected logouts by making getting/storing session data use a Mutex for synchronization.
Also added some more logs so we can understand exactly where it's failing. ([#+try-mitigating-unexpected-logouts](https://github.com/element-hq/element-x-android/issues/+try-mitigating-unexpected-logouts))
- Upgrade Material3 Compose to `1.2.0-beta02`.
- Upgrade Material3 Compose to `1.2.0-beta02`.
There is also a constraint on a transitive Compose Foundation dependency version (1.6.0-beta02) that fixes the timeline scrolling issue. ([#0-beta02](https://github.com/element-hq/element-x-android/issues/0-beta02))
- Disambiguate display name in the timeline. ([#2215](https://github.com/element-hq/element-x-android/issues/2215))
- Disambiguate display name in the timeline. ([#2215](https://github.com/element-hq/element-x-android/issues/2215))
- Disambiguate display name in notifications ([#2224](https://github.com/element-hq/element-x-android/issues/2224))
- Remove room creation, self-join of room creator and 'this is the beginning of X' timeline items for DMs. ([#2217](https://github.com/element-hq/element-x-android/issues/2217))
- Encrypt databases used by the Rust SDK on Nightly and Debug builds. ([#2219](https://github.com/element-hq/element-x-android/issues/2219))
- Fallback to UnifiedPush (if available) if the PlayServices are not installed on the device. ([#2248](https://github.com/element-hq/element-x-android/issues/2248))
- Add "Report a problem" button to the onboarding screen ([#2275](https://github.com/element-hq/element-x-android/issues/2275))
- Add in app logs viewer to the "Report a problem" screen. ([#2276](https://github.com/element-hq/element-x-android/issues/2276))
- Remove room creation, self-join of room creator and 'this is the beginning of X' timeline items for DMs. ([#2217](https://github.com/element-hq/element-x-android/issues/2217))
- Encrypt databases used by the Rust SDK on Nightly and Debug builds. ([#2219](https://github.com/element-hq/element-x-android/issues/2219))
- Fallback to UnifiedPush (if available) if the PlayServices are not installed on the device. ([#2248](https://github.com/element-hq/element-x-android/issues/2248))
- Add "Report a problem" button to the onboarding screen ([#2275](https://github.com/element-hq/element-x-android/issues/2275))
- Add in app logs viewer to the "Report a problem" screen. ([#2276](https://github.com/element-hq/element-x-android/issues/2276))
Changes in Element X v0.4.1 (2024-01-17)
@@ -195,35 +260,35 @@ Changes in Element X v0.4.1 (2024-01-17)
Features ✨
----------
- Render m.sticker events ([#1949](https://github.com/element-hq/element-x-android/issues/1949))
- Add support for sending images from the keyboard ([#1977](https://github.com/element-hq/element-x-android/issues/1977))
- Added support for MSC4027 (render custom images in reactions) ([#2159](https://github.com/element-hq/element-x-android/issues/2159))
- Render m.sticker events ([#1949](https://github.com/element-hq/element-x-android/issues/1949))
- Add support for sending images from the keyboard ([#1977](https://github.com/element-hq/element-x-android/issues/1977))
- Added support for MSC4027 (render custom images in reactions) ([#2159](https://github.com/element-hq/element-x-android/issues/2159))
Bugfixes 🐛
----------
- Fix crash sending image with latest Posthog because of an usage of an internal Android method. ([#+crash-sending-image-with-latest-posthog](https://github.com/element-hq/element-x-android/issues/+crash-sending-image-with-latest-posthog))
- Make sure the media viewer tries the main url first (if not empty) then the thumbnail url and then not open if both are missing instead of failing with an error dialog ([#1949](https://github.com/element-hq/element-x-android/issues/1949))
- Fix room transition animation happens twice. ([#2084](https://github.com/element-hq/element-x-android/issues/2084))
- Disable ability to send reaction if the user does not have the permission to. ([#2093](https://github.com/element-hq/element-x-android/issues/2093))
- Trim whitespace at the end of messages to ensure we render the right content. ([#2099](https://github.com/element-hq/element-x-android/issues/2099))
- Fix crashes in room list when the last message for a room was an extremely long one (several thousands of characters) with no line breaks. ([#2105](https://github.com/element-hq/element-x-android/issues/2105))
- Disable rasterisation of Vector XMLs, which was causing crashes on API 23. ([#2124](https://github.com/element-hq/element-x-android/issues/2124))
- Use `SubomposeLayout` for `ContentAvoidingLayout` to prevent wrong measurements in the layout process, leading to cut-off text messages in the timeline. ([#2155](https://github.com/element-hq/element-x-android/issues/2155))
- Improve rendering of voice messages in the timeline in large displays ([#2156](https://github.com/element-hq/element-x-android/issues/2156))
- Fix no indication that user list is loading when inviting to room. ([#2172](https://github.com/element-hq/element-x-android/issues/2172))
- Hide keyboard when tapping on a message in the timeline. ([#2182](https://github.com/element-hq/element-x-android/issues/2182))
- Mention selector gets stuck when quickly deleting the prompt. ([#2192](https://github.com/element-hq/element-x-android/issues/2192))
- Hide verbose state events from the timeline ([#2216](https://github.com/element-hq/element-x-android/issues/2216))
- Fix crash sending image with latest Posthog because of an usage of an internal Android method. ([#+crash-sending-image-with-latest-posthog](https://github.com/element-hq/element-x-android/issues/+crash-sending-image-with-latest-posthog))
- Make sure the media viewer tries the main url first (if not empty) then the thumbnail url and then not open if both are missing instead of failing with an error dialog ([#1949](https://github.com/element-hq/element-x-android/issues/1949))
- Fix room transition animation happens twice. ([#2084](https://github.com/element-hq/element-x-android/issues/2084))
- Disable ability to send reaction if the user does not have the permission to. ([#2093](https://github.com/element-hq/element-x-android/issues/2093))
- Trim whitespace at the end of messages to ensure we render the right content. ([#2099](https://github.com/element-hq/element-x-android/issues/2099))
- Fix crashes in room list when the last message for a room was an extremely long one (several thousands of characters) with no line breaks. ([#2105](https://github.com/element-hq/element-x-android/issues/2105))
- Disable rasterisation of Vector XMLs, which was causing crashes on API 23. ([#2124](https://github.com/element-hq/element-x-android/issues/2124))
- Use `SubomposeLayout` for `ContentAvoidingLayout` to prevent wrong measurements in the layout process, leading to cut-off text messages in the timeline. ([#2155](https://github.com/element-hq/element-x-android/issues/2155))
- Improve rendering of voice messages in the timeline in large displays ([#2156](https://github.com/element-hq/element-x-android/issues/2156))
- Fix no indication that user list is loading when inviting to room. ([#2172](https://github.com/element-hq/element-x-android/issues/2172))
- Hide keyboard when tapping on a message in the timeline. ([#2182](https://github.com/element-hq/element-x-android/issues/2182))
- Mention selector gets stuck when quickly deleting the prompt. ([#2192](https://github.com/element-hq/element-x-android/issues/2192))
- Hide verbose state events from the timeline ([#2216](https://github.com/element-hq/element-x-android/issues/2216))
Other changes
-------------
- Only apply `com.autonomousapps.dependency-analysis` plugin in those modules that need it. ([#+only-apply-dependency-analysis-plugin-where-needed](https://github.com/element-hq/element-x-android/issues/+only-apply-dependency-analysis-plugin-where-needed))
- Migrate to Kover 0.7.X ([#1782](https://github.com/element-hq/element-x-android/issues/1782))
- Remove extra logout screen. ([#2072](https://github.com/element-hq/element-x-android/issues/2072))
- Handle `MembershipChange.NONE` rendering in the timeline. ([#2102](https://github.com/element-hq/element-x-android/issues/2102))
- Remove extra previews for timestamp view with 'document' case ([#2127](https://github.com/element-hq/element-x-android/issues/2127))
- Bump AGP version to 8.2.0 ([#2142](https://github.com/element-hq/element-x-android/issues/2142))
- Replace 'leave room' text with 'leave conversation' for DMs. ([#2218](https://github.com/element-hq/element-x-android/issues/2218))
- Only apply `com.autonomousapps.dependency-analysis` plugin in those modules that need it. ([#+only-apply-dependency-analysis-plugin-where-needed](https://github.com/element-hq/element-x-android/issues/+only-apply-dependency-analysis-plugin-where-needed))
- Migrate to Kover 0.7.X ([#1782](https://github.com/element-hq/element-x-android/issues/1782))
- Remove extra logout screen. ([#2072](https://github.com/element-hq/element-x-android/issues/2072))
- Handle `MembershipChange.NONE` rendering in the timeline. ([#2102](https://github.com/element-hq/element-x-android/issues/2102))
- Remove extra previews for timestamp view with 'document' case ([#2127](https://github.com/element-hq/element-x-android/issues/2127))
- Bump AGP version to 8.2.0 ([#2142](https://github.com/element-hq/element-x-android/issues/2142))
- Replace 'leave room' text with 'leave conversation' for DMs. ([#2218](https://github.com/element-hq/element-x-android/issues/2218))
Changes in Element X v0.4.0 (2023-12-22)
@@ -231,75 +296,75 @@ Changes in Element X v0.4.0 (2023-12-22)
Features ✨
----------
- Use the RTE library `TextView` to render text events in the timeline. Add support for mention pills - with no interaction yet. ([#1433](https://github.com/element-hq/element-x-android/issues/1433))
- Tapping on a user mention pill opens their profile. ([#1448](https://github.com/element-hq/element-x-android/issues/1448))
- Display different notifications for mentions. ([#1451](https://github.com/element-hq/element-x-android/issues/1451))
- Reply to a poll ([#1848](https://github.com/element-hq/element-x-android/issues/1848))
- Add plain text representation of messages ([#1850](https://github.com/element-hq/element-x-android/issues/1850))
- Allow polls to be edited when they have not been voted on ([#1869](https://github.com/element-hq/element-x-android/issues/1869))
- Scroll to end of timeline when sending a new message. ([#1877](https://github.com/element-hq/element-x-android/issues/1877))
- Confirm back navigation when editing a poll only if the poll was changed ([#1886](https://github.com/element-hq/element-x-android/issues/1886))
- Add option to delete a poll while editing the poll ([#1895](https://github.com/element-hq/element-x-android/issues/1895))
- Open room member avatar when you click on it inside the member details screen. ([#1907](https://github.com/element-hq/element-x-android/issues/1907))
- Poll history of a room is now accessible from the room details screen. ([#2014](https://github.com/element-hq/element-x-android/issues/2014))
- Always close the invite list screen when there is no more invite. ([#2022](https://github.com/element-hq/element-x-android/issues/2022))
- Use the RTE library `TextView` to render text events in the timeline. Add support for mention pills - with no interaction yet. ([#1433](https://github.com/element-hq/element-x-android/issues/1433))
- Tapping on a user mention pill opens their profile. ([#1448](https://github.com/element-hq/element-x-android/issues/1448))
- Display different notifications for mentions. ([#1451](https://github.com/element-hq/element-x-android/issues/1451))
- Reply to a poll ([#1848](https://github.com/element-hq/element-x-android/issues/1848))
- Add plain text representation of messages ([#1850](https://github.com/element-hq/element-x-android/issues/1850))
- Allow polls to be edited when they have not been voted on ([#1869](https://github.com/element-hq/element-x-android/issues/1869))
- Scroll to end of timeline when sending a new message. ([#1877](https://github.com/element-hq/element-x-android/issues/1877))
- Confirm back navigation when editing a poll only if the poll was changed ([#1886](https://github.com/element-hq/element-x-android/issues/1886))
- Add option to delete a poll while editing the poll ([#1895](https://github.com/element-hq/element-x-android/issues/1895))
- Open room member avatar when you click on it inside the member details screen. ([#1907](https://github.com/element-hq/element-x-android/issues/1907))
- Poll history of a room is now accessible from the room details screen. ([#2014](https://github.com/element-hq/element-x-android/issues/2014))
- Always close the invite list screen when there is no more invite. ([#2022](https://github.com/element-hq/element-x-android/issues/2022))
Bugfixes 🐛
----------
- Fix see room in the room list after leaving it. ([#1006](https://github.com/element-hq/element-x-android/issues/1006))
- Adjust mention pills font weight and horizontal padding ([#1449](https://github.com/element-hq/element-x-android/issues/1449))
- Font size in 'All Chats' header was changing mid-animation. ([#1572](https://github.com/element-hq/element-x-android/issues/1572))
- Accessibility: do not read initial used for avatar out loud. ([#1864](https://github.com/element-hq/element-x-android/issues/1864))
- Use the right avatar for DMs in DM rooms ([#1912](https://github.com/element-hq/element-x-android/issues/1912))
- Fix scaling of timeline images: don't crop, don't set min/max aspect ratio values. ([#1940](https://github.com/element-hq/element-x-android/issues/1940))
- Fix rendering of user name with vertical text by clipping the text. ([#1950](https://github.com/element-hq/element-x-android/issues/1950))
- Do not render `roomId` if the room has no canonical alias. ([#1970](https://github.com/element-hq/element-x-android/issues/1970))
- Fix avatar not displayed in notification when the app is not in background ([#1991](https://github.com/element-hq/element-x-android/issues/1991))
- Fix wording in room invite members view: `Send` -> `Invite`. ([#2037](https://github.com/element-hq/element-x-android/issues/2037))
- Timestamp positioning was broken, specially for edited messages. ([#2060](https://github.com/element-hq/element-x-android/issues/2060))
- Emojis in custom reaction bottom sheet are too tiny. ([#2066](https://github.com/element-hq/element-x-android/issues/2066))
- Set a default power level to join calls. Also, create new rooms taking this power level into account.
- Fix see room in the room list after leaving it. ([#1006](https://github.com/element-hq/element-x-android/issues/1006))
- Adjust mention pills font weight and horizontal padding ([#1449](https://github.com/element-hq/element-x-android/issues/1449))
- Font size in 'All Chats' header was changing mid-animation. ([#1572](https://github.com/element-hq/element-x-android/issues/1572))
- Accessibility: do not read initial used for avatar out loud. ([#1864](https://github.com/element-hq/element-x-android/issues/1864))
- Use the right avatar for DMs in DM rooms ([#1912](https://github.com/element-hq/element-x-android/issues/1912))
- Fix scaling of timeline images: don't crop, don't set min/max aspect ratio values. ([#1940](https://github.com/element-hq/element-x-android/issues/1940))
- Fix rendering of user name with vertical text by clipping the text. ([#1950](https://github.com/element-hq/element-x-android/issues/1950))
- Do not render `roomId` if the room has no canonical alias. ([#1970](https://github.com/element-hq/element-x-android/issues/1970))
- Fix avatar not displayed in notification when the app is not in background ([#1991](https://github.com/element-hq/element-x-android/issues/1991))
- Fix wording in room invite members view: `Send` -> `Invite`. ([#2037](https://github.com/element-hq/element-x-android/issues/2037))
- Timestamp positioning was broken, specially for edited messages. ([#2060](https://github.com/element-hq/element-x-android/issues/2060))
- Emojis in custom reaction bottom sheet are too tiny. ([#2066](https://github.com/element-hq/element-x-android/issues/2066))
- Set a default power level to join calls. Also, create new rooms taking this power level into account.
Other changes
-------------
- Add a warning for 'mentions and keywords only' notification option if your homeserver does not support it ([#1749](https://github.com/element-hq/element-x-android/issues/1749))
- Remove `:libraries:theme` module, extract theme and tokens to [Compound Android](https://github.com/element-hq/compound-android). ([#1833](https://github.com/element-hq/element-x-android/issues/1833))
- Update poll icons from Compound ([#1849](https://github.com/element-hq/element-x-android/issues/1849))
- Add ability to see the room avatar in the media viewer. ([#1918](https://github.com/element-hq/element-x-android/issues/1918))
- RoomList: introduce incremental loading to improve performances. ([#1920](https://github.com/element-hq/element-x-android/issues/1920))
- Add toggle in the notification settings to disable notifications for room invites. ([#1944](https://github.com/element-hq/element-x-android/issues/1944))
- Update rendering of Emojis displayed during verification. ([#1965](https://github.com/element-hq/element-x-android/issues/1965))
- Hide sender info in direct rooms ([#1979](https://github.com/element-hq/element-x-android/issues/1979))
- Render images in Notification ([#1991](https://github.com/element-hq/element-x-android/issues/1991))
- Only process content.json from Localazy. ([#2031](https://github.com/element-hq/element-x-android/issues/2031))
- Always show user avatar in message action sheet ([#2032](https://github.com/element-hq/element-x-android/issues/2032))
- Hide room list dropdown menu. ([#2062](https://github.com/element-hq/element-x-android/issues/2062))
- Enable Chat backup, Mentions and Read Receipt in release. ([#2087](https://github.com/element-hq/element-x-android/issues/2087))
- Make most code used in Compose from `:libraries:matrix` and derived classes Immutable or Stable.
- Add a warning for 'mentions and keywords only' notification option if your homeserver does not support it ([#1749](https://github.com/element-hq/element-x-android/issues/1749))
- Remove `:libraries:theme` module, extract theme and tokens to [Compound Android](https://github.com/element-hq/compound-android). ([#1833](https://github.com/element-hq/element-x-android/issues/1833))
- Update poll icons from Compound ([#1849](https://github.com/element-hq/element-x-android/issues/1849))
- Add ability to see the room avatar in the media viewer. ([#1918](https://github.com/element-hq/element-x-android/issues/1918))
- RoomList: introduce incremental loading to improve performances. ([#1920](https://github.com/element-hq/element-x-android/issues/1920))
- Add toggle in the notification settings to disable notifications for room invites. ([#1944](https://github.com/element-hq/element-x-android/issues/1944))
- Update rendering of Emojis displayed during verification. ([#1965](https://github.com/element-hq/element-x-android/issues/1965))
- Hide sender info in direct rooms ([#1979](https://github.com/element-hq/element-x-android/issues/1979))
- Render images in Notification ([#1991](https://github.com/element-hq/element-x-android/issues/1991))
- Only process content.json from Localazy. ([#2031](https://github.com/element-hq/element-x-android/issues/2031))
- Always show user avatar in message action sheet ([#2032](https://github.com/element-hq/element-x-android/issues/2032))
- Hide room list dropdown menu. ([#2062](https://github.com/element-hq/element-x-android/issues/2062))
- Enable Chat backup, Mentions and Read Receipt in release. ([#2087](https://github.com/element-hq/element-x-android/issues/2087))
- Make most code used in Compose from `:libraries:matrix` and derived classes Immutable or Stable.
Changes in Element X v0.3.2 (2023-11-22)
========================================
Features ✨
----------
- Add ongoing call indicator to rooms lists items. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Add support for typing mentions in the message composer. ([#1453](https://github.com/element-hq/element-x-android/issues/1453))
- Add intentional mentions to messages. This needs to be enabled in developer options since it's disabled by default. ([#1591](https://github.com/element-hq/element-x-android/issues/1591))
- Update voice message recording behaviour. Instead of holding the record button, users can now tap the record button to start recording and tap again to stop recording. ([#1784](https://github.com/element-hq/element-x-android/issues/1784))
- Add ongoing call indicator to rooms lists items. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Add support for typing mentions in the message composer. ([#1453](https://github.com/element-hq/element-x-android/issues/1453))
- Add intentional mentions to messages. This needs to be enabled in developer options since it's disabled by default. ([#1591](https://github.com/element-hq/element-x-android/issues/1591))
- Update voice message recording behaviour. Instead of holding the record button, users can now tap the record button to start recording and tap again to stop recording. ([#1784](https://github.com/element-hq/element-x-android/issues/1784))
Bugfixes 🐛
----------
- Always ensure media temp dir exists ([#1790](https://github.com/element-hq/element-x-android/issues/1790))
- Always ensure media temp dir exists ([#1790](https://github.com/element-hq/element-x-android/issues/1790))
Other changes
-------------
- Update icons and move away from `PreferenceText` components. ([#1718](https://github.com/element-hq/element-x-android/issues/1718))
- Add item "This is the beginning of..." at the beginning of the timeline. ([#1801](https://github.com/element-hq/element-x-android/issues/1801))
- LockScreen : rework LoggedInFlowNode and back management when locked. ([#1806](https://github.com/element-hq/element-x-android/issues/1806))
- Suppress usage of removeTimeline method. ([#1824](https://github.com/element-hq/element-x-android/issues/1824))
- Remove Element Call feature flag, it's now always enabled.
- Reverted the EC base URL to `https://call.element.io`.
- Moved the option to override this URL to developer settings from advanced settings.
- Update icons and move away from `PreferenceText` components. ([#1718](https://github.com/element-hq/element-x-android/issues/1718))
- Add item "This is the beginning of..." at the beginning of the timeline. ([#1801](https://github.com/element-hq/element-x-android/issues/1801))
- LockScreen : rework LoggedInFlowNode and back management when locked. ([#1806](https://github.com/element-hq/element-x-android/issues/1806))
- Suppress usage of removeTimeline method. ([#1824](https://github.com/element-hq/element-x-android/issues/1824))
- Remove Element Call feature flag, it's now always enabled.
- Reverted the EC base URL to `https://call.element.io`.
- Moved the option to override this URL to developer settings from advanced settings.
Changes in Element X v0.3.1 (2023-11-09)
@@ -307,16 +372,16 @@ Changes in Element X v0.3.1 (2023-11-09)
Features ✨
----------
- Chat backup is still under a feature flag, but when enabled, user can enter their recovery key (it's also possible to input a passphrase) to unlock the encrypted room history. ([#1770](https://github.com/element-hq/element-x-android/pull/1770))
- Chat backup is still under a feature flag, but when enabled, user can enter their recovery key (it's also possible to input a passphrase) to unlock the encrypted room history. ([#1770](https://github.com/element-hq/element-x-android/pull/1770))
Bugfixes 🐛
----------
- Improve confusing text in the 'ready to start verification' screen. ([#879](https://github.com/element-hq/element-x-android/issues/879))
- Message composer wasn't resized when selecting a several lines message to reply to, then a single line one. ([#1560](https://github.com/element-hq/element-x-android/issues/1560))
- Improve confusing text in the 'ready to start verification' screen. ([#879](https://github.com/element-hq/element-x-android/issues/879))
- Message composer wasn't resized when selecting a several lines message to reply to, then a single line one. ([#1560](https://github.com/element-hq/element-x-android/issues/1560))
Other changes
-------------
- PIN: Set lock grace period to 0. ([#1732](https://github.com/element-hq/element-x-android/issues/1732))
- PIN: Set lock grace period to 0. ([#1732](https://github.com/element-hq/element-x-android/issues/1732))
Changes in Element X v0.3.0 (2023-10-31)
@@ -324,24 +389,24 @@ Changes in Element X v0.3.0 (2023-10-31)
Features ✨
----------
- Element Call: change the 'join call' button in a chat room when there's an active call. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Mentions: add mentions suggestion view in RTE ([#1452](https://github.com/element-hq/element-x-android/issues/1452))
- Record and send voice messages ([#1596](https://github.com/element-hq/element-x-android/issues/1596))
- Enable voice messages for all users ([#1669](https://github.com/element-hq/element-x-android/issues/1669))
- Receive and play a voice message ([#2084](https://github.com/element-hq/element-x-android/issues/2084))
- Enable Element Call integration in rooms by default, fix several issues when creating or joining calls.
- Element Call: change the 'join call' button in a chat room when there's an active call. ([#1158](https://github.com/element-hq/element-x-android/issues/1158))
- Mentions: add mentions suggestion view in RTE ([#1452](https://github.com/element-hq/element-x-android/issues/1452))
- Record and send voice messages ([#1596](https://github.com/element-hq/element-x-android/issues/1596))
- Enable voice messages for all users ([#1669](https://github.com/element-hq/element-x-android/issues/1669))
- Receive and play a voice message ([#2084](https://github.com/element-hq/element-x-android/issues/2084))
- Enable Element Call integration in rooms by default, fix several issues when creating or joining calls.
Bugfixes 🐛
----------
- Group fallback notification to avoid having plenty of them displayed. ([#994](https://github.com/element-hq/element-x-android/issues/994))
- Hide keyboard when exiting the chat room screen. ([#1375](https://github.com/element-hq/element-x-android/issues/1375))
- Always register the pusher when application starts ([#1481](https://github.com/element-hq/element-x-android/issues/1481))
- Ensure screen does not turn off when playing a video ([#1519](https://github.com/element-hq/element-x-android/issues/1519))
- Fix issue where text is cleared when cancelling a reply ([#1617](https://github.com/element-hq/element-x-android/issues/1617))
- Group fallback notification to avoid having plenty of them displayed. ([#994](https://github.com/element-hq/element-x-android/issues/994))
- Hide keyboard when exiting the chat room screen. ([#1375](https://github.com/element-hq/element-x-android/issues/1375))
- Always register the pusher when application starts ([#1481](https://github.com/element-hq/element-x-android/issues/1481))
- Ensure screen does not turn off when playing a video ([#1519](https://github.com/element-hq/element-x-android/issues/1519))
- Fix issue where text is cleared when cancelling a reply ([#1617](https://github.com/element-hq/element-x-android/issues/1617))
Other changes
-------------
- Remove usage of blocking methods. ([#1563](https://github.com/element-hq/element-x-android/issues/1563))
- Remove usage of blocking methods. ([#1563](https://github.com/element-hq/element-x-android/issues/1563))
Changes in Element X v0.2.4 (2023-10-12)
@@ -349,20 +414,20 @@ Changes in Element X v0.2.4 (2023-10-12)
Features ✨
----------
- [Rich text editor] Add full screen mode ([#1447](https://github.com/element-hq/element-x-android/issues/1447))
- Improve rendering of m.emote. ([#1497](https://github.com/element-hq/element-x-android/issues/1497))
- Improve deleted session behavior. ([#1520](https://github.com/element-hq/element-x-android/issues/1520))
- [Rich text editor] Add full screen mode ([#1447](https://github.com/element-hq/element-x-android/issues/1447))
- Improve rendering of m.emote. ([#1497](https://github.com/element-hq/element-x-android/issues/1497))
- Improve deleted session behavior. ([#1520](https://github.com/element-hq/element-x-android/issues/1520))
Bugfixes 🐛
----------
- WebP images can't be sent as media. ([#1483](https://github.com/element-hq/element-x-android/issues/1483))
- Fix back button not working in bottom sheets. ([#1517](https://github.com/element-hq/element-x-android/issues/1517))
- Render body of unknown msgtype in the timeline and in the room list ([#1539](https://github.com/element-hq/element-x-android/issues/1539))
- WebP images can't be sent as media. ([#1483](https://github.com/element-hq/element-x-android/issues/1483))
- Fix back button not working in bottom sheets. ([#1517](https://github.com/element-hq/element-x-android/issues/1517))
- Render body of unknown msgtype in the timeline and in the room list ([#1539](https://github.com/element-hq/element-x-android/issues/1539))
Other changes
-------------
- Room : makes subscribeToSync/unsubscribeFromSync suspendable. ([#1457](https://github.com/element-hq/element-x-android/issues/1457))
- Add some Konsist tests. ([#1526](https://github.com/element-hq/element-x-android/issues/1526))
- Room : makes subscribeToSync/unsubscribeFromSync suspendable. ([#1457](https://github.com/element-hq/element-x-android/issues/1457))
- Add some Konsist tests. ([#1526](https://github.com/element-hq/element-x-android/issues/1526))
Changes in Element X v0.2.3 (2023-09-27)
@@ -370,12 +435,12 @@ Changes in Element X v0.2.3 (2023-09-27)
Features ✨
----------
- Handle installation of Apks from the media viewer. ([#1432](https://github.com/element-hq/element-x-android/pull/1432))
- Integrate SDK 0.1.58 ([#1437](https://github.com/element-hq/element-x-android/pull/1437))
- Handle installation of Apks from the media viewer. ([#1432](https://github.com/element-hq/element-x-android/pull/1432))
- Integrate SDK 0.1.58 ([#1437](https://github.com/element-hq/element-x-android/pull/1437))
Other changes
-------------
- Element call: add custom parameters to Element Call urls. ([#1434](https://github.com/element-hq/element-x-android/issues/1434))
- Element call: add custom parameters to Element Call urls. ([#1434](https://github.com/element-hq/element-x-android/issues/1434))
Changes in Element X v0.2.2 (2023-09-21)
@@ -383,8 +448,8 @@ Changes in Element X v0.2.2 (2023-09-21)
Bugfixes 🐛
----------
- Add animation when rendering the timeline to avoid glitches. ([#1323](https://github.com/element-hq/element-x-android/issues/1323))
- Fix crash when trying to take a photo or record a video. ([#1395](https://github.com/element-hq/element-x-android/issues/1395))
- Add animation when rendering the timeline to avoid glitches. ([#1323](https://github.com/element-hq/element-x-android/issues/1323))
- Fix crash when trying to take a photo or record a video. ([#1395](https://github.com/element-hq/element-x-android/issues/1395))
Changes in Element X v0.2.1 (2023-09-20)
@@ -392,19 +457,19 @@ Changes in Element X v0.2.1 (2023-09-20)
Features ✨
----------
- Bump Rust SDK to `v0.1.56`
- [Rich text editor] Add link support to rich text editor ([#1309](https://github.com/element-hq/element-x-android/issues/1309))
- Let the SDK figure the best scheme given an homeserver URL (thus allowing HTTP homeservers) ([#1382](https://github.com/element-hq/element-x-android/issues/1382))
- Bump Rust SDK to `v0.1.56`
- [Rich text editor] Add link support to rich text editor ([#1309](https://github.com/element-hq/element-x-android/issues/1309))
- Let the SDK figure the best scheme given an homeserver URL (thus allowing HTTP homeservers) ([#1382](https://github.com/element-hq/element-x-android/issues/1382))
Bugfixes 🐛
----------
- Fix ANR on RoomList when notification settings change. ([#1370](https://github.com/element-hq/element-x-android/issues/1370))
- Fix ANR on RoomList when notification settings change. ([#1370](https://github.com/element-hq/element-x-android/issues/1370))
Other changes
-------------
- Element Call: support scheme `io.element.call` ([#1377](https://github.com/element-hq/element-x-android/issues/1377))
- [DI] Rework how dagger components are created and provided. ([#1378](https://github.com/element-hq/element-x-android/issues/1378))
- Remove usage of async-uniffi as it leads to a deadlocks and memory leaks. ([#1381](https://github.com/element-hq/element-x-android/issues/1381))
- Element Call: support scheme `io.element.call` ([#1377](https://github.com/element-hq/element-x-android/issues/1377))
- [DI] Rework how dagger components are created and provided. ([#1378](https://github.com/element-hq/element-x-android/issues/1378))
- Remove usage of async-uniffi as it leads to a deadlocks and memory leaks. ([#1381](https://github.com/element-hq/element-x-android/issues/1381))
Changes in Element X v0.2.0 (2023-09-18)
@@ -412,38 +477,38 @@ Changes in Element X v0.2.0 (2023-09-18)
Features ✨
----------
- Bump Rust SDK to `v0.1.54`
- Add a "Mute" shortcut icon and a "Notifications" section in the room details screen ([#506](https://github.com/element-hq/element-x-android/issues/506))
- Add a notification permission screen to the initial flow. ([#897](https://github.com/element-hq/element-x-android/issues/897))
- Integrate Element Call into EX by embedding a call in a WebView. ([#1300](https://github.com/element-hq/element-x-android/issues/1300))
- Implement Bloom effect modifier. ([#1217](https://github.com/element-hq/element-x-android/issues/1217))
- Set color on display name and default avatar in the timeline. ([#1224](https://github.com/element-hq/element-x-android/issues/1224))
- Display a thread decorator in timeline so we know when a message is coming from a thread. ([#1236](https://github.com/element-hq/element-x-android/issues/1236))
- [Rich text editor] Integrate rich text editor library. Note that markdown is now not supported and further formatting support will be introduced through the rich text editor. ([#1172](https://github.com/element-hq/element-x-android/issues/1172))
- [Rich text editor] Add formatting menu (accessible via the '+' button) ([#1261](https://github.com/element-hq/element-x-android/issues/1261))
- [Rich text editor] Add feature flag for rich text editor. Markdown support can now be enabled by disabling the rich text editor. ([#1289](https://github.com/element-hq/element-x-android/issues/1289))
- [Rich text editor] Update design ([#1332](https://github.com/element-hq/element-x-android/issues/1332))
- Bump Rust SDK to `v0.1.54`
- Add a "Mute" shortcut icon and a "Notifications" section in the room details screen ([#506](https://github.com/element-hq/element-x-android/issues/506))
- Add a notification permission screen to the initial flow. ([#897](https://github.com/element-hq/element-x-android/issues/897))
- Integrate Element Call into EX by embedding a call in a WebView. ([#1300](https://github.com/element-hq/element-x-android/issues/1300))
- Implement Bloom effect modifier. ([#1217](https://github.com/element-hq/element-x-android/issues/1217))
- Set color on display name and default avatar in the timeline. ([#1224](https://github.com/element-hq/element-x-android/issues/1224))
- Display a thread decorator in timeline so we know when a message is coming from a thread. ([#1236](https://github.com/element-hq/element-x-android/issues/1236))
- [Rich text editor] Integrate rich text editor library. Note that markdown is now not supported and further formatting support will be introduced through the rich text editor. ([#1172](https://github.com/element-hq/element-x-android/issues/1172))
- [Rich text editor] Add formatting menu (accessible via the '+' button) ([#1261](https://github.com/element-hq/element-x-android/issues/1261))
- [Rich text editor] Add feature flag for rich text editor. Markdown support can now be enabled by disabling the rich text editor. ([#1289](https://github.com/element-hq/element-x-android/issues/1289))
- [Rich text editor] Update design ([#1332](https://github.com/element-hq/element-x-android/issues/1332))
Bugfixes 🐛
----------
- Make links in room topic clickable ([#612](https://github.com/element-hq/element-x-android/issues/612))
- Reply action: harmonize conditions in bottom sheet and swipe to reply. ([#1173](https://github.com/element-hq/element-x-android/issues/1173))
- Fix system bar color after login on light theme. ([#1222](https://github.com/element-hq/element-x-android/issues/1222))
- Fix long click on simple formatted messages ([#1232](https://github.com/element-hq/element-x-android/issues/1232))
- Enable polls in release build. ([#1241](https://github.com/element-hq/element-x-android/issues/1241))
- Fix top padding in room list when app is opened in offline mode. ([#1297](https://github.com/element-hq/element-x-android/issues/1297))
- [Rich text editor] Fix 'text formatting' option only partially visible ([#1335](https://github.com/element-hq/element-x-android/issues/1335))
- [Rich text editor] Ensure keyboard opens for reply and text formatting modes ([#1337](https://github.com/element-hq/element-x-android/issues/1337))
- [Rich text editor] Fix placeholder spilling onto multiple lines ([#1347](https://github.com/element-hq/element-x-android/issues/1347))
- Make links in room topic clickable ([#612](https://github.com/element-hq/element-x-android/issues/612))
- Reply action: harmonize conditions in bottom sheet and swipe to reply. ([#1173](https://github.com/element-hq/element-x-android/issues/1173))
- Fix system bar color after login on light theme. ([#1222](https://github.com/element-hq/element-x-android/issues/1222))
- Fix long click on simple formatted messages ([#1232](https://github.com/element-hq/element-x-android/issues/1232))
- Enable polls in release build. ([#1241](https://github.com/element-hq/element-x-android/issues/1241))
- Fix top padding in room list when app is opened in offline mode. ([#1297](https://github.com/element-hq/element-x-android/issues/1297))
- [Rich text editor] Fix 'text formatting' option only partially visible ([#1335](https://github.com/element-hq/element-x-android/issues/1335))
- [Rich text editor] Ensure keyboard opens for reply and text formatting modes ([#1337](https://github.com/element-hq/element-x-android/issues/1337))
- [Rich text editor] Fix placeholder spilling onto multiple lines ([#1347](https://github.com/element-hq/element-x-android/issues/1347))
Other changes
-------------
- Add a sub-screen "Notifications" in the existing application Settings ([#510](https://github.com/element-hq/element-x-android/issues/510))
- Exclude some groups related to analytics to be included. ([#1191](https://github.com/element-hq/element-x-android/issues/1191))
- Use the new SyncIndicator API. ([#1244](https://github.com/element-hq/element-x-android/issues/1244))
- Improve RoomSummary mapping by using RoomInfo. ([#1251](https://github.com/element-hq/element-x-android/issues/1251))
- Ensure Posthog data are sent to "https://posthog.element.io" ([#1269](https://github.com/element-hq/element-x-android/issues/1269))
- New app icon, with monochrome support. ([#1363](https://github.com/element-hq/element-x-android/issues/1363))
- Add a sub-screen "Notifications" in the existing application Settings ([#510](https://github.com/element-hq/element-x-android/issues/510))
- Exclude some groups related to analytics to be included. ([#1191](https://github.com/element-hq/element-x-android/issues/1191))
- Use the new SyncIndicator API. ([#1244](https://github.com/element-hq/element-x-android/issues/1244))
- Improve RoomSummary mapping by using RoomInfo. ([#1251](https://github.com/element-hq/element-x-android/issues/1251))
- Ensure Posthog data are sent to "https://posthog.element.io" ([#1269](https://github.com/element-hq/element-x-android/issues/1269))
- New app icon, with monochrome support. ([#1363](https://github.com/element-hq/element-x-android/issues/1363))
Changes in Element X v0.1.6 (2023-09-04)
@@ -451,22 +516,22 @@ Changes in Element X v0.1.6 (2023-09-04)
Features ✨
----------
- Enable the Polls feature. Allows to create, view, vote and end polls. ([#1196](https://github.com/element-hq/element-x-android/issues/1196))
- Enable the Polls feature. Allows to create, view, vote and end polls. ([#1196](https://github.com/element-hq/element-x-android/issues/1196))
- Create poll. ([#1143](https://github.com/element-hq/element-x-android/issues/1143))
Bugfixes 🐛
----------
- Ensure notification for Event from encrypted room get decrypted content. ([#1178](https://github.com/element-hq/element-x-android/issues/1178))
- Make sure Snackbars are only displayed once. ([#928](https://github.com/element-hq/element-x-android/issues/928))
- Fix the orientation of sent images. ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
- Bug reporter crashes when 'send logs' is disabled. ([#1168](https://github.com/element-hq/element-x-android/issues/1168))
- Add missing link to the terms on the analytics setting screen. ([#1177](https://github.com/element-hq/element-x-android/issues/1177))
- Re-enable `SyncService.withEncryptionSync` to improve decryption of notifications. ([#1198](https://github.com/element-hq/element-x-android/issues/1198))
- Crash with `aspectRatio` modifier when `Float.NaN` was used as input. ([#1995](https://github.com/element-hq/element-x-android/issues/1995))
- Make sure Snackbars are only displayed once. ([#928](https://github.com/element-hq/element-x-android/issues/928))
- Fix the orientation of sent images. ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
- Bug reporter crashes when 'send logs' is disabled. ([#1168](https://github.com/element-hq/element-x-android/issues/1168))
- Add missing link to the terms on the analytics setting screen. ([#1177](https://github.com/element-hq/element-x-android/issues/1177))
- Re-enable `SyncService.withEncryptionSync` to improve decryption of notifications. ([#1198](https://github.com/element-hq/element-x-android/issues/1198))
- Crash with `aspectRatio` modifier when `Float.NaN` was used as input. ([#1995](https://github.com/element-hq/element-x-android/issues/1995))
Other changes
-------------
- Remove unnecessary year in copyright mention. ([#1187](https://github.com/element-hq/element-x-android/issues/1187))
- Remove unnecessary year in copyright mention. ([#1187](https://github.com/element-hq/element-x-android/issues/1187))
Changes in Element X v0.1.5 (2023-08-28)
@@ -474,7 +539,7 @@ Changes in Element X v0.1.5 (2023-08-28)
Bugfixes 🐛
----------
- Fix crash when opening any room. ([#1160](https://github.com/element-hq/element-x-android/issues/1160))
- Fix crash when opening any room. ([#1160](https://github.com/element-hq/element-x-android/issues/1160))
Changes in Element X v0.1.4 (2023-08-28)
@@ -482,32 +547,32 @@ Changes in Element X v0.1.4 (2023-08-28)
Features ✨
----------
- Allow cancelling media upload ([#769](https://github.com/element-hq/element-x-android/issues/769))
- Enable OIDC support. ([#1127](https://github.com/element-hq/element-x-android/issues/1127))
- Add a "Setting up account" screen, displayed the first time the user logs in to the app (per account). ([#1149](https://github.com/element-hq/element-x-android/issues/1149))
- Allow cancelling media upload ([#769](https://github.com/element-hq/element-x-android/issues/769))
- Enable OIDC support. ([#1127](https://github.com/element-hq/element-x-android/issues/1127))
- Add a "Setting up account" screen, displayed the first time the user logs in to the app (per account). ([#1149](https://github.com/element-hq/element-x-android/issues/1149))
Bugfixes 🐛
----------
- Videos sent from the app were cropped in some cases. ([#862](https://github.com/element-hq/element-x-android/issues/862))
- Timeline: sender names are now displayed in one single line. ([#1033](https://github.com/element-hq/element-x-android/issues/1033))
- Fix `TextButtons` being displayed in black. ([#1077](https://github.com/element-hq/element-x-android/issues/1077))
- Linkify links in HTML contents. ([#1079](https://github.com/element-hq/element-x-android/issues/1079))
- Fix bug reporter failing after not finding some log files. ([#1082](https://github.com/element-hq/element-x-android/issues/1082))
- Fix rendering of inline elements in list items. ([#1090](https://github.com/element-hq/element-x-android/issues/1090))
- Fix crash RuntimeException "No matching key found for the ciphertext in the stream" ([#1101](https://github.com/element-hq/element-x-android/issues/1101))
- Make links in messages clickable again. ([#1111](https://github.com/element-hq/element-x-android/issues/1111))
- When event has no id, just cancel parsing the latest room message for a room. ([#1125](https://github.com/element-hq/element-x-android/issues/1125))
- Only display verification prompt after initial sync is done. ([#1131](https://github.com/element-hq/element-x-android/issues/1131))
- Videos sent from the app were cropped in some cases. ([#862](https://github.com/element-hq/element-x-android/issues/862))
- Timeline: sender names are now displayed in one single line. ([#1033](https://github.com/element-hq/element-x-android/issues/1033))
- Fix `TextButtons` being displayed in black. ([#1077](https://github.com/element-hq/element-x-android/issues/1077))
- Linkify links in HTML contents. ([#1079](https://github.com/element-hq/element-x-android/issues/1079))
- Fix bug reporter failing after not finding some log files. ([#1082](https://github.com/element-hq/element-x-android/issues/1082))
- Fix rendering of inline elements in list items. ([#1090](https://github.com/element-hq/element-x-android/issues/1090))
- Fix crash RuntimeException "No matching key found for the ciphertext in the stream" ([#1101](https://github.com/element-hq/element-x-android/issues/1101))
- Make links in messages clickable again. ([#1111](https://github.com/element-hq/element-x-android/issues/1111))
- When event has no id, just cancel parsing the latest room message for a room. ([#1125](https://github.com/element-hq/element-x-android/issues/1125))
- Only display verification prompt after initial sync is done. ([#1131](https://github.com/element-hq/element-x-android/issues/1131))
In development 🚧
----------------
- [Poll] Add feature flag in developer options ([#1064](https://github.com/element-hq/element-x-android/issues/1064))
- [Polls] Improve UI and render ended state ([#1113](https://github.com/element-hq/element-x-android/issues/1113))
- [Poll] Add feature flag in developer options ([#1064](https://github.com/element-hq/element-x-android/issues/1064))
- [Polls] Improve UI and render ended state ([#1113](https://github.com/element-hq/element-x-android/issues/1113))
Other changes
-------------
- Compound: add `ListItem` and `ListSectionHeader` components. ([#990](https://github.com/element-hq/element-x-android/issues/990))
- Migrate `object` to `data object` in sealed interface / class #1135 ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
- Compound: add `ListItem` and `ListSectionHeader` components. ([#990](https://github.com/element-hq/element-x-android/issues/990))
- Migrate `object` to `data object` in sealed interface / class #1135 ([#1135](https://github.com/element-hq/element-x-android/issues/1135))
Changes in Element X v0.1.2 (2023-08-16)
@@ -515,20 +580,20 @@ Changes in Element X v0.1.2 (2023-08-16)
Bugfixes 🐛
----------
- Filter push notifications using push rules. ([#640](https://github.com/element-hq/element-x-android/issues/640))
- Use `for` instead of `forEach` in `DefaultDiffCacheInvalidator` to improve performance. ([#1035](https://github.com/element-hq/element-x-android/issues/1035))
- Filter push notifications using push rules. ([#640](https://github.com/element-hq/element-x-android/issues/640))
- Use `for` instead of `forEach` in `DefaultDiffCacheInvalidator` to improve performance. ([#1035](https://github.com/element-hq/element-x-android/issues/1035))
In development 🚧
----------------
- [Poll] Render start event in the timeline ([#1031](https://github.com/element-hq/element-x-android/issues/1031))
- [Poll] Render start event in the timeline ([#1031](https://github.com/element-hq/element-x-android/issues/1031))
Other changes
-------------
- Add Button component based on Compound designs ([#1021](https://github.com/element-hq/element-x-android/issues/1021))
- Compound: implement dialogs. ([#1043](https://github.com/element-hq/element-x-android/issues/1043))
- Compound: customise `IconButton` component. ([#1049](https://github.com/element-hq/element-x-android/issues/1049))
- Compound: implement `DropdownMenu` customisations. ([#1050](https://github.com/element-hq/element-x-android/issues/1050))
- Compound: implement Snackbar component. ([#1054](https://github.com/element-hq/element-x-android/issues/1054))
- Add Button component based on Compound designs ([#1021](https://github.com/element-hq/element-x-android/issues/1021))
- Compound: implement dialogs. ([#1043](https://github.com/element-hq/element-x-android/issues/1043))
- Compound: customise `IconButton` component. ([#1049](https://github.com/element-hq/element-x-android/issues/1049))
- Compound: implement `DropdownMenu` customisations. ([#1050](https://github.com/element-hq/element-x-android/issues/1050))
- Compound: implement Snackbar component. ([#1054](https://github.com/element-hq/element-x-android/issues/1054))
Changes in Element X v0.1.0 (2023-07-19)

View File

@@ -23,6 +23,7 @@ import extension.allServicesImpl
import extension.gitBranchName
import extension.gitRevision
import extension.koverDependencies
import extension.locales
import extension.setupKover
plugins {
@@ -74,6 +75,10 @@ android {
isUniversalApk = true
}
}
defaultConfig {
resourceConfigurations += locales
}
}
signingConfigs {

View File

@@ -29,6 +29,7 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
@@ -84,7 +85,13 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="*.element.io" />
<!-- Note: we can't use "*.element.io" here because it'll intercept the "mas.element.io" domain too. -->
<!-- Matching asset file: https://app.element.io/.well-known/assetlinks.json -->
<data android:host="app.element.io" />
<!-- Matching asset file: https://develop.element.io/.well-known/assetlinks.json -->
<data android:host="develop.element.io" />
<!-- Matching asset file: https://staging.element.io/.well-known/assetlinks.json -->
<data android:host="staging.element.io" />
</intent-filter>
<!--
matrix.to links

View File

@@ -36,6 +36,6 @@ class ElementXApplication : Application(), DaggerComponentOwner {
initializeComponent(TracingInitializer::class.java)
initializeComponent(CacheCleanerInitializer::class.java)
}
logApplicationInfo()
logApplicationInfo(this)
}
}

View File

@@ -32,6 +32,9 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.bumble.appyx.core.integration.NodeHost
import com.bumble.appyx.core.integrationpoint.NodeActivity
import com.bumble.appyx.core.plugin.NodeReadyObserver
@@ -39,14 +42,16 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.isDark
import io.element.android.compound.theme.mapToTheme
import io.element.android.features.call.ui.ElementCallActivity
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.features.lockscreen.api.LockScreenLockState
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.api.handleSecureFlag
import io.element.android.features.lockscreen.api.isLocked
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
import io.element.android.x.di.AppBindings
import io.element.android.x.intent.SafeUriHandler
import kotlinx.coroutines.launch
import timber.log.Timber
private val loggerTag = LoggerTag("MainActivity")
@@ -59,35 +64,14 @@ class MainActivity : NodeActivity() {
Timber.tag(loggerTag.value).w("onCreate, with savedInstanceState: ${savedInstanceState != null}")
installSplashScreen()
super.onCreate(savedInstanceState)
if (ElementCallActivity.maybeStart(this, intent)) {
Timber.tag(loggerTag.value).w("Starting Element Call Activity")
if (savedInstanceState == null) {
finish()
return
}
}
appBindings = bindings()
appBindings.lockScreenService().handleSecureFlag(this)
setupLockManagement(appBindings.lockScreenService(), appBindings.lockScreenEntryPoint())
enableEdgeToEdge()
setContent {
MainContent(appBindings)
}
}
@Deprecated("")
override fun onBackPressed() {
// If the app is locked, we need to intercept onBackPressed before it goes to OnBackPressedDispatcher.
// Indeed, otherwise we would need to trick Appyx backstack management everywhere.
// Without this trick, we would get pop operations on the hidden backstack.
if (appBindings.lockScreenService().isLocked) {
// Do not kill the app in this case, just go to background.
moveTaskToBack(false)
} else {
@Suppress("DEPRECATION")
super.onBackPressed()
}
}
@Composable
private fun MainContent(appBindings: AppBindings) {
val theme by remember {
@@ -104,8 +88,8 @@ class MainActivity : NodeActivity() {
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
) {
if (migrationState.migrationAction.isSuccess()) {
MainNodeHost()
@@ -139,6 +123,22 @@ class MainActivity : NodeActivity() {
}
}
private fun setupLockManagement(
lockScreenService: LockScreenService,
lockScreenEntryPoint: LockScreenEntryPoint
) {
lockScreenService.handleSecureFlag(this)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
lockScreenService.lockState.collect { state ->
if (state == LockScreenLockState.Locked) {
startActivity(lockScreenEntryPoint.pinUnlockIntent(this@MainActivity))
}
}
}
}
}
/**
* Called when:
* - the launcher icon is clicked (if the app is already running);
@@ -149,12 +149,6 @@ class MainActivity : NodeActivity() {
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Timber.tag(loggerTag.value).w("onNewIntent")
if (ElementCallActivity.maybeStart(this, intent)) {
Timber.tag(loggerTag.value).w("Starting Element Call Activity")
return
}
// If the mainNode is not init yet, keep the intent for later.
// It can happen when the activity is killed by the system. The methods are called in this order :
// onCreate(savedInstanceState=true) -> onNewIntent -> onResume -> onMainNodeInit

View File

@@ -18,6 +18,7 @@ package io.element.android.x.di
import com.squareup.anvil.annotations.ContributesTo
import io.element.android.features.api.MigrationEntryPoint
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.preferences.api.store.AppPreferencesStore
import io.element.android.features.rageshake.api.reporter.BugReporter
@@ -38,4 +39,6 @@ interface AppBindings {
fun preferencesStore(): AppPreferencesStore
fun migrationEntryPoint(): MigrationEntryPoint
fun lockScreenEntryPoint(): LockScreenEntryPoint
}

View File

@@ -26,6 +26,7 @@ import dagger.Provides
import io.element.android.appconfig.ApplicationConfig
import io.element.android.features.messages.impl.timeline.components.customreaction.DefaultEmojibaseProvider
import io.element.android.features.messages.impl.timeline.components.customreaction.EmojibaseProvider
import io.element.android.libraries.androidutils.system.getVersionCodeFromManifest
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
@@ -87,7 +88,7 @@ object AppModule {
// TODO EAx Config.LOW_PRIVACY_LOG_ENABLE,
lowPrivacyLoggingEnabled = false,
versionName = BuildConfig.VERSION_NAME,
versionCode = BuildConfig.VERSION_CODE,
versionCode = context.getVersionCodeFromManifest(),
gitRevision = BuildConfig.GIT_REVISION,
gitBranchName = BuildConfig.GIT_BRANCH_NAME,
flavorDescription = BuildConfig.FLAVOR_DESCRIPTION,

View File

@@ -16,17 +16,19 @@
package io.element.android.x.info
import android.content.Context
import io.element.android.libraries.androidutils.system.getVersionCodeFromManifest
import io.element.android.x.BuildConfig
import timber.log.Timber
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
fun logApplicationInfo() {
fun logApplicationInfo(context: Context) {
val appVersion = buildString {
append(BuildConfig.VERSION_NAME)
append(" (")
append(BuildConfig.VERSION_CODE)
append(context.getVersionCodeFromManifest())
append(") - ")
append(BuildConfig.BUILD_TYPE)
append(" / ")

View File

@@ -0,0 +1,17 @@
#
# Copyright (c) 2024 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
unqualifiedResLocale=en

View File

@@ -0,0 +1,22 @@
<!-- File generated by importSupportedLocalesFromLocalazy.py, do not edit -->
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="be"/>
<locale android:name="bg"/>
<locale android:name="cs"/>
<locale android:name="de"/>
<locale android:name="en"/>
<locale android:name="es"/>
<locale android:name="fr"/>
<locale android:name="hu"/>
<locale android:name="in"/>
<locale android:name="it"/>
<locale android:name="ka"/>
<locale android:name="pt_BR"/>
<locale android:name="ro"/>
<locale android:name="ru"/>
<locale android:name="sk"/>
<locale android:name="sv"/>
<locale android:name="uk"/>
<locale android:name="zh-CN"/>
<locale android:name="zh-TW"/>
</locale-config>

View File

@@ -40,4 +40,9 @@ object ApplicationConfig {
* For Element, the value is "Element". We use the same name for desktop and mobile for now.
*/
const val DESKTOP_APPLICATION_NAME: String = "Element"
/**
* The maximum size of the upload request. Default value is just below CloudFlare's max request size.
*/
const val MAX_LOG_UPLOAD_SIZE = 50 * 1024 * 1024L
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 New Vector Ltd
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +14,11 @@
* limitations under the License.
*/
package io.element.android.libraries.push.impl.notifications.fake
package io.element.android.appconfig
import io.element.android.libraries.push.impl.notifications.SummaryGroupMessageCreator
import io.mockk.mockk
class MockkSummaryGroupMessageCreator {
val instance = mockk<SummaryGroupMessageCreator>()
object MessageComposerConfig {
/**
* Enable the rich text editing in the composer.
*/
const val ENABLE_RICH_TEXT_EDITING = true
}

View File

@@ -20,6 +20,9 @@ object NotificationConfig {
// TODO EAx Implement and set to true at some point
const val SUPPORT_MARK_AS_READ_ACTION = false
// TODO EAx Implement and set to true at some point
const val SUPPORT_JOIN_DECLINE_INVITE = false
// TODO EAx Implement and set to true at some point
const val SUPPORT_QUICK_REPLY_ACTION = false
}

View File

@@ -72,6 +72,7 @@ dependencies {
testImplementation(projects.features.rageshake.test)
testImplementation(projects.features.rageshake.impl)
testImplementation(projects.services.appnavstate.test)
testImplementation(projects.services.analytics.test)
testImplementation(libs.test.appyx.junit)
testImplementation(libs.test.arch.core)

View File

@@ -37,6 +37,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
import com.bumble.appyx.navmodel.backstack.operation.replace
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.loggedin.LoggedInNode
import io.element.android.appnav.room.RoomFlowNode
@@ -46,9 +47,6 @@ import io.element.android.features.createroom.api.CreateRoomEntryPoint
import io.element.android.features.ftue.api.FtueEntryPoint
import io.element.android.features.ftue.api.state.FtueService
import io.element.android.features.ftue.api.state.FtueState
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.features.lockscreen.api.LockScreenLockState
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.preferences.api.PreferencesEntryPoint
@@ -99,8 +97,6 @@ class LoggedInFlowNode @AssistedInject constructor(
private val coroutineScope: CoroutineScope,
private val networkMonitor: NetworkMonitor,
private val ftueService: FtueService,
private val lockScreenEntryPoint: LockScreenEntryPoint,
private val lockScreenStateService: LockScreenService,
private val roomDirectoryEntryPoint: RoomDirectoryEntryPoint,
private val matrixClient: MatrixClient,
snackbarDispatcher: SnackbarDispatcher,
@@ -110,7 +106,7 @@ class LoggedInFlowNode @AssistedInject constructor(
savedStateMap = buildContext.savedStateMap,
),
permanentNavModel = PermanentNavModel(
navTargets = setOf(NavTarget.LoggedInPermanent, NavTarget.LockPermanent),
navTargets = setOf(NavTarget.LoggedInPermanent),
savedStateMap = buildContext.savedStateMap,
),
buildContext = buildContext,
@@ -188,15 +184,14 @@ class LoggedInFlowNode @AssistedInject constructor(
@Parcelize
data object LoggedInPermanent : NavTarget
@Parcelize
data object LockPermanent : NavTarget
@Parcelize
data object RoomList : NavTarget
@Parcelize
data class Room(
val roomIdOrAlias: RoomIdOrAlias,
val serverNames: List<String> = emptyList(),
val trigger: JoinedRoom.Trigger? = null,
val roomDescription: RoomDescription? = null,
val initialElement: RoomNavigationTarget = RoomNavigationTarget.Messages()
) : NavTarget
@@ -232,11 +227,6 @@ class LoggedInFlowNode @AssistedInject constructor(
NavTarget.LoggedInPermanent -> {
createNode<LoggedInNode>(buildContext)
}
NavTarget.LockPermanent -> {
lockScreenEntryPoint.nodeBuilder(this, buildContext)
.target(LockScreenEntryPoint.Target.Unlock)
.build()
}
NavTarget.RoomList -> {
val callback = object : RoomListEntryPoint.Callback {
override fun onRoomClicked(roomId: RoomId) {
@@ -292,8 +282,9 @@ class LoggedInFlowNode @AssistedInject constructor(
backstack.push(
NavTarget.Room(
roomIdOrAlias = data.roomIdOrAlias,
serverNames = data.viaParameters,
trigger = JoinedRoom.Trigger.Timeline,
initialElement = RoomNavigationTarget.Messages(data.eventId),
// TODO Use the viaParameters
)
)
}
@@ -311,6 +302,8 @@ class LoggedInFlowNode @AssistedInject constructor(
val inputs = RoomFlowNode.Inputs(
roomIdOrAlias = navTarget.roomIdOrAlias,
roomDescription = Optional.ofNullable(navTarget.roomDescription),
serverNames = navTarget.serverNames,
trigger = Optional.ofNullable(navTarget.trigger),
initialElement = navTarget.initialElement
)
createNode<RoomFlowNode>(buildContext, plugins = listOf(inputs, callback))
@@ -370,12 +363,14 @@ class LoggedInFlowNode @AssistedInject constructor(
NavTarget.RoomDirectorySearch -> {
roomDirectoryEntryPoint.nodeBuilder(this, buildContext)
.callback(object : RoomDirectoryEntryPoint.Callback {
override fun onRoomJoined(roomId: RoomId) {
backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias()))
}
override fun onResultClicked(roomDescription: RoomDescription) {
backstack.push(NavTarget.Room(roomDescription.roomId.toRoomIdOrAlias(), roomDescription))
backstack.push(
NavTarget.Room(
roomIdOrAlias = roomDescription.roomId.toRoomIdOrAlias(),
roomDescription = roomDescription,
trigger = JoinedRoom.Trigger.RoomDirectory,
)
)
}
})
.build()
@@ -383,7 +378,12 @@ class LoggedInFlowNode @AssistedInject constructor(
}
}
suspend fun attachRoom(roomIdOrAlias: RoomIdOrAlias, eventId: EventId? = null) {
suspend fun attachRoom(
roomIdOrAlias: RoomIdOrAlias,
serverNames: List<String> = emptyList(),
trigger: JoinedRoom.Trigger? = null,
eventId: EventId? = null,
) {
waitForNavTargetAttached { navTarget ->
navTarget is NavTarget.RoomList
}
@@ -391,6 +391,8 @@ class LoggedInFlowNode @AssistedInject constructor(
backstack.push(
NavTarget.Room(
roomIdOrAlias = roomIdOrAlias,
serverNames = serverNames,
trigger = trigger,
initialElement = RoomNavigationTarget.Messages(
focusedEventId = eventId
)
@@ -415,15 +417,11 @@ class LoggedInFlowNode @AssistedInject constructor(
@Composable
override fun View(modifier: Modifier) {
Box(modifier = modifier) {
val lockScreenState by lockScreenStateService.lockState.collectAsState()
val ftueState by ftueService.state.collectAsState()
BackstackView()
if (ftueState is FtueState.Complete) {
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent)
}
if (lockScreenState == LockScreenLockState.Locked) {
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LockPermanent)
}
}
}

View File

@@ -34,6 +34,7 @@ import com.bumble.appyx.navmodel.backstack.operation.pop
import com.bumble.appyx.navmodel.backstack.operation.push
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.di.MatrixClientsHolder
import io.element.android.appnav.intent.IntentResolver
@@ -295,6 +296,8 @@ class RootFlowNode @AssistedInject constructor(
is PermalinkData.RoomLink -> {
attachRoom(
roomIdOrAlias = permalinkData.roomIdOrAlias,
trigger = JoinedRoom.Trigger.MobilePermalink,
serverNames = permalinkData.viaParameters,
eventId = permalinkData.eventId,
)
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.appnav.loggedin
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
fun SessionVerifiedStatus.toAnalyticsUserPropertyValue(): UserProperties.VerificationState? {
return when (this) {
// we don't need to report transient states
SessionVerifiedStatus.Unknown -> null
SessionVerifiedStatus.NotVerified -> UserProperties.VerificationState.NotVerified
SessionVerifiedStatus.Verified -> UserProperties.VerificationState.Verified
}
}
fun RecoveryState.toAnalyticsUserPropertyValue(): UserProperties.RecoveryState? {
return when (this) {
RecoveryState.ENABLED -> UserProperties.RecoveryState.Enabled
RecoveryState.DISABLED -> UserProperties.RecoveryState.Disabled
RecoveryState.INCOMPLETE -> UserProperties.RecoveryState.Incomplete
// we don't need to report transient states
else -> null
}
}
fun SessionVerifiedStatus.toAnalyticsStateChangeValue(): CryptoSessionStateChange.VerificationState? {
return when (this) {
// we don't need to report transient states
SessionVerifiedStatus.Unknown -> null
SessionVerifiedStatus.NotVerified -> CryptoSessionStateChange.VerificationState.NotVerified
SessionVerifiedStatus.Verified -> CryptoSessionStateChange.VerificationState.Verified
}
}
fun RecoveryState.toAnalyticsStateChangeValue(): CryptoSessionStateChange.RecoveryState? {
return when (this) {
RecoveryState.ENABLED -> CryptoSessionStateChange.RecoveryState.Enabled
RecoveryState.DISABLED -> CryptoSessionStateChange.RecoveryState.Disabled
RecoveryState.INCOMPLETE -> CryptoSessionStateChange.RecoveryState.Incomplete
// we don't need to report transient states
else -> null
}
}

View File

@@ -22,15 +22,21 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.features.networkmonitor.api.NetworkMonitor
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.push.api.PushService
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.flow.map
import timber.log.Timber
import javax.inject.Inject
class LoggedInPresenter @Inject constructor(
@@ -38,6 +44,8 @@ class LoggedInPresenter @Inject constructor(
private val networkMonitor: NetworkMonitor,
private val pushService: PushService,
private val sessionVerificationService: SessionVerificationService,
private val analyticsService: AnalyticsService,
private val encryptionService: EncryptionService,
) : Presenter<LoggedInState> {
@Composable
override fun present(): LoggedInState {
@@ -48,10 +56,26 @@ class LoggedInPresenter @Inject constructor(
LaunchedEffect(isVerified) {
if (isVerified) {
// Ensure pusher is registered
// TODO Manually select push provider for now
val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect
val distributor = pushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect
pushService.registerWith(matrixClient, pushProvider, distributor)
val currentPushProvider = pushService.getCurrentPushProvider()
val result = if (currentPushProvider == null) {
// Register with the first available push provider
val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect
val distributor = pushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect
pushService.registerWith(matrixClient, pushProvider, distributor)
} else {
val currentPushDistributor = currentPushProvider.getCurrentDistributor(matrixClient)
if (currentPushDistributor == null) {
// Register with the first available distributor
val distributor = currentPushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect
pushService.registerWith(matrixClient, currentPushProvider, distributor)
} else {
// Re-register with the current distributor
pushService.registerWith(matrixClient, currentPushProvider, currentPushDistributor)
}
}
result.onFailure {
Timber.e(it, "Failed to register pusher")
}
}
}
@@ -62,8 +86,36 @@ class LoggedInPresenter @Inject constructor(
networkStatus == NetworkStatus.Online && syncIndicator == RoomListService.SyncIndicator.Show
}
}
val verificationState by sessionVerificationService.sessionVerifiedStatus.collectAsState()
val recoveryState by encryptionService.recoveryStateStateFlow.collectAsState()
LaunchedEffect(verificationState, recoveryState) {
reportCryptoStatusToAnalytics(verificationState, recoveryState)
}
return LoggedInState(
showSyncSpinner = showSyncSpinner,
)
}
private fun reportCryptoStatusToAnalytics(verificationState: SessionVerifiedStatus, recoveryState: RecoveryState) {
// Update first the user property, to store the current status for that posthog user
val userVerificationState = verificationState.toAnalyticsUserPropertyValue()
val userRecoveryState = recoveryState.toAnalyticsUserPropertyValue()
if (userRecoveryState != null && userVerificationState != null) {
// we want to report when both value are known (if one is unknown we wait until we have them both)
analyticsService.updateUserProperties(
UserProperties(
verificationState = userVerificationState,
recoveryState = userRecoveryState
)
)
}
// Also report when there is a change in the state, to be able to track the changes
val changeVerificationState = verificationState.toAnalyticsStateChangeValue()
val changeRecoveryState = recoveryState.toAnalyticsStateChangeValue()
if (changeVerificationState != null && changeRecoveryState != null) {
analyticsService.capture(CryptoSessionStateChange(changeRecoveryState, changeVerificationState))
}
}
}

View File

@@ -32,6 +32,7 @@ import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.newRoot
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.anvilannotations.ContributesNode
import io.element.android.appnav.room.joined.JoinedRoomFlowNode
import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
@@ -54,6 +55,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
@@ -83,6 +85,8 @@ class RoomFlowNode @AssistedInject constructor(
data class Inputs(
val roomIdOrAlias: RoomIdOrAlias,
val roomDescription: Optional<RoomDescription>,
val serverNames: List<String>,
val trigger: Optional<JoinedRoom.Trigger>,
val initialElement: RoomNavigationTarget,
) : NodeInputs
@@ -96,7 +100,11 @@ class RoomFlowNode @AssistedInject constructor(
data class Resolving(val roomAlias: RoomAlias) : NavTarget
@Parcelize
data class JoinRoom(val roomId: RoomId) : NavTarget
data class JoinRoom(
val roomId: RoomId,
val serverNames: List<String>,
val trigger: im.vector.app.features.analytics.plan.JoinedRoom.Trigger,
) : NavTarget
@Parcelize
data class JoinedRoom(val roomId: RoomId) : NavTarget
@@ -114,13 +122,13 @@ class RoomFlowNode @AssistedInject constructor(
backstack.newRoot(NavTarget.Resolving(i.roomAlias))
}
is RoomIdOrAlias.Id -> {
subscribeToRoomInfoFlow(i.roomId)
subscribeToRoomInfoFlow(i.roomId, inputs.serverNames)
}
}
}
}
private fun subscribeToRoomInfoFlow(roomId: RoomId) {
private fun subscribeToRoomInfoFlow(roomId: RoomId, serverNames: List<String>) {
val roomInfoFlow = client.getRoomInfoFlow(
roomId = roomId
).map { it.getOrNull() }
@@ -136,7 +144,13 @@ class RoomFlowNode @AssistedInject constructor(
// we can have a space here in case the space has just been joined.
// So navigate to the JoinRoom target for now, which will
// handle the space not supported screen
backstack.newRoot(NavTarget.JoinRoom(roomId))
backstack.newRoot(
NavTarget.JoinRoom(
roomId = roomId,
serverNames = serverNames,
trigger = inputs.trigger.getOrNull() ?: JoinedRoom.Trigger.Invite,
)
)
} else {
backstack.newRoot(NavTarget.JoinedRoom(roomId))
}
@@ -147,7 +161,13 @@ class RoomFlowNode @AssistedInject constructor(
}
else -> {
// Was invited or the room is not known, display the join room screen
backstack.newRoot(NavTarget.JoinRoom(roomId))
backstack.newRoot(
NavTarget.JoinRoom(
roomId = roomId,
serverNames = serverNames,
trigger = inputs.trigger.getOrNull() ?: JoinedRoom.Trigger.Invite,
)
)
}
}
}.launchIn(lifecycleScope)
@@ -158,8 +178,11 @@ class RoomFlowNode @AssistedInject constructor(
is NavTarget.Loading -> loadingNode(buildContext)
is NavTarget.Resolving -> {
val callback = object : RoomAliasResolverEntryPoint.Callback {
override fun onAliasResolved(roomId: RoomId) {
subscribeToRoomInfoFlow(roomId)
override fun onAliasResolved(data: ResolvedRoomAlias) {
subscribeToRoomInfoFlow(
roomId = data.roomId,
serverNames = data.servers,
)
}
}
val params = RoomAliasResolverEntryPoint.Params(navTarget.roomAlias)
@@ -173,6 +196,8 @@ class RoomFlowNode @AssistedInject constructor(
roomId = navTarget.roomId,
roomIdOrAlias = inputs.roomIdOrAlias,
roomDescription = inputs.roomDescription,
serverNames = navTarget.serverNames,
trigger = navTarget.trigger,
)
joinRoomEntryPoint.createNode(this, buildContext, inputs)
}

View File

@@ -20,21 +20,21 @@ import com.bumble.appyx.core.state.MutableSavedStateMapImpl
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.auth.FakeAuthenticationService
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
import kotlinx.coroutines.test.runTest
import org.junit.Test
class MatrixClientsHolderTest {
@Test
fun `test getOrNull`() {
val fakeAuthenticationService = FakeAuthenticationService()
val fakeAuthenticationService = FakeMatrixAuthenticationService()
val matrixClientsHolder = MatrixClientsHolder(fakeAuthenticationService)
assertThat(matrixClientsHolder.getOrNull(A_SESSION_ID)).isNull()
}
@Test
fun `test getOrRestore`() = runTest {
val fakeAuthenticationService = FakeAuthenticationService()
val fakeAuthenticationService = FakeMatrixAuthenticationService()
val matrixClientsHolder = MatrixClientsHolder(fakeAuthenticationService)
val fakeMatrixClient = FakeMatrixClient()
fakeAuthenticationService.givenMatrixClient(fakeMatrixClient)
@@ -47,7 +47,7 @@ class MatrixClientsHolderTest {
@Test
fun `test remove`() = runTest {
val fakeAuthenticationService = FakeAuthenticationService()
val fakeAuthenticationService = FakeMatrixAuthenticationService()
val matrixClientsHolder = MatrixClientsHolder(fakeAuthenticationService)
val fakeMatrixClient = FakeMatrixClient()
fakeAuthenticationService.givenMatrixClient(fakeMatrixClient)
@@ -60,7 +60,7 @@ class MatrixClientsHolderTest {
@Test
fun `test remove all`() = runTest {
val fakeAuthenticationService = FakeAuthenticationService()
val fakeAuthenticationService = FakeMatrixAuthenticationService()
val matrixClientsHolder = MatrixClientsHolder(fakeAuthenticationService)
val fakeMatrixClient = FakeMatrixClient()
fakeAuthenticationService.givenMatrixClient(fakeMatrixClient)
@@ -73,7 +73,7 @@ class MatrixClientsHolderTest {
@Test
fun `test save and restore`() = runTest {
val fakeAuthenticationService = FakeAuthenticationService()
val fakeAuthenticationService = FakeMatrixAuthenticationService()
val matrixClientsHolder = MatrixClientsHolder(fakeAuthenticationService)
val fakeMatrixClient = FakeMatrixClient()
fakeAuthenticationService.givenMatrixClient(fakeMatrixClient)

View File

@@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_THREAD_ID
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.tests.testutils.lambda.lambdaError
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
@@ -229,7 +230,7 @@ class IntentResolverTest {
}
private fun createIntentResolver(
permalinkParserResult: () -> PermalinkData = { throw NotImplementedError() }
permalinkParserResult: () -> PermalinkData = { lambdaError() }
): IntentResolver {
return IntentResolver(
deeplinkParser = DeeplinkParser(),

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.appnav.loggedin
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.tests.testutils.WarmUpRule
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
class AnalyticsVerificationStateMappingTests {
@get:Rule
val warmUpRule = WarmUpRule()
@Test
fun `Test verification Mappings`() = runTest {
assertThat(SessionVerifiedStatus.Verified.toAnalyticsUserPropertyValue())
.isEqualTo(UserProperties.VerificationState.Verified)
assertThat(SessionVerifiedStatus.NotVerified.toAnalyticsUserPropertyValue())
.isEqualTo(UserProperties.VerificationState.NotVerified)
assertThat(SessionVerifiedStatus.Verified.toAnalyticsStateChangeValue())
.isEqualTo(CryptoSessionStateChange.VerificationState.Verified)
assertThat(SessionVerifiedStatus.NotVerified.toAnalyticsStateChangeValue())
.isEqualTo(CryptoSessionStateChange.VerificationState.NotVerified)
}
@Test
fun `Test recovery state Mappings`() = runTest {
assertThat(RecoveryState.UNKNOWN.toAnalyticsUserPropertyValue())
.isNull()
assertThat(RecoveryState.WAITING_FOR_SYNC.toAnalyticsUserPropertyValue())
.isNull()
assertThat(RecoveryState.INCOMPLETE.toAnalyticsUserPropertyValue())
.isEqualTo(UserProperties.RecoveryState.Incomplete)
assertThat(RecoveryState.ENABLED.toAnalyticsUserPropertyValue())
.isEqualTo(UserProperties.RecoveryState.Enabled)
assertThat(RecoveryState.DISABLED.toAnalyticsUserPropertyValue())
.isEqualTo(UserProperties.RecoveryState.Disabled)
assertThat(RecoveryState.UNKNOWN.toAnalyticsStateChangeValue())
.isNull()
assertThat(RecoveryState.WAITING_FOR_SYNC.toAnalyticsStateChangeValue())
.isNull()
assertThat(RecoveryState.INCOMPLETE.toAnalyticsStateChangeValue())
.isEqualTo(CryptoSessionStateChange.RecoveryState.Incomplete)
assertThat(RecoveryState.ENABLED.toAnalyticsStateChangeValue())
.isEqualTo(CryptoSessionStateChange.RecoveryState.Enabled)
assertThat(RecoveryState.DISABLED.toAnalyticsStateChangeValue())
.isEqualTo(CryptoSessionStateChange.RecoveryState.Disabled)
}
}

View File

@@ -20,13 +20,19 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
import io.element.android.libraries.push.test.FakePushService
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.consumeItemsUntilPredicate
import kotlinx.coroutines.test.runTest
@@ -64,15 +70,56 @@ class LoggedInPresenterTest {
}
}
@Test
fun `present - report crypto status analytics`() = runTest {
val analyticsService = FakeAnalyticsService()
val roomListService = FakeRoomListService()
val verificationService = FakeSessionVerificationService()
val encryptionService = FakeEncryptionService()
val presenter = LoggedInPresenter(
matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService),
networkMonitor = FakeNetworkMonitor(NetworkStatus.Online),
pushService = FakePushService(),
sessionVerificationService = verificationService,
analyticsService = analyticsService,
encryptionService = encryptionService
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
encryptionService.emitRecoveryState(RecoveryState.UNKNOWN)
encryptionService.emitRecoveryState(RecoveryState.INCOMPLETE)
verificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
skipItems(4)
assertThat(analyticsService.capturedEvents.size).isEqualTo(1)
assertThat(analyticsService.capturedEvents[0]).isInstanceOf(CryptoSessionStateChange::class.java)
assertThat(analyticsService.capturedUserProperties.size).isEqualTo(1)
assertThat(analyticsService.capturedUserProperties[0].recoveryState).isEqualTo(UserProperties.RecoveryState.Incomplete)
assertThat(analyticsService.capturedUserProperties[0].verificationState).isEqualTo(UserProperties.VerificationState.Verified)
// ensure a sync status change does not trigger a new capture
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show)
skipItems(1)
assertThat(analyticsService.capturedEvents.size).isEqualTo(1)
}
}
private fun createLoggedInPresenter(
roomListService: RoomListService = FakeRoomListService(),
networkStatus: NetworkStatus = NetworkStatus.Offline
networkStatus: NetworkStatus = NetworkStatus.Offline,
analyticsService: FakeAnalyticsService = FakeAnalyticsService(),
encryptionService: FakeEncryptionService = FakeEncryptionService(),
): LoggedInPresenter {
return LoggedInPresenter(
matrixClient = FakeMatrixClient(roomListService = roomListService),
networkMonitor = FakeNetworkMonitor(networkStatus),
pushService = FakePushService(),
sessionVerificationService = FakeSessionVerificationService(),
analyticsService = analyticsService,
encryptionService = encryptionService
)
}
}

View File

@@ -60,7 +60,7 @@ allprojects {
config.from(files("$rootDir/tools/detekt/detekt.yml"))
}
dependencies {
detektPlugins("io.nlopez.compose.rules:detekt:0.3.12")
detektPlugins("io.nlopez.compose.rules:detekt:0.3.13")
}
// KtLint

View File

@@ -1 +0,0 @@
Fix session verification being asked again for already verified users.

View File

@@ -1 +0,0 @@
RoomMember screen: fallback to userProfile data, if the member is not a user of the room.

View File

@@ -1 +0,0 @@
Instead of displaying 'create new recovery key' on the session verification screen when there is no other session active, display it always under the 'enter recovery key' screen.

View File

@@ -1 +0,0 @@
Migrate application data.

View File

@@ -1 +0,0 @@
Add support for expected decryption errors due to membership (UX and analytics).

View File

@@ -1 +0,0 @@
Let the SDK manage the file log cleanup, and keep one week of log.

View File

@@ -1 +0,0 @@
Handle permalink navigation to Events.

View File

@@ -1 +0,0 @@
Adjust the typography used in the selected user component so a user's display name fits better.

View File

@@ -1 +0,0 @@
User display name overflows in timeline messages when it's way too long.

View File

@@ -1 +0,0 @@
Pretty-print event JSON in debug viewer

View File

@@ -1 +0,0 @@
Add support for external permalinks.

View File

@@ -1 +0,0 @@
Ensure the application open the room when a notification is clicked.

1
changelog.d/2809.bugfix Normal file
View File

@@ -0,0 +1 @@
Render selected/deselected room list filters on top

1
changelog.d/2893.misc Normal file
View File

@@ -0,0 +1 @@
BugReporting | Add public device keys to rageshakes

1
changelog.d/2896.bugfix Normal file
View File

@@ -0,0 +1 @@
Set auto captilization, multiline and autocompletion flags for the markdown EditText.

1
changelog.d/2898.bugfix Normal file
View File

@@ -0,0 +1 @@
Restoree Markdown text input contents when returning to the room screen.

1
changelog.d/2912.misc Normal file
View File

@@ -0,0 +1 @@
Move push provider setting to the "Notifications" screen and display it only when several push provider are available.

1
changelog.d/2917.bugfix Normal file
View File

@@ -0,0 +1 @@
Fixed sending rich content from android keyboards on the markdown text input

3
changelog.d/2924.misc Normal file
View File

@@ -0,0 +1,3 @@
Simplify notifications by removing the custom persistence layer.
Bump minSdk to 24 (Android 7).

1
changelog.d/2930.misc Normal file
View File

@@ -0,0 +1 @@
Add a feature flag ShowBlockedUsersDetails, disabled by default to render display name and avatar of blocked users in the blocked users list.

View File

@@ -0,0 +1,10 @@
Main changes in this version:
- Added support for opening matrix URLs inside the app and navigating to replied to messages.
- Added per-app language support for Android 13+.
- Session verification is no longer mandatory for already logged in users.
- Better log handling.
- Fixed CVE-2024-34353 / GHSA-9ggc-845v-gcgv.
- UX improvements.
Full changelog: https://github.com/element-hq/element-x-android/releases

View File

@@ -0,0 +1,2 @@
Main changes in this version: Add plain text editor based on Markdown input.
Full changelog: https://github.com/element-hq/element-x-android/releases

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Teile anonyme Nutzungsdaten, um uns bei der Identifizierung von Problemen zu helfen."</string>
<string name="screen_analytics_settings_read_terms">"Du kannst alle unsere Bedingungen lesen %1$s."</string>
<string name="screen_analytics_settings_read_terms">"Weitere Informationen findest du %1$s ."</string>
<string name="screen_analytics_settings_read_terms_content_link">"hier"</string>
<string name="screen_analytics_settings_share_data">"Analysedaten teilen"</string>
</resources>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"გააზიარეთ ანონიმური გამოყენების მონაცემები, რათა დაგვეხმაროთ პრობლემების იდენტიფიცირებაში."</string>
<string name="screen_analytics_settings_read_terms">"შეგიძლიათ, წაიკითხოთ ჩვენი ყველა პირობა %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"აქ"</string>
<string name="screen_analytics_settings_share_data">"გააზიარეთ ანალიტიკური მონაცემები"</string>
</resources>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Partilhe dados de utilização anónimos para nos ajudar a identificar problemas."</string>
<string name="screen_analytics_settings_read_terms">"Podes ler todos os nossos termos %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"aqui"</string>
<string name="screen_analytics_settings_share_data">"Partilhar dados de utilização"</string>
</resources>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
<string name="screen_analytics_settings_read_terms">"您可以阅读我们的所有条款 %1$s。"</string>
<string name="screen_analytics_settings_read_terms_content_link">"此处"</string>
<string name="screen_analytics_settings_share_data">"共享分析数据"</string>
</resources>

View File

@@ -2,7 +2,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Wir zeichnen keine persönlichen Daten auf und erstellen keine Profile."</string>
<string name="screen_analytics_prompt_help_us_improve">"Teile anonyme Nutzungsdaten, um uns bei der Identifizierung von Problemen zu helfen."</string>
<string name="screen_analytics_prompt_read_terms">"Du kannst alle unsere Bedingungen lesen %1$s."</string>
<string name="screen_analytics_prompt_read_terms">"Weitere Informationen findest du %1$s ."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"hier"</string>
<string name="screen_analytics_prompt_settings">"Du kannst diese Funktion jederzeit deaktivieren"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Wir geben deine Daten nicht an Dritte weiter"</string>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"ჩვენ არ ჩავწერთ და არ დავაფიქსირებთ პერსონალურ მონაცემებს"</string>
<string name="screen_analytics_prompt_help_us_improve">"გააზიარეთ ანონიმური გამოყენების მონაცემები, რათა დაგვეხმაროთ პრობლემების იდენტიფიცირებაში."</string>
<string name="screen_analytics_prompt_read_terms">"შეგიძლიათ, წაიკითხოთ ჩვენი ყველა პირობა %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"აქ"</string>
<string name="screen_analytics_prompt_settings">"ამის გამორთვა ნებისმიერ დროს შეგიძლიათ"</string>
<string name="screen_analytics_prompt_third_party_sharing">"თქვენს მონაცემებს მესამე პირს არ გადავცემთ"</string>
<string name="screen_analytics_prompt_title">"დაგვეხმარეთ, გავაუმჯობესოთ %1$s"</string>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Não recolheremos ou analisaremos quaisquer dados pessoais"</string>
<string name="screen_analytics_prompt_help_us_improve">"Partilhe dados de utilização anónimos para nos ajudar a identificar problemas."</string>
<string name="screen_analytics_prompt_read_terms">"Podes ler todos os nossos termos %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"aqui"</string>
<string name="screen_analytics_prompt_settings">"Podes desligar qualquer momento"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Não partilharemos os teus dados com terceiros"</string>
<string name="screen_analytics_prompt_title">"Ajude a melhorar a %1$s"</string>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"我们不会记录或分析任何个人数据"</string>
<string name="screen_analytics_prompt_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
<string name="screen_analytics_prompt_read_terms">"您可以阅读我们的所有条款 %1$s。"</string>
<string name="screen_analytics_prompt_read_terms_content_link">"此处"</string>
<string name="screen_analytics_prompt_settings">"你可以随时关闭此功能"</string>
<string name="screen_analytics_prompt_third_party_sharing">"我们不会与第三方共享您的数据"</string>
<string name="screen_analytics_prompt_title">"帮助改进 %1$s"</string>
</resources>

View File

@@ -16,8 +16,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.microphone"
android:required="false" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
@@ -28,19 +32,27 @@
<application>
<activity
android:name=".ui.ElementCallActivity"
android:label="@string/element_call"
android:exported="true"
android:taskAffinity="io.element.android.features.call"
android:configChanges="screenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation|uiMode"
android:launchMode="singleTask">
android:exported="true"
android:label="@string/element_call"
android:launchMode="singleTask"
android:taskAffinity="io.element.android.features.call">
<!--
Note: intent-filter for https://call.element.io link is now managed by the MainActivity.
-->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<!-- Matching asset file: https://call.element.io/.well-known/assetlinks.json -->
<data android:host="call.element.io" />
</intent-filter>
<!-- Custom scheme to handle urls from other domains in the format: element://call?url=https%3A%2F%2Felement.io -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -50,6 +62,7 @@
<!-- Custom scheme to handle urls from other domains in the format: io.element.call:/?url=https%3A%2F%2Felement.io -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -57,7 +70,10 @@
</intent-filter>
</activity>
<service android:name=".CallForegroundService" android:enabled="true" android:foregroundServiceType="mediaPlayback" />
<service
android:name=".CallForegroundService"
android:enabled="true"
android:foregroundServiceType="mediaPlayback" />
</application>
</manifest>

View File

@@ -72,15 +72,10 @@ class CallForegroundService : Service() {
startForeground(1, notification)
}
@Suppress("DEPRECATION")
override fun onDestroy() {
super.onDestroy()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
stopForeground(STOP_FOREGROUND_REMOVE)
} else {
stopForeground(true)
}
stopForeground(STOP_FOREGROUND_REMOVE)
}
override fun onBind(intent: Intent?): IBinder? {

View File

@@ -17,7 +17,6 @@
package io.element.android.features.call.ui
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
@@ -36,7 +35,6 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.IntentCompat
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
import io.element.android.compound.theme.ElementTheme
@@ -49,7 +47,6 @@ import io.element.android.features.call.di.CallBindings
import io.element.android.features.call.utils.CallIntentDataParser
import io.element.android.features.preferences.api.store.AppPreferencesStore
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.bool.orFalse
import javax.inject.Inject
class ElementCallActivity : NodeComponentActivity(), CallScreenNavigator {
@@ -66,28 +63,6 @@ class ElementCallActivity : NodeComponentActivity(), CallScreenNavigator {
}
context.startActivity(intent)
}
/**
* Starts the [ElementCallActivity] if the intent contains a valid URL,
* and returns true if it's the case.
*/
fun maybeStart(
activity: Activity,
intent: Intent?,
): Boolean {
return intent?.data
?.takeIf { uri -> uri.scheme == "https" && uri.host == "call.element.io" }
?.let { uri ->
val callIntent = Intent(activity, ElementCallActivity::class.java).apply {
data = uri
}
// Disable animation since MainActivity has already been animated.
val options = ActivityOptionsCompat.makeCustomAnimation(activity, 0, 0)
activity.startActivity(callIntent, options.toBundle())
true
}
.orFalse()
}
}
@Inject lateinit var callIntentDataParser: CallIntentDataParser

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"მიმდინარე ზარი"</string>
<string name="call_foreground_service_message_android">"დააწკაპუნეთ ზარში დასაბრუნებლად"</string>
<string name="call_foreground_service_title_android">"☎️ ზარი მიმდინარეობს"</string>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"Chamada em curso"</string>
<string name="call_foreground_service_message_android">"Toca para voltar à chamada"</string>
<string name="call_foreground_service_title_android">"☎️ Chamada em curso"</string>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"通话进行中"</string>
<string name="call_foreground_service_message_android">"点按即可返回通话"</string>
<string name="call_foreground_service_title_android">"☎️ 通话中"</string>
</resources>

View File

@@ -30,7 +30,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
import io.element.android.libraries.matrix.test.widget.FakeWidgetDriver
import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver
import io.element.android.libraries.network.useragent.UserAgentProvider
import io.element.android.services.toolbox.api.systemclock.SystemClock
import io.element.android.tests.testutils.WarmUpRule
@@ -68,7 +68,7 @@ class CallScreenPresenterTest {
@Test
fun `present - with CallType RoomCall loads URL and runs WidgetDriver`() = runTest {
val widgetDriver = FakeWidgetDriver()
val widgetDriver = FakeMatrixWidgetDriver()
val widgetProvider = FakeCallWidgetProvider(widgetDriver)
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
@@ -91,7 +91,7 @@ class CallScreenPresenterTest {
@Test
fun `present - set message interceptor, send and receive messages`() = runTest {
val widgetDriver = FakeWidgetDriver()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
widgetDriver = widgetDriver,
@@ -119,7 +119,7 @@ class CallScreenPresenterTest {
@Test
fun `present - hang up event closes the screen and stops the widget driver`() = runTest(UnconfinedTestDispatcher()) {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeWidgetDriver()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
widgetDriver = widgetDriver,
@@ -149,7 +149,7 @@ class CallScreenPresenterTest {
@Test
fun `present - a received hang up message closes the screen and stops the widget driver`() = runTest(UnconfinedTestDispatcher()) {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeWidgetDriver()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
widgetDriver = widgetDriver,
@@ -178,7 +178,7 @@ class CallScreenPresenterTest {
@Test
fun `present - automatically starts the Matrix client sync when on RoomCall`() = runTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeWidgetDriver()
val widgetDriver = FakeMatrixWidgetDriver()
val matrixClient = FakeMatrixClient()
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
@@ -201,7 +201,7 @@ class CallScreenPresenterTest {
@Test
fun `present - automatically stops the Matrix client sync on dispose`() = runTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeWidgetDriver()
val widgetDriver = FakeMatrixWidgetDriver()
val matrixClient = FakeMatrixClient()
val presenter = createCallScreenPresenter(
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
@@ -229,7 +229,7 @@ class CallScreenPresenterTest {
private fun TestScope.createCallScreenPresenter(
callType: CallType,
navigator: CallScreenNavigator = FakeCallScreenNavigator(),
widgetDriver: FakeWidgetDriver = FakeWidgetDriver(),
widgetDriver: FakeMatrixWidgetDriver = FakeMatrixWidgetDriver(),
widgetProvider: FakeCallWidgetProvider = FakeCallWidgetProvider(widgetDriver),
dispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
matrixClientsProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),

View File

@@ -18,7 +18,6 @@ package io.element.android.features.call.utils
import com.google.common.truth.Truth.assertThat
import io.element.android.features.preferences.api.store.AppPreferencesStore
import io.element.android.libraries.featureflag.test.InMemoryAppPreferencesStore
import io.element.android.libraries.matrix.api.MatrixClientProvider
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
import io.element.android.libraries.matrix.test.A_ROOM_ID
@@ -27,7 +26,8 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.widget.FakeCallWidgetSettingsProvider
import io.element.android.libraries.matrix.test.widget.FakeWidgetDriver
import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -76,7 +76,7 @@ class DefaultCallWidgetProviderTest {
fun `getWidget - returns a widget driver when all steps are successful`() = runTest {
val room = FakeMatrixRoom().apply {
givenGenerateWidgetWebViewUrlResult(Result.success("url"))
givenGetWidgetDriverResult(Result.success(FakeWidgetDriver()))
givenGetWidgetDriverResult(Result.success(FakeMatrixWidgetDriver()))
}
val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, room)
@@ -89,7 +89,7 @@ class DefaultCallWidgetProviderTest {
fun `getWidget - will use a custom base url if it exists`() = runTest {
val room = FakeMatrixRoom().apply {
givenGenerateWidgetWebViewUrlResult(Result.success("url"))
givenGetWidgetDriverResult(Result.success(FakeWidgetDriver()))
givenGetWidgetDriverResult(Result.success(FakeMatrixWidgetDriver()))
}
val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, room)

View File

@@ -19,10 +19,10 @@ package io.element.android.features.call.utils
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.test.widget.FakeWidgetDriver
import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver
class FakeCallWidgetProvider(
private val widgetDriver: FakeWidgetDriver = FakeWidgetDriver(),
private val widgetDriver: FakeMatrixWidgetDriver = FakeMatrixWidgetDriver(),
private val url: String = "https://call.element.io",
) : CallWidgetProvider {
var getWidgetCalled = false

View File

@@ -29,12 +29,10 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
@@ -63,9 +61,7 @@ import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList
import io.element.android.libraries.matrix.ui.components.UnsavedAvatar
import io.element.android.libraries.permissions.api.PermissionsView
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ConfigureRoomView(
state: ConfigureRoomState,
@@ -73,17 +69,12 @@ fun ConfigureRoomView(
onRoomCreated: (RoomId) -> Unit,
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
val focusManager = LocalFocusManager.current
val itemActionsBottomSheetState = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Hidden,
)
val isAvatarActionsSheetVisible = remember { mutableStateOf(false) }
fun onAvatarClicked() {
focusManager.clearFocus()
coroutineScope.launch {
itemActionsBottomSheetState.show()
}
isAvatarActionsSheetVisible.value = true
}
Scaffold(
@@ -143,7 +134,8 @@ fun ConfigureRoomView(
AvatarActionBottomSheet(
actions = state.avatarActions,
modalBottomSheetState = itemActionsBottomSheetState,
isVisible = isAvatarActionsSheetVisible.value,
onDismiss = { isAvatarActionsSheetVisible.value = false },
onActionSelected = { state.eventSink(ConfigureRoomEvents.HandleAvatarAction(it)) }
)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_create_room_action_create_room">"ახალი ოთახი"</string>
<string name="screen_create_room_add_people_title">"ხალხის მოწვევა"</string>
<string name="screen_create_room_error_creating_room">"ოთახის შექმნისას შეცდომა მოხდა"</string>
<string name="screen_create_room_private_option_description">"ამ ოთახში შეტყობინებები დაშიფრულია. შემდგომ დაშიფვრის გამორთვა შეუძლებელია."</string>
<string name="screen_create_room_private_option_title">"კერძო ოთახი (მხოლოდ მოწვევა)"</string>
<string name="screen_create_room_public_option_description">"შეტყობინებები არ არის დაშიფრული და ყველას შეუძლია მათი წაკითხვა. შეგიძლიათ ჩართოთ დაშიფვრა მოგვიანებით."</string>
<string name="screen_create_room_public_option_title">"საჯარო ოთახი (ნებისმიერი)"</string>
<string name="screen_create_room_room_name_label">"ოთახის სახელი"</string>
<string name="screen_create_room_title">"ოთახის შექმნა"</string>
<string name="screen_create_room_topic_label">"თემა (სურვილისამებრ)"</string>
<string name="screen_start_chat_error_starting_chat">"ჩატის დაწყების მცდელობისას შეცდომა მოხდა"</string>
</resources>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_create_room_action_create_room">"Nova sala"</string>
<string name="screen_create_room_add_people_title">"Convidar pessoas"</string>
<string name="screen_create_room_error_creating_room">"Ocorreu um erro ao criar a sala"</string>
<string name="screen_create_room_private_option_description">"As mensagens serão cifradas. Uma vez ativada, não é possível desativar a cifragem."</string>
<string name="screen_create_room_private_option_title">"Sala privada (entrada apenas por convite)"</string>
<string name="screen_create_room_public_option_description">"As mensagens não serão cifradas e qualquer um as poderá ler. É possível ativar a cifragem posteriormente."</string>
<string name="screen_create_room_public_option_title">"Sala pública (entrada livre)"</string>
<string name="screen_create_room_room_name_label">"Nome da sala"</string>
<string name="screen_create_room_title">"Criar uma sala"</string>
<string name="screen_create_room_topic_label">"Descrição (opcional)"</string>
<string name="screen_start_chat_error_starting_chat">"Ocorreu um erro ao tentar iniciar uma conversa"</string>
</resources>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_create_room_action_create_room">"新聊天室"</string>
<string name="screen_create_room_add_people_title">"邀请朋友"</string>
<string name="screen_create_room_error_creating_room">"创建房间时出错"</string>
<string name="screen_create_room_private_option_description">"此聊天室中的消息已加密。加密无法禁用。"</string>
<string name="screen_create_room_private_option_title">"私人房间(仅限受邀者)"</string>
<string name="screen_create_room_public_option_description">"消息未加密,任何人都可以查看。你可以稍后启用加密。"</string>
<string name="screen_create_room_public_option_title">"公共房间(任何人)"</string>
<string name="screen_create_room_room_name_label">"房间名称"</string>
<string name="screen_create_room_title">"创建房间"</string>
<string name="screen_create_room_topic_label">"主题(可选)"</string>
<string name="screen_start_chat_error_starting_chat">"在开始聊天时发生了错误"</string>
</resources>

View File

@@ -132,9 +132,8 @@ class FtueFlowNode @AssistedInject constructor(
lifecycleScope.launch { moveToNextStep() }
}
}
lockScreenEntryPoint.nodeBuilder(this, buildContext)
lockScreenEntryPoint.nodeBuilder(this, buildContext, LockScreenEntryPoint.Target.Setup)
.callback(callback)
.target(LockScreenEntryPoint.Target.Setup)
.build()
}
}

View File

@@ -11,11 +11,24 @@
<string name="screen_qr_code_login_connection_note_secure_state_title">"Злучэнне небяспечнае"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Вам будзе прапанавана ўвесці дзве лічбы, паказаныя на гэтай прыладзе."</string>
<string name="screen_qr_code_login_device_code_title">"Увядзіце наступны нумар на іншай прыладзе."</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"Уваход быў адменены на іншай прыладзе."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Запыт на ўваход скасаваны"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"Запыт на іншай прыладзе не быў прыняты."</string>
<string name="screen_qr_code_login_error_declined_title">"Уваход адхілены"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Тэрмін уваходу скончыўся. Калі ласка, паспрабуйце яшчэ раз."</string>
<string name="screen_qr_code_login_error_expired_title">"Уваход у сістэму не быў завершаны своечасова"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Ваша іншая прылада не падтрымлівае ўваход у %s з дапамогай QR-кода.
Паспрабуйце ўвайсці ў сістэму ўручную або адскануйце QR-код з дапамогай іншай прылады."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"QR-код не падтрымліваецца"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Ваш правайдар уліковага запісу не падтрымлівае %1$s."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s не падтрымліваецца"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Гатовы да сканавання"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Адкрыйце %1$s на настольнай прыладзе"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Націсніце на свой аватар"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Выберыце %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"“Звязаць новую прыладу”"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Выконвайце паказаныя інструкцыі"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Адсканіруйце QR-код з дапамогай гэтай прылады"</string>
<string name="screen_qr_code_login_initial_state_title">"Адкрыйце %1$s на іншай прыладзе, каб атрымаць QR-код"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Выкарыстоўвайце QR-код, паказаны на іншай прыладзе."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Паўтарыць спробу"</string>

View File

@@ -11,11 +11,24 @@
<string name="screen_qr_code_login_connection_note_secure_state_title">"Připojení není zabezpečené"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Budete požádáni o zadání dvou níže uvedených číslic."</string>
<string name="screen_qr_code_login_device_code_title">"Zadejte níže uvedené číslo na svém dalším zařízení"</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"Přihlášení bylo na druhém zařízení zrušeno."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Žádost o přihlášení zrušena"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"Požadavek na vašem druhém zařízení nebyl přijat."</string>
<string name="screen_qr_code_login_error_declined_title">"Přihlášení odmítnuto"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Platnost přihlášení vypršela. Zkuste to prosím znovu."</string>
<string name="screen_qr_code_login_error_expired_title">"Přihlášení nebylo dokončeno včas"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Vaše druhé zařízení nepodporuje přihlášení k %su pomocí QR kódu.
Zkuste se přihlásit ručně nebo naskenujte QR kód pomocí jiného zařízení."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"QR kód není podporován"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Váš poskytovatel účtu nepodporuje %1$s."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s není podporováno"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Připraveno ke skenování"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Otevřete %1$s na stolním počítači"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Klikněte na svůj avatar"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Vybrat %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"\"Připojit nové zařízení\""</string>
<string name="screen_qr_code_login_initial_state_item_4">"Postupujte podle uvedených pokynů"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Naskenujte QR kód pomocí tohoto zařízení"</string>
<string name="screen_qr_code_login_initial_state_title">"Otevřete %1$s na jiném zařízení pro získání QR kódu"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Použijte QR kód zobrazený na druhém zařízení."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Zkusit znovu"</string>

View File

@@ -11,11 +11,12 @@
<string name="screen_qr_code_login_connection_note_secure_state_title">"Die Verbindung ist nicht sicher"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Du wirst aufgefordert, die beiden unten abgebildeten Ziffern einzugeben."</string>
<string name="screen_qr_code_login_device_code_title">"Trage die unten angezeigte Zahl auf einem anderen Device ein"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Bereit zum Scannen"</string>
<string name="screen_qr_code_login_initial_state_item_1">"%1$s auf einem Desktop-Gerät öffnen"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Klick auf deinen Avatar"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Wähle %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"\"Neues Gerät verknüpfen\""</string>
<string name="screen_qr_code_login_initial_state_item_4">"Befolge die angezeigten Anweisungen"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Scanne den QR-Code mit diesem Gerät"</string>
<string name="screen_qr_code_login_initial_state_title">"Öffne %1$s auf einem anderen Gerät, um den QR-Code zu erhalten"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Verwende den QR-Code, der auf dem anderen Gerät angezeigt wird."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Erneut versuchen"</string>

View File

@@ -2,17 +2,44 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"Vous pourrez modifier vos paramètres ultérieurement."</string>
<string name="screen_notification_optin_title">"Autorisez les notifications et ne manquez aucun message"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Établissement de la connexion"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Établissement dune connexion sécurisée"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Aucune connexion sécurisée na pu être établie avec la nouvelle session. Vos sessions existantes sont toujours en sécurité et vous navez pas à vous en soucier."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Et maintenant ?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"Essayez de vous connecter à nouveau à laide du code QR au cas où il sagirait dun problème réseau"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"Si vous rencontrez le même problème, essayez un autre réseau wifi ou utilisez vos données mobiles au lieu du wifi"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"Si cela ne fonctionne pas, connectez-vous manuellement"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"La connexion nest pas sécurisée"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Il vous sera demandé de saisir les deux chiffres affichés sur cet appareil."</string>
<string name="screen_qr_code_login_device_code_title">"Saisissez le nombre ci-dessous sur votre autre appareil"</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"La connexion a été annulée sur lautre appareil."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Demande de connexion annulée"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"La demande sur lautre appareil na pas été acceptée."</string>
<string name="screen_qr_code_login_error_declined_title">"Connexion refusée"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Connexion expirée. Veuillez essayer à nouveau."</string>
<string name="screen_qr_code_login_error_expired_title">"La connexion a pris trop de temps."</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Votre autre appareil ne supporte pas la connexion à %s avec un code QR. Essayer de vous connecter manuellement, ou scanner le code QR avec un autre appareil."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"Code QR non supporté"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Votre fournisseur de compte ne supporte pas %1$s."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s nest pas supporté"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Prêt à scanner"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Ouvrez %1$s sur un ordinateur"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Cliquez sur votre image de profil"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Choisissez %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"“Associer une nouvelle session”"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Suivez les instructions affichées"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Scanner le code QR avec cet appareil"</string>
<string name="screen_qr_code_login_initial_state_title">"Ouvrez %1$s sur un autre appareil pour obtenir le QR code"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Scannez le QR code affiché sur lautre appareil."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Essayer à nouveau"</string>
<string name="screen_qr_code_login_invalid_scan_state_subtitle">"QR code erroné"</string>
<string name="screen_qr_code_login_no_camera_permission_button">"Accéder aux paramètres de lappareil photo"</string>
<string name="screen_qr_code_login_no_camera_permission_state_description">"Vous devez autoriser %1$s à utiliser la camera de votre appareil pour continuer."</string>
<string name="screen_qr_code_login_no_camera_permission_state_title">"Autoriser lusage de la caméra pour scanner le code QR"</string>
<string name="screen_qr_code_login_scanning_state_title">"Scannez le QR code"</string>
<string name="screen_qr_code_login_start_over_button">"Recommencer"</string>
<string name="screen_qr_code_login_unknown_error_description">"Une erreur inattendue sest produite. Veuillez réessayer."</string>
<string name="screen_qr_code_login_verify_code_loading">"En attente de votre autre session"</string>
<string name="screen_qr_code_login_verify_code_subtitle">"Votre fournisseur de compte peut vous demander le code suivant pour vérifier la connexion."</string>
<string name="screen_qr_code_login_verify_code_title">"Votre code de vérification"</string>
<string name="screen_welcome_bullet_1">"Les appels, les sondages, les recherches et plus encore seront ajoutés plus tard cette année."</string>
<string name="screen_welcome_bullet_2">"Lhistorique des messages pour les salons chiffrés ne sera pas disponible dans cette mise à jour."</string>
<string name="screen_welcome_bullet_3">"Nhésitez pas à nous faire part de vos commentaires via lécran des paramètres."</string>

View File

@@ -11,11 +11,12 @@
<string name="screen_qr_code_login_connection_note_secure_state_title">"A kapcsolat nem biztonságos"</string>
<string name="screen_qr_code_login_device_code_subtitle">"A rendszer kérni fogja, hogy adja meg az alábbi két számjegyet az eszközén."</string>
<string name="screen_qr_code_login_device_code_title">"Adja meg az alábbi számot a másik eszközén"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Készen áll a beolvasásra"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Nyissa meg az %1$set egy asztali eszközön"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Kattintson a profilképére"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Válassza ezt: %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"„Új eszköz összekapcsolása”"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Kövesse a látható utasításokat"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Olvassa be a QR-kódot ezzel az eszközzel"</string>
<string name="screen_qr_code_login_initial_state_title">"Nyissa meg az %1$set egy másik eszközön a QR-kód lekéréséhez."</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Használja a másik eszközön látható QR-kódot."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Próbálja újra"</string>

View File

@@ -2,7 +2,33 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"Potrai modificare le tue impostazioni in seguito."</string>
<string name="screen_notification_optin_title">"Consenti le notifiche e non perdere mai un messaggio"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Stabilendo la connessione"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Non è stato possibile stabilire una connessione sicura con il nuovo dispositivo. I tuoi dispositivi esistenti sono ancora al sicuro e non devi preoccuparti di loro."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"E adesso?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"Prova ad accedere di nuovo con un codice QR nel caso si sia verificato un problema di rete."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"Se riscontri lo stesso problema, prova con un altra rete wifi o usa i dati mobili al posto del wifi."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"Se il problema persiste, accedi manualmente"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"La connessione non è sicura"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Ti verrà chiesto di inserire le due cifre mostrate su questo dispositivo."</string>
<string name="screen_qr_code_login_device_code_title">"Inserisci il numero qui sotto sull\'altro dispositivo"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Apri %1$s su un dispositivo desktop"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Clicca sul tuo avatar"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Seleziona %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"\"Collega un nuovo dispositivo\""</string>
<string name="screen_qr_code_login_initial_state_item_4">"Segui le istruzioni mostrate"</string>
<string name="screen_qr_code_login_initial_state_title">"Apri %1$s su un altro dispositivo per ottenere il codice QR"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Usa il codice QR mostrato sull\'altro dispositivo."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Riprova"</string>
<string name="screen_qr_code_login_invalid_scan_state_subtitle">"Codice QR sbagliato"</string>
<string name="screen_qr_code_login_no_camera_permission_button">"Vai alle impostazioni della fotocamera"</string>
<string name="screen_qr_code_login_no_camera_permission_state_description">"Per continuare, è necessario fornire l\'autorizzazione a %1$s per utilizzare la fotocamera del dispositivo."</string>
<string name="screen_qr_code_login_no_camera_permission_state_title">"Consenti l\'accesso alla fotocamera per la scansione del codice QR"</string>
<string name="screen_qr_code_login_scanning_state_title">"Scansiona il codice QR"</string>
<string name="screen_qr_code_login_start_over_button">"Ricomincia"</string>
<string name="screen_qr_code_login_unknown_error_description">"Si è verificato un errore inatteso. Riprova."</string>
<string name="screen_qr_code_login_verify_code_loading">"In attesa dell\'altro dispositivo"</string>
<string name="screen_qr_code_login_verify_code_subtitle">"Il fornitore dell\'account potrebbe richiedere il seguente codice per verificare l\'accesso."</string>
<string name="screen_qr_code_login_verify_code_title">"Il tuo codice di verifica"</string>
<string name="screen_welcome_bullet_1">"Chiamate, sondaggi, ricerche e altro ancora saranno aggiunti nel corso dell\'anno."</string>
<string name="screen_welcome_bullet_2">"La cronologia dei messaggi per le stanze crittografate non è ancora disponibile."</string>
<string name="screen_welcome_bullet_3">"Ci piacerebbe sentire il tuo parere, facci sapere cosa ne pensi tramite la pagina delle impostazioni."</string>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"თქვენ შეგიძლიათ შეცვალოთ თქვენი პარამეტრები მოგვიანებით."</string>
<string name="screen_notification_optin_title">"ყველა შეტყობინებაზე შეტყობინებების მიღება"</string>
<string name="screen_welcome_bullet_1">"ზარები, გამოკითხვები, ძიება და სხვა დაემატება ამ წლის ბოლოს."</string>
<string name="screen_welcome_bullet_2">"დაშიფრული ოთახებისთვის შეტყობინებების ისტორია ჯერ არ არის ხელმისაწვდომი."</string>
<string name="screen_welcome_bullet_3">"ჩვენ სიამოვნებით მოვისმინოთ თქვენგან, შეგვატყობინეთ რას ფიქრობთ პარამეტრების გვერდზე."</string>
<string name="screen_welcome_button">"დავიწყოთ!"</string>
<string name="screen_welcome_subtitle">"აი, რა უნდა იცოდეთ:"</string>
<string name="screen_welcome_title">"კეთილი იყოს თქვენი მობრძანება %1$s-ში!"</string>
</resources>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"Podes alterar as tuas definições mais tarde."</string>
<string name="screen_notification_optin_title">"Permite as notificações e nunca percas uma mensagem"</string>
<string name="screen_qr_code_login_connecting_subtitle">"A estabelecer uma ligação segura"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Não foi possível estabelecer uma ligação segura com o novo dispositivo. Os teus outros dispositivos continuam seguros, não precisas de te preocupar com eles."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"E agora?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"Tenta iniciar sessão novamente com um código QR, caso se trate de um problema de rede"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"Se tiveres o mesmo problema, experimenta uma rede Wi-Fi diferente ou utiliza os teus dados móveis."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"Se isso não funcionar, inicia sessão manualmente"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"Ligação insegura"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Ser-te-á pedido que insiras os dois dígitos indicados neste dispositivo."</string>
<string name="screen_qr_code_login_device_code_title">"Insere o número abaixo no teu dispositivo"</string>
<string name="screen_qr_code_login_error_cancelled_title">"Pedido de início de sessão cancelado"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Pronto para ler"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Abre a %1$s num computador"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Carrega no teu avatar"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Seleciona %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"“Ligar novo dispositivo”"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Lê o código QR com este dispositivo"</string>
<string name="screen_qr_code_login_initial_state_title">"Abre a %1$s noutro dispositivo para obteres o código QR"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Lê o código QR apresentado no outro dispositivo."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Tentar novamente"</string>
<string name="screen_qr_code_login_invalid_scan_state_subtitle">"Código QR inválido"</string>
<string name="screen_qr_code_login_no_camera_permission_button">"Ir para as configurações da câmara"</string>
<string name="screen_qr_code_login_no_camera_permission_state_description">"Para continuar, tens que dar permissão à %1$s para aceder à câmara do teu dispositivo."</string>
<string name="screen_qr_code_login_no_camera_permission_state_title">"Permitir o acesso à câmara para ler o código QR"</string>
<string name="screen_qr_code_login_scanning_state_title">"Ler o código QR"</string>
<string name="screen_qr_code_login_start_over_button">"Começar de novo"</string>
<string name="screen_qr_code_login_unknown_error_description">"Ocorreu um erro inesperado. Tenta novamente."</string>
<string name="screen_qr_code_login_verify_code_loading">"À espera do teu outro dispositivo"</string>
<string name="screen_qr_code_login_verify_code_subtitle">"O teu fornecedor de conta pode pedir o seguinte código para verificar o início de sessão."</string>
<string name="screen_qr_code_login_verify_code_title">"O teu código de verificação"</string>
<string name="screen_welcome_bullet_1">"Chamadas, sondagens, pesquisa e mais funcionalidades vão ser adicionadas ao longo do ano."</string>
<string name="screen_welcome_bullet_2">"O histórico de mensagens em salas cifradas ainda não está disponível."</string>
<string name="screen_welcome_bullet_3">"Gostaríamos de ouvir a tua opinião, diz-nos o que pensas através da página de configurações."</string>
<string name="screen_welcome_button">"Vamos lá!"</string>
<string name="screen_welcome_subtitle">"Eis o que tens de saber:"</string>
<string name="screen_welcome_title">"Bem-vindo à %1$s!"</string>
</resources>

View File

@@ -2,7 +2,34 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"Puteți modifica setările mai târziu."</string>
<string name="screen_notification_optin_title">"Permiteți notificările și nu pierdeți niciodată un mesaj"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Se stabilește o conexiune securizată"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Nu a putut fi făcută o conexiune sigură la noul dispozitiv. Dispozitivele existente sunt încă în siguranță și nu trebuie să vă faceți griji cu privire la ele."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Și acum?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"Încercați să vă conectați din nou cu un cod QR în cazul în care a fost o problemă de rețea."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"Dacă întâmpinați aceeași problemă, încercați o altă rețea Wi-Fi sau utilizați datele mobile în loc de Wi-Fi."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"Dacă nu funcționează, conectați-vă manual"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"Conexiunea nu este sigură"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Vi se va cere să introduceți cele două cifre afișate pe acest dispozitiv."</string>
<string name="screen_qr_code_login_device_code_title">"Introduceți numărul de mai jos pe celălalt dispozitiv"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Gata de scanare"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Deschideți %1$s pe un dispozitiv desktop"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Faceți clic pe avatarul dumneavoastră"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Selectați %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"„Conectați un dispozitiv nou”"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Scanați codul QR cu acest dispozitiv"</string>
<string name="screen_qr_code_login_initial_state_title">"Deschideți %1$s pe un alt dispozitiv pentru a obține codul QR"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Utilizați codul QR afișat pe celălalt dispozitiv."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Încercați din nou"</string>
<string name="screen_qr_code_login_invalid_scan_state_subtitle">"Cod QR greșit"</string>
<string name="screen_qr_code_login_no_camera_permission_button">"Mergeți la setările camerei"</string>
<string name="screen_qr_code_login_no_camera_permission_state_description">"Trebuie să acordați permisiunea ca %1$s să folosească camera dispozitivului pentru a continua."</string>
<string name="screen_qr_code_login_no_camera_permission_state_title">"Permiteți accesul la cameră pentru a scana codul QR"</string>
<string name="screen_qr_code_login_scanning_state_title">"Scanați codul QR"</string>
<string name="screen_qr_code_login_start_over_button">"Începeți din nou"</string>
<string name="screen_qr_code_login_unknown_error_description">"A apărut o eroare neașteptată. Vă rugăm să încercați din nou."</string>
<string name="screen_qr_code_login_verify_code_loading">"În așteptarea celuilalt dispozitiv"</string>
<string name="screen_qr_code_login_verify_code_subtitle">"Furnizorul dumneavoastră de cont poate solicita următorul cod pentru a verifica conectarea."</string>
<string name="screen_qr_code_login_verify_code_title">"Codul dumneavoastră de verificare"</string>
<string name="screen_welcome_bullet_1">"Apelurile, sondajele, căutare și multe altele vor fi adăugate în cursul acestui an."</string>
<string name="screen_welcome_bullet_2">"Istoricul mesajelor pentru camerele criptate nu va fi disponibil în această actualizare."</string>
<string name="screen_welcome_bullet_3">"Ne-ar plăcea să auzim de la dumneavoastră, spuneți-ne ce părere aveți prin intermediul paginii de setări."</string>

View File

@@ -2,19 +2,33 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"Вы можете изменить настройки позже."</string>
<string name="screen_notification_optin_title">"Разрешите уведомления и никогда не пропустите сообщение"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Установление соединения"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Установление безопасного соединения"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Не удалось установить безопасное соединение с новым устройством. Существующие устройства по-прежнему в безопасности, и вам не нужно беспокоиться о них."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Что теперь?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"Попробуйте снова войти в систему с помощью QR-кода, если это была сетевая проблема"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"Если вы столкнулись с той же проблемой, попробуйте сменить точку доступа Wi-Fi или используйте мобильные данные"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"Если это не помогло, войдите вручную"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"Соединение не защищено"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Вам будет предложено ввести две цифры, показанные ниже."</string>
<string name="screen_qr_code_login_device_code_title">"Введите номер на своем устройстве"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Вам нужно будет ввести две цифры, показанные на этом устройстве."</string>
<string name="screen_qr_code_login_device_code_title">"Введите показанный номер на своем другом устройстве"</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"Вход на другом устройстве был отменен."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Запрос на вход отменен"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"Запрос не был принят на другом устройстве."</string>
<string name="screen_qr_code_login_error_declined_title">"Вход отклонен"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Срок действия входа истек. Пожалуйста, попробуйте еще раз."</string>
<string name="screen_qr_code_login_error_expired_title">"Вход в систему не был выполнен вовремя"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Другое устройство не поддерживает вход в %s с помощью QR-кода.
Попробуйте войти вручную или отсканируйте QR-код на другом устройстве."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"QR-код не поддерживается"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Поставщик учетной записи не поддерживает %1$s."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s не поддерживается"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Готово к сканированию"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Откройте %1$s на настольном устройстве"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Нажмите на свое изображение"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Выбрать %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"\"Привязать новое устройство\""</string>
<string name="screen_qr_code_login_initial_state_item_4">"Отсканируйте QR-код с помощью этого устройства"</string>
<string name="screen_qr_code_login_initial_state_title">"Откройте %1$s на другом устройстве, чтобы получить QR-код"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Используйте QR-код, показанный на другом устройстве."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Повторить попытку"</string>

View File

@@ -11,11 +11,24 @@
<string name="screen_qr_code_login_connection_note_secure_state_title">"Pripojenie nie je bezpečené"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Budete požiadaní o zadanie dvoch číslic zobrazených na tomto zariadení."</string>
<string name="screen_qr_code_login_device_code_title">"Zadajte nižšie uvedené číslo na vašom druhom zariadení"</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"Prihlásenie bolo zrušené na druhom zariadení."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Žiadosť o prihlásenie bola zrušená"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"Žiadosť na vašom druhom zariadení nebola prijatá."</string>
<string name="screen_qr_code_login_error_declined_title">"Prihlásenie bolo odmietnuté"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Platnosť prihlásenia vypršala. Skúste to prosím znova."</string>
<string name="screen_qr_code_login_error_expired_title">"Prihlásenie nebolo včas dokončené"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Vaše druhé zariadenie nepodporuje prihlásenie do aplikácie %s pomocou QR kódu.
Skúste sa prihlásiť manuálne alebo naskenujte QR kód pomocou iného zariadenia."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"QR kód nie je podporovaný"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Poskytovateľ vášho účtu nepodporuje %1$s."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s nie je podporovaný"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Pripravené na skenovanie"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Otvorte %1$s na stolnom zariadení"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Kliknite na svoj obrázok"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Vyberte %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"„Prepojiť nové zariadenie“"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Postupujte podľa zobrazených pokynov"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Naskenujte QR kód pomocou tohto zariadenia"</string>
<string name="screen_qr_code_login_initial_state_title">"Ak chcete získať QR kód, otvorte %1$s na inom zariadení"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Použite QR kód zobrazený na druhom zariadení."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Skúste to znova"</string>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"您可以稍后更改设置。"</string>
<string name="screen_notification_optin_title">"允许通知,绝不错过任何消息"</string>
<string name="screen_qr_code_login_connecting_subtitle">"建立安全连接"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"无法与新设备建立安全连接。您现有的设备仍然安全,无需担心。"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"现在怎么办?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"如果这是网络问题,请尝试使用二维码再次登录"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"如果你遇到同样的问题,请尝试使用不同的 WiFi 网络或使用你的移动数据代替 WiFi"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"如果不起作用,请手动登录"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"连接不安全"</string>
<string name="screen_qr_code_login_device_code_subtitle">"您会被要求输入此设备上显示的两位数。"</string>
<string name="screen_qr_code_login_device_code_title">"在您的其他设备上输入下面的数字"</string>
<string name="screen_qr_code_login_initial_state_item_1">"在桌面设备上打开 %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_2">"点击你的头像"</string>
<string name="screen_qr_code_login_initial_state_item_3">"选择 %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"「连接新设备」"</string>
<string name="screen_qr_code_login_initial_state_item_4">"按照说明进行操作"</string>
<string name="screen_qr_code_login_initial_state_title">"在另一台设备上打开 %1$s 以获取二维码"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"使用其他设备上显示的二维码。"</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"再试一次"</string>
<string name="screen_qr_code_login_invalid_scan_state_subtitle">"二维码错误"</string>
<string name="screen_qr_code_login_no_camera_permission_button">"转到摄像头设置"</string>
<string name="screen_qr_code_login_no_camera_permission_state_description">"您需要授予 %1$s 使用设备摄像头的权限才能继续。"</string>
<string name="screen_qr_code_login_no_camera_permission_state_title">"允许摄像头权限以扫描 QR 码"</string>
<string name="screen_qr_code_login_scanning_state_title">"扫描二维码"</string>
<string name="screen_qr_code_login_start_over_button">"重新开始"</string>
<string name="screen_qr_code_login_unknown_error_description">"发生了意外错误。请再试一次。"</string>
<string name="screen_qr_code_login_verify_code_loading">"等着您的其他设备"</string>
<string name="screen_qr_code_login_verify_code_subtitle">"您的账户提供商可能会要求您提供以下代码来验证登录。"</string>
<string name="screen_qr_code_login_verify_code_title">"您的验证码"</string>
<string name="screen_welcome_bullet_1">"今年晚些时候将增加通话、投票、搜索等功能。"</string>
<string name="screen_welcome_bullet_2">"加密房间的消息历史记录尚不可用。"</string>
<string name="screen_welcome_bullet_3">"我们很乐意听取您的意见,请通过设置页面告诉我们您的想法。"</string>
<string name="screen_welcome_button">"开始吧!"</string>
<string name="screen_welcome_subtitle">"以下是您需要了解的内容:"</string>
<string name="screen_welcome_title">"欢迎使用 %1$s"</string>
</resources>

View File

@@ -11,11 +11,24 @@
<string name="screen_qr_code_login_connection_note_secure_state_title">"Connection not secure"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Youll be asked to enter the two digits shown on this device."</string>
<string name="screen_qr_code_login_device_code_title">"Enter the number below on your other device"</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"The sign in was cancelled on the other device."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Sign in request cancelled"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"The request on your other device was not accepted."</string>
<string name="screen_qr_code_login_error_declined_title">"Sign in declined"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Sign in expired. Please try again."</string>
<string name="screen_qr_code_login_error_expired_title">"The sign in was not completed in time"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Your other device does not support signing in to %s with a QR code.
Try signing in manually, or scan the QR code with another device."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"QR code not supported"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Your account provider does not support %1$s."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s not supported"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Ready to scan"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Open %1$s on a desktop device"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Click on your avatar"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Select %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"“Link new device”"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Follow the instructions shown"</string>
<string name="screen_qr_code_login_initial_state_item_4">"Scan the QR code with this device"</string>
<string name="screen_qr_code_login_initial_state_title">"Open %1$s on another device to get the QR code"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Use the QR code shown on the other device."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Try again"</string>

View File

@@ -24,10 +24,10 @@ import io.element.android.features.ftue.impl.state.DefaultFtueService
import io.element.android.features.ftue.impl.state.FtueStep
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.test.FakeLockScreenService
import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider

View File

@@ -16,7 +16,7 @@
package io.element.android.features.ftue.impl.welcome.state
class FakeWelcomeState : WelcomeScreenState {
class FakeWelcomeScreenState : WelcomeScreenState {
private var isWelcomeScreenNeeded = true
override fun isWelcomeScreenNeeded(): Boolean {

View File

@@ -25,4 +25,5 @@ android {
dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.services.analytics.api)
}

View File

@@ -33,9 +33,8 @@ import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.api.extensions.toAnalyticsJoinedRoom
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.Optional
@@ -44,7 +43,7 @@ import kotlin.jvm.optionals.getOrNull
class AcceptDeclineInvitePresenter @Inject constructor(
private val client: MatrixClient,
private val analyticsService: AnalyticsService,
private val joinRoom: JoinRoom,
private val notificationDrawerManager: NotificationDrawerManager,
) : Presenter<AcceptDeclineInviteState> {
@Composable
@@ -59,9 +58,11 @@ class AcceptDeclineInvitePresenter @Inject constructor(
fun handleEvents(event: AcceptDeclineInviteEvents) {
when (event) {
is AcceptDeclineInviteEvents.AcceptInvite -> {
currentInvite = Optional.of(event.invite)
localCoroutineScope.acceptInvite(event.invite.roomId, acceptedAction)
// currentInvite is used to render the decline confirmation dialog
// and to reuse the roomId when the user confirm the rejection of the invitation.
// Just set it to empty here.
currentInvite = Optional.empty()
localCoroutineScope.acceptInvite(event.invite.roomId, acceptedAction)
}
is AcceptDeclineInviteEvents.DeclineInvite -> {
@@ -100,14 +101,18 @@ class AcceptDeclineInvitePresenter @Inject constructor(
)
}
private fun CoroutineScope.acceptInvite(roomId: RoomId, acceptedAction: MutableState<AsyncAction<RoomId>>) = launch {
private fun CoroutineScope.acceptInvite(
roomId: RoomId,
acceptedAction: MutableState<AsyncAction<RoomId>>,
) = launch {
acceptedAction.runUpdatingState {
client.joinRoom(roomId)
joinRoom(
roomId = roomId,
serverNames = emptyList(),
trigger = JoinedRoom.Trigger.Invite,
)
.onSuccess {
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true)
client.getRoom(roomId)?.use { room ->
analyticsService.capture(room.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
}
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId)
}
.map { roomId }
}
@@ -117,7 +122,7 @@ class AcceptDeclineInvitePresenter @Inject constructor(
suspend {
client.getRoom(roomId)?.use {
it.leave().getOrThrow()
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true)
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId)
}
roomId
}.runCatchingUpdatingState(declinedAction)

Some files were not shown because too many files have changed in this diff Show More