diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd5524c7e3..7d1f7d8ea3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,19 +44,19 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 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 }} persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble debug APKs @@ -80,7 +80,7 @@ jobs: path: | app/build/outputs/apk/gplay/debug/*-universal-debug.apk app/build/outputs/apk/fdroid/debug/*-universal-debug.apk - - uses: rnkdsh/action-upload-diawi@4e1421305be7cfc510d05f47850262eeaf345108 # v1.5.12 + - uses: rnkdsh/action-upload-diawi@76778fcd1f9f589efaaa62f63d5f03430bbb1306 # v1.5.13 id: diawi # Do not fail the whole build if Diawi upload fails continue-on-error: true diff --git a/.github/workflows/build_enterprise.yml b/.github/workflows/build_enterprise.yml index 956655b262..861efd7665 100644 --- a/.github/workflows/build_enterprise.yml +++ b/.github/workflows/build_enterprise.yml @@ -43,7 +43,7 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -56,12 +56,12 @@ jobs: - name: Clone submodules run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble debug Gplay Enterprise APK diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml index 4bb51d05b5..287492bce5 100644 --- a/.github/workflows/danger.yml +++ b/.github/workflows/danger.yml @@ -11,7 +11,7 @@ jobs: # Skip in forks, it doesn't work even with the fallback token if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Add SSH private keys for submodule repositories @@ -24,7 +24,7 @@ jobs: - run: | npm install --save-dev @babel/plugin-transform-flow-strip-types - name: Danger - uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5 + uses: danger/danger-js@e9b58820039524318198d8059ec98b0c02b7875c # 13.0.10 with: args: "--dangerfile ./tools/danger/dangerfile.js" env: diff --git a/.github/workflows/generate_github_pages.yml b/.github/workflows/generate_github_pages.yml index 8de21b3ef1..a9bee5c09d 100644 --- a/.github/workflows/generate_github_pages.yml +++ b/.github/workflows/generate_github_pages.yml @@ -1,9 +1,10 @@ name: Generate GitHub Pages on: workflow_dispatch: - schedule: - # At 00:00 on every Tuesday UTC - - cron: '0 0 * * 2' +# Disabled for now, as we don't want to generate GitHub Pages on every push to main anymore +# schedule: +# # At 00:00 on every Tuesday UTC +# - cron: '0 0 * * 2' permissions: {} @@ -18,12 +19,12 @@ jobs: - name: ⏬ Checkout with LFS uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5 - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Set up Python 3.12 diff --git a/.github/workflows/gradle-wrapper-update.yml b/.github/workflows/gradle-wrapper-update.yml index 66078b7b4b..e98c7ca9eb 100644 --- a/.github/workflows/gradle-wrapper-update.yml +++ b/.github/workflows/gradle-wrapper-update.yml @@ -13,10 +13,10 @@ jobs: # Skip in forks if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 name: Use JDK 21 if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch' with: diff --git a/.github/workflows/maestro-local.yml b/.github/workflows/maestro-local.yml index 9af5c6bc1d..a3f08728e5 100644 --- a/.github/workflows/maestro-local.yml +++ b/.github/workflows/maestro-local.yml @@ -38,19 +38,19 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 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.ref }} persist-credentials: false - - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 name: Use JDK 21 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble debug APK @@ -78,7 +78,7 @@ jobs: concurrency: group: maestro-test steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 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 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 31a8806a85..f9c960fa8d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -32,11 +32,11 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml index 371c11b3ff..e3e1ad6d72 100644 --- a/.github/workflows/nightlyReports.yml +++ b/.github/workflows/nightlyReports.yml @@ -37,13 +37,13 @@ jobs: uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5 - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: false @@ -76,16 +76,16 @@ jobs: name: Dependency analysis runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Dependency analysis diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index ceaa86016a..8aac9e5794 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -33,7 +33,7 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Add SSH private keys for submodule repositories @@ -51,7 +51,7 @@ jobs: name: Search for invalid screenshot files runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Set up Python 3.12 @@ -65,16 +65,16 @@ jobs: name: Search for invalid dependencies runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Set up Python 3.12 @@ -93,7 +93,7 @@ jobs: 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -108,12 +108,12 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run Konsist tests @@ -134,7 +134,7 @@ jobs: group: ${{ github.ref == 'refs/heads/main' && format('check-compose-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-compose-develop-{0}', github.sha) || format('check-compose-{0}', github.ref) }} cancel-in-progress: true steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -149,12 +149,12 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run compose tests @@ -168,7 +168,7 @@ jobs: 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -183,12 +183,12 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Build Gplay Debug @@ -213,7 +213,7 @@ jobs: 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -228,12 +228,12 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run Detekt @@ -254,7 +254,7 @@ jobs: 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -269,12 +269,12 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Run Ktlint check @@ -295,7 +295,7 @@ jobs: group: ${{ github.ref == 'refs/heads/main' && format('check-docs-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-docs-develop-{0}', github.sha) || format('check-docs-{0}', github.ref) }} cancel-in-progress: true steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -319,7 +319,7 @@ jobs: name: Check shell scripts runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Run shellcheck @@ -333,10 +333,10 @@ jobs: permissions: security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files. steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + - uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7 upload_reports: name: Project Check Suite @@ -344,7 +344,7 @@ jobs: needs: [konsist, lint, ktlint, detekt] if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Ensure we are building the branch and not the branch after being merged on develop # https://github.com/actions/checkout/issues/881 @@ -360,7 +360,7 @@ jobs: yarn add danger-plugin-lint-report --dev - name: Danger lint if: always() - uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5 + uses: danger/danger-js@e9b58820039524318198d8059ec98b0c02b7875c # 13.0.10 with: args: "--dangerfile ./tools/danger/dangerfile-lint.js" env: diff --git a/.github/workflows/recordScreenshots.yml b/.github/workflows/recordScreenshots.yml index 4b70cffe61..6edb0492e4 100644 --- a/.github/workflows/recordScreenshots.yml +++ b/.github/workflows/recordScreenshots.yml @@ -54,13 +54,13 @@ jobs: with: persist-credentials: false - name: ☕️ Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' # Add gradle cache, this should speed up the process - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Record screenshots diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eece5ab0d4..5d59c9530b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,16 +34,16 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 - name: Create app bundle env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} @@ -71,7 +71,7 @@ jobs: group: ${{ format('build-release-main-enterprise-{0}', github.sha) }} cancel-in-progress: true steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Add SSH private keys for submodule repositories @@ -82,12 +82,12 @@ jobs: - name: Clone submodules run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 - name: Create Enterprise app bundle env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} @@ -122,16 +122,16 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 - name: Create APKs env: ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }} diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 40cf9d0058..ac9a69c0e8 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -38,19 +38,19 @@ jobs: docker-images: true swap-storage: false - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 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 }} persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Build debug code and test fixtures diff --git a/.github/workflows/sync-localazy.yml b/.github/workflows/sync-localazy.yml index 6de0f3b0df..d52100ad9f 100644 --- a/.github/workflows/sync-localazy.yml +++ b/.github/workflows/sync-localazy.yml @@ -13,16 +13,16 @@ jobs: # Skip in forks if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Set up Python 3.12 diff --git a/.github/workflows/sync-sas-strings.yml b/.github/workflows/sync-sas-strings.yml index 9f7a67cc22..f84b1596cb 100644 --- a/.github/workflows/sync-sas-strings.yml +++ b/.github/workflows/sync-sas-strings.yml @@ -14,7 +14,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} # No concurrency required, runs every time on a schedule. steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Set up Python 3.12 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 842c8113f4..5f646cacf7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,12 +63,12 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: ☕️ Use JDK 21 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Configure gradle - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 with: cache-read-only: ${{ github.ref != 'refs/heads/develop' }} @@ -108,7 +108,7 @@ jobs: # https://github.com/codecov/codecov-action - name: ☂️ Upload coverage reports to codecov - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index f393d5cdd1..089816d5c8 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -2,6 +2,6 @@ diff --git a/CHANGES.md b/CHANGES.md index 9775c2fea5..f31b91bc97 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,238 @@ +Changes in Element X v26.07.0 +============================= + + + +## What's Changed +### ✨ Features +* Add read all messages feature by @hghgrtut in https://github.com/element-hq/element-x-android/pull/7049 +### 🐛 Bugfixes +* Detect RTL text in events and adjust the text rendering by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6994 +### 🗣 Translations +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/7071 +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/7115 +### 🧱 Build +* Fix Sonar with AGP 9 (some workarounds) by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7055 +* Disable periodically generating the screenshot gallery by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7110 +* Try a different workaround for flaky `ScanQrCodeViewTest` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7109 +### 🚧 In development 🚧 +* Protect link new device by @bmarty in https://github.com/element-hq/element-x-android/pull/6992 +### Dependency upgrades +* Update metro to v1.2.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7057 +* Update gradle/actions action to v6.2.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7063 +* Update roborazzi to v1.64.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7068 +* Update rnkdsh/action-upload-diawi action to v1.5.13 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7067 +* Update dependency io.element.android:element-call-embedded to v0.20.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7075 +* Update dependency com.github.matrix-org:matrix-analytics-events to v0.37.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7079 +* Update actions/setup-java action to v5.3.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7088 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.06.18 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7052 +* Update firebaseAppDistribution to v5.3.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7096 +* Update dependency com.google.firebase:firebase-bom to v34.15.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7089 +* Update dependency com.google.crypto.tink:tink-android to v1.22.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7105 +* Update actions/checkout action to v7 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7098 +* Update lifecycle to v2.11.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7097 +* Update danger/danger-js action to v13.0.8 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7104 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.06.25 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7107 +* Update dependency androidx.compose:compose-bom to v2026.06.00 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7095 +* Update dependency io.element.android:element-call-embedded to v0.20.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7117 +* Update zizmorcore/zizmor-action action to v0.5.7 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7116 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.06.30 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7127 +* Update dependency com.posthog:posthog-android to v3.51.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7128 +### Others +* Fix small code smell by @bmarty in https://github.com/element-hq/element-x-android/pull/7058 +* Hide message notification content when the app is locked by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6902 + +## New Contributors +* @hghgrtut made their first contribution in https://github.com/element-hq/element-x-android/pull/7049 + +**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.06.4...v26.07.0 + +Changes in Element X v26.06.4 +============================= + + + +## What's Changed +### ✨ Features +* Add well-known parsing and extension seam for custom recovery passphrase by @jennaharris7 in https://github.com/element-hq/element-x-android/pull/6944 +### 🙌 Improvements +* Add ability to forward a message to several rooms. by @bmarty in https://github.com/element-hq/element-x-android/pull/7013 +### 🐛 Bugfixes +* `screen_custom_recovery_key_input_notice` is now a plurals. by @bmarty in https://github.com/element-hq/element-x-android/pull/7045 +* Replace `ContentResolver.delete` usage with a backwards-compatible version by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7053 +### Dependency upgrades +* Update kotlin to v0.5.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7036 +* Update gradle/actions action to v6.1.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7037 +* Update jna monorepo to v5.19.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7026 +* Update coil to v3.5.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7043 +* Update metro to v1.2.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7048 +* Update dependency io.sentry:sentry-android to v8.43.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7047 +* Update dependencyAnalysis to v3.15.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7050 +* Compile with sdk37 and target API 37 by @bmarty in https://github.com/element-hq/element-x-android/pull/7041 +### Others +* call: Remove deprecated web<->EX api calls, use the new ones by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/6628 +* Fix deprecation warning by @bmarty in https://github.com/element-hq/element-x-android/pull/7042 +* Let Divider use our theme color. by @bmarty in https://github.com/element-hq/element-x-android/pull/7054 + + +**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.06.3...v26.06.4 + +Changes in Element X v26.06.3 +============================= + + + +## What's Changed +### ✨ Features +* Click on avatar in moderation bottom sheet opens avatar preview by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6991 +### 🙌 Improvements +* Change: hide UserLocationPuck when sharing from current device by @ganfra in https://github.com/element-hq/element-x-android/pull/6955 +* Replace "Edit" button with Crop icon. by @bmarty in https://github.com/element-hq/element-x-android/pull/6953 +* change(location): ensure permissions are always requested at least once by @ganfra in https://github.com/element-hq/element-x-android/pull/6996 +* Refactor: replace client-side event filtering for public rooms with SDK by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7025 +### 🐛 Bugfixes +* Ensure the video preview can be played several times. by @bmarty in https://github.com/element-hq/element-x-android/pull/6964 +* Fix "Sent" checkmark disappearing when the message is read and "Share presence" is disabled by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6985 +* Make `BaseRoom.getDirectRoomMember` change when `roomInfo.isDm` changes by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6989 +* Fix invites not being sent during the room creation by @bxdxnn in https://github.com/element-hq/element-x-android/pull/7018 +* Fix sharing media inside the app by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7016 +* Fix ANRs when calculating DB sizes for Sentry by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7017 +* Fix thread list not loading older threads by @bxdxnn in https://github.com/element-hq/element-x-android/pull/7034 +### 🗣 Translations +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6986 +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/7021 +### 🧱 Build +* Try fixing flaky screenshots for location timeline items by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6954 +* `ScanQrCodeViewTest`: try fixing broken test in CI by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7027 +### 🚧 In development 🚧 +* Ensure that the application rotate the QrCode if one day the SDK emits the `.Expired` error. by @bmarty in https://github.com/element-hq/element-x-android/pull/6993 +### Dependency upgrades +* Update dependency androidx.javascriptengine:javascriptengine to v1.1.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6785 +* Update dependency com.google.firebase:firebase-bom to v34.14.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6967 +* Update dependency com.github.matrix-org:matrix-analytics-events to v0.36.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6963 +* Update dependencyAnalysis to v3.14.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6892 +* Update dependency io.element.android:element-call-embedded to v0.20.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6988 +* Update dependency io.mockk:mockk to v1.14.11 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6977 +* Update zizmorcore/zizmor-action action to v0.5.6 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6845 +* deps(codecov) : bumps to v7.0.0 to unblock CI by @ganfra in https://github.com/element-hq/element-x-android/pull/7002 +* Update wysiwyg to v2.42.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7009 +* Update actions/checkout action to v6.0.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6997 +* fix(deps): update android.gradle.plugin to v9 (major) by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6021 +* Update dependencyAnalysis to v3.14.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6995 +* Update dependency io.sentry:sentry-android to v8.43.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6895 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.06.11 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7014 +* Update dependency org.maplibre.gl:android-sdk to v13.3.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7022 +* Update dependency com.google.firebase:firebase-bom to v34.14.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7029 +* Update okhttp monorepo to v5.4.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/7031 +### Others +* Fix some string mappings for link new device errors by @hughns in https://github.com/element-hq/element-x-android/pull/6675 +* Fallback to the default push gateway on error by @p1gp1g in https://github.com/element-hq/element-x-android/pull/5742 +* Fix some string mappings for link new device errors by @bmarty in https://github.com/element-hq/element-x-android/pull/6958 +* Add `/myroomnick` slash command to change your display name in the current room by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6865 +* Update release notes for `v26.05.1` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6990 +* Fix message drafts not being saved in Threads by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6984 +* build-rust-sdk: allow skipping git update for kotlin components by @richvdh in https://github.com/element-hq/element-x-android/pull/7012 +* Fix broken screenshot tests by @jmartinesp in https://github.com/element-hq/element-x-android/pull/7038 + + +**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.06.2...v26.06.3 + +Changes in Element X v26.06.2 +============================= + +Security fixes 🔐 +----------------- +- Fixed an issue with OIDC callback URLs that could cause the app to crash [(GHSA-r4f9-46vw-v7g3)](https://github.com/element-hq/element-x-android/security/advisories/GHSA-r4f9-46vw-v7g3). + +Changes in Element X v26.06.1 +============================= + +The release of `v26.06.0` was cancelled because it contained some changes that would prevent some users with devices having no Vulkan support from being able to install the app. This release contains the same changes as `v26.06.0` but with the Vulkan requirement removed. + +## What's Changed +### ✨ Features +* Image edition before sending: crop and rotate. by @bmarty in https://github.com/element-hq/element-x-android/pull/6842 +* Use a raw key for the SDK stores for new sessions by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6835 +* Notification settings: pick custom sounds for messages and call ringtones by @bmarty in https://github.com/element-hq/element-x-android/pull/6897 +### 🙌 Improvements +* Do not show membership/profile events in public rooms by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6360 +* Use `runBlocking` for the token refresh logic by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6863 +* Move empty day separator filtering to a timeline post-processor by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6866 +* Add better logs to track token update failures by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6859 +* Read map tiler custom style from matrix .well-known file by @bmarty in https://github.com/element-hq/element-x-android/pull/6886 +* change(permissions) : allow to change ShareLiveLocation permission by @ganfra in https://github.com/element-hq/element-x-android/pull/6890 +* Avoid SQLCipher key derivation by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6774 +* change: replace the maplibre-compose UserLocationState to a simpler one by @ganfra in https://github.com/element-hq/element-x-android/pull/6913 +* Change : location provider by @ganfra in https://github.com/element-hq/element-x-android/pull/6935 +* Add flip actions to image edition by @bmarty in https://github.com/element-hq/element-x-android/pull/6949 +* Remove the `FloatingDateBadge` feature flag by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6950 +### 🐛 Bugfixes +* Fix media viewer flickering by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6800 +* Fix 'Conversation label cannot be empty' error by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6823 +* Release proximity wakelock on Element Call when call ends by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6825 +* Hide edit pencil from accessibility by @bmarty in https://github.com/element-hq/element-x-android/pull/6826 +* Don't compress images sent through the Files attachment picker by @cizra in https://github.com/element-hq/element-x-android/pull/6755 +* [a11y] Improve accessibility of video and audio player by @bmarty in https://github.com/element-hq/element-x-android/pull/6830 +* [a11y] Improve accessibility of screen headers. by @bmarty in https://github.com/element-hq/element-x-android/pull/6827 +* Add mark as read / unread in room details by @bmarty in https://github.com/element-hq/element-x-android/pull/6818 +* Fix formatting inconsistencies in latest event summaries by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6855 +* Fix public read receipts being sent by mistake by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6838 +* Fix app having a pink top bar in the recent app list when PIN lock is setup by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6903 +* Create log messages from `WebView` just once by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6923 +* Use secondary color icon for leading icons by @bmarty in https://github.com/element-hq/element-x-android/pull/6926 +* Use reverse ordering for `FilterEmptyDayPostProcessor` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6927 +* Make Vulkan a *not required* feature by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6961 +### 🗣 Translations +* Sync Strings - new translations to Catalan by @ElementBot in https://github.com/element-hq/element-x-android/pull/6856 +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6921 +### 🧱 Build +* Remove DI-generated code from Kover reports by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6834 +* Disable cron jobs and private SSH key jobs in forks by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6821 +* Revert "Disable cron jobs and private SSH key jobs in forks" by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6905 +* Downgrade detekt compose rules by @bmarty in https://github.com/element-hq/element-x-android/pull/6846 +* Add Stefan's etiquette to the project. by @bmarty in https://github.com/element-hq/element-x-android/pull/6909 +### 🚧 In development 🚧 +* [Link new device] Rotate QrCode instead of showing an error by @bmarty in https://github.com/element-hq/element-x-android/pull/6817 +* Fix image resizing behavior. by @bmarty in https://github.com/element-hq/element-x-android/pull/6924 +### Dependency upgrades +* Update dependency net.zetetic:sqlcipher-android to v4.16.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6819 +* Update dependencyAnalysis to v3.11.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6813 +* Update metro to v1.1.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6832 +* Update dependency io.element.android:element-call-embedded to v0.19.4 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6833 +* Update kotlin to v2.3.8 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6822 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.05.20 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6831 +* Update media3 to v1.10.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6816 +* Update peaceiris/actions-gh-pages action to v4.1.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6820 +* Update dependencyAnalysis to v3.12.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6840 +* Update codecov/codecov-action action to v6.0.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6864 +* Update dependency io.element.android:element-call-embedded to v0.20.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6876 +* Update roborazzi to v1.62.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6858 +* Update dependency androidx.compose:compose-bom to v2026.05.01 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6888 +* Update roborazzi to v1.63.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6893 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.05.26 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6885 +* Update dependency org.maplibre.compose:maplibre-compose to v0.13.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6891 +* Update actions/stale action to v10.3.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6904 +* Update tspascoal/get-user-teams-membership action to v4.0.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6900 +* Update dependency org.maplibre.gl:android-sdk to v13.2.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6930 +* Update dependency org.unifiedpush.android:connector to v3.3.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6937 +* Update kotlin to v2.3.9 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6946 +* Update dependency com.posthog:posthog-android to v3.47.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6920 +* Import compound token from release 10.2.1 https://github.com/element-hq/compound-design-tokens/releases/tag/v10.2.1 by @bmarty in https://github.com/element-hq/element-x-android/pull/6942 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.06.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6947 +* Update dependency com.github.matrix-org:matrix-analytics-events to v0.36.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6939 +### Others +* Make the avatar in the room member moderation bottom sheet clickable by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6705 +* Do not hide your own media for "Show media in timeline" by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6898 +* Report problem: add an optional TextField to provide a GitHub issue number. by @bmarty in https://github.com/element-hq/element-x-android/pull/6911 +* Fix read receipts not shown for calls by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6889 +* Reorder room detail items by @bmarty in https://github.com/element-hq/element-x-android/pull/6929 +* [Media viewer] File preview improvement by @bmarty in https://github.com/element-hq/element-x-android/pull/6933 +* [Media bottom sheet] UI iteration by @bmarty in https://github.com/element-hq/element-x-android/pull/6938 +* Add unread count to the room unread indicator by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6887 + + +**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.05.2...v26.06.1 + Changes in Element X v26.05.2 ============================= @@ -42,6 +277,14 @@ Changes in Element X v26.05.1 +Security fixes 🔐 +----------------- + +This release contains some important security fixes: + +- Check the user ID in the `sender_device_keys` property of Olm-encrypted to-device events to prevent sender spoofing by homeserver owners. ([#6553](https://github.com/matrix-org/matrix-rust-sdk/pull/6553), High, [CVE-2026-45056](https://www.cve.org/CVERecord?id=CVE-2026-45056), [GHSA-wfq4-36m3-9g42](https://github.com/matrix-org/matrix-rust-sdk/security/advisories/GHSA-wfq4-36m3-9g42)) +- Reject invalid edits as candidates for timeline updates. ([#6454](https://github.com/matrix-org/matrix-rust-sdk/pull/6454), Moderate, [CVE-2026-45057](https://www.cve.org/CVERecord?id=CVE-2026-45057), [GHSA-h97m-27fx-42rx](https://github.com/matrix-org/matrix-rust-sdk/security/advisories/GHSA-h97m-27fx-42rx)) + ## What's Changed ### ✨ Features * Make Element Call screen work edge-to-edge by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6634 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index da90ec82e4..ecd5ed8e7b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,11 +24,11 @@ import extension.buildConfigFieldStr import extension.locales import extension.setupDependencyInjection import extension.testCommonDependencies +import org.sonarqube.gradle.SonarResolverTask import java.util.Locale plugins { id("io.element.android-compose-application") - alias(libs.plugins.kotlin.android) // When using precompiled plugins, we need to apply the firebase plugin like this id(libs.plugins.firebaseAppDistribution.get().pluginId) id("kotlin-parcelize") @@ -189,6 +189,7 @@ android { buildFeatures { buildConfig = true + resValues = true } flavorDimensions += "store" productFlavors { @@ -245,6 +246,11 @@ androidComponents { configureLicensesTasks(reportingExtension) } +// Configure the SonarQube plugin to wait for the resource generation tasks to complete before running the analysis. +tasks.withType().configureEach { + dependsOn("generateGplayDebugResValues", "generateGplayDebugAndroidTestResValues") +} + setupDependencyInjection() dependencies { diff --git a/app/src/test/kotlin/io/element/android/x/intent/DefaultIntentProviderTest.kt b/app/src/test/kotlin/io/element/android/x/intent/DefaultIntentProviderTest.kt index 4598a74e51..be059ed2a8 100644 --- a/app/src/test/kotlin/io/element/android/x/intent/DefaultIntentProviderTest.kt +++ b/app/src/test/kotlin/io/element/android/x/intent/DefaultIntentProviderTest.kt @@ -24,14 +24,12 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_THREAD_ID import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.x.MainActivity import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment -@RunWith(RobolectricTestRunner::class) -class DefaultIntentProviderTest { +class DefaultIntentProviderTest : RobolectricTest() { @Test fun `test getViewRoomIntent with data`() { val deepLinkCreator = lambdaRecorder { _, _, _, _ -> "deepLinkCreatorResult" } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt index 6dffda9e42..5ef3d8cd70 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt @@ -45,15 +45,13 @@ import io.element.android.services.analytics.test.watchers.FakeAnalyticsSendMess import io.element.android.services.appnavstate.api.ActiveRoomsHolder import io.element.android.services.appnavstate.test.FakeActiveRoomsHolder import io.element.android.services.appnavstate.test.FakeAppNavigationStateService +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class JoinedRoomLoadedFlowNodeTest { +class JoinedRoomLoadedFlowNodeTest : RobolectricTest() { @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() diff --git a/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt index 451ca279f8..841f79678b 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt @@ -29,13 +29,11 @@ import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.oauth.api.OAuthAction import io.element.android.libraries.oauth.test.FakeOAuthIntentResolver import io.element.android.tests.testutils.lambda.lambdaError +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment -@RunWith(RobolectricTestRunner::class) -class IntentResolverTest { +class IntentResolverTest : RobolectricTest() { @Test fun `resolve launcher intent should return null`() { val sut = createIntentResolver() diff --git a/build.gradle.kts b/build.gradle.kts index 661fc9d30a..0e0df9dbc6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -106,8 +106,6 @@ allprojects { // Fix compilation warning for annotations // See https://youtrack.jetbrains.com/issue/KT-73255/Change-defaulting-rule-for-annotations for more details freeCompilerArgs.add("-Xannotation-default-target=first-only") - // Opt-in to context receivers - freeCompilerArgs.add("-Xcontext-parameters") } } } diff --git a/enterprise b/enterprise index 6781da90aa..efdf9d9a15 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit 6781da90aae61cf77dcdbc543e18d76411d578b4 +Subproject commit efdf9d9a15a5b600c55f674d64794e7737ad906e diff --git a/fastlane/metadata/android/en-US/changelogs/202606000.txt b/fastlane/metadata/android/en-US/changelogs/202606000.txt new file mode 100644 index 0000000000..6c68999e99 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/202606000.txt @@ -0,0 +1,2 @@ +Main changes in this version: added image editing before sending and an option for custom notification sounds, improved start times, several other bug fixes and improvements. +Full changelog: https://github.com/element-hq/element-x-android/releases \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/202606010.txt b/fastlane/metadata/android/en-US/changelogs/202606010.txt new file mode 100644 index 0000000000..08c06cf192 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/202606010.txt @@ -0,0 +1,2 @@ +Main changes in this version: fixed an issue with devices not supporting Vulkan, added image editing before sending and an option for custom notification sounds, improved start times, several other bug fixes and improvements. +Full changelog: https://github.com/element-hq/element-x-android/releases \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/202606030.txt b/fastlane/metadata/android/en-US/changelogs/202606030.txt new file mode 100644 index 0000000000..a4b397f1bb --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/202606030.txt @@ -0,0 +1,2 @@ +Main changes in this version: bug fixes and improvements. +Full changelog: https://github.com/element-hq/element-x-android/releases \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/202606040.txt b/fastlane/metadata/android/en-US/changelogs/202606040.txt new file mode 100644 index 0000000000..a4b397f1bb --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/202606040.txt @@ -0,0 +1,2 @@ +Main changes in this version: bug fixes and improvements. +Full changelog: https://github.com/element-hq/element-x-android/releases \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/202607000.txt b/fastlane/metadata/android/en-US/changelogs/202607000.txt new file mode 100644 index 0000000000..a4b397f1bb --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/202607000.txt @@ -0,0 +1,2 @@ +Main changes in this version: bug fixes and improvements. +Full changelog: https://github.com/element-hq/element-x-android/releases \ No newline at end of file diff --git a/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt b/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt index 4fc9ce5c6b..c05edd825c 100644 --- a/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt +++ b/features/analytics/impl/src/main/kotlin/io/element/android/features/analytics/impl/AnalyticsOptInView.kt @@ -31,12 +31,12 @@ import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.analytics.api.AnalyticsOptInEvents import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule -import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem -import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.background.OnboardingBackground import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.components.ClickableLinkText +import io.element.android.libraries.designsystem.components.visuallist.VisualList +import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart @@ -129,22 +129,21 @@ private fun AnalyticsOptInContent() { verticalBias = -0.4f ) ) { - InfoListOrganism( + VisualList( items = persistentListOf( - InfoListItem( + VisualListItemData( message = stringResource(id = R.string.screen_analytics_prompt_data_usage), iconVector = CompoundIcons.CheckCircle(), ), - InfoListItem( + VisualListItemData( message = stringResource(id = R.string.screen_analytics_prompt_third_party_sharing), iconVector = CompoundIcons.CheckCircle(), ), - InfoListItem( + VisualListItemData( message = stringResource(id = R.string.screen_analytics_prompt_settings), iconVector = CompoundIcons.CheckCircle(), ), ), - textStyle = ElementTheme.typography.fontBodyLgMedium, iconTint = ElementTheme.colors.iconSuccessPrimary, ) } diff --git a/features/announcement/impl/src/main/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementView.kt b/features/announcement/impl/src/main/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementView.kt index c544fd4914..5f7778900b 100644 --- a/features/announcement/impl/src/main/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementView.kt +++ b/features/announcement/impl/src/main/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementView.kt @@ -36,10 +36,10 @@ import io.element.android.features.announcement.impl.AnnouncementState import io.element.android.features.announcement.impl.AnnouncementStateProvider import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule -import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem -import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.components.BigIcon +import io.element.android.libraries.designsystem.components.visuallist.VisualList +import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button @@ -134,11 +134,9 @@ private fun FullscreenAnnouncementContent( Column( modifier = modifier.fillMaxSize(), ) { - InfoListOrganism( + VisualList( modifier = Modifier.fillMaxWidth(), items = announcement.items(), - textStyle = ElementTheme.typography.fontBodyLgMedium, - iconTint = ElementTheme.colors.iconSecondary, iconSize = 24.dp ) announcement.notice()?.let { notice -> @@ -186,25 +184,25 @@ private fun Announcement.Fullscreen.icon() = when (this) { } @Composable -private fun Announcement.Fullscreen.items(): ImmutableList = when (this) { +private fun Announcement.Fullscreen.items(): ImmutableList = when (this) { Announcement.Fullscreen.Space -> persistentListOf( - InfoListItem( + VisualListItemData( message = "View spaces you\'ve created or joined", iconVector = CompoundIcons.VisibilityOn(), ), - InfoListItem( + VisualListItemData( message = "Accept or decline invites to spaces", iconVector = CompoundIcons.Email(), ), - InfoListItem( + VisualListItemData( message = "Discover any rooms you can join in your spaces", iconVector = CompoundIcons.Search(), ), - InfoListItem( + VisualListItemData( message = "Join public spaces", iconVector = CompoundIcons.Explore(), ), - InfoListItem( + VisualListItemData( message = "Leave any spaces you’ve joined", iconVector = CompoundIcons.Leave(), ), diff --git a/features/announcement/impl/src/test/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementViewTest.kt b/features/announcement/impl/src/test/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementViewTest.kt index b7932898a8..e049935212 100644 --- a/features/announcement/impl/src/test/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementViewTest.kt +++ b/features/announcement/impl/src/test/kotlin/io/element/android/features/announcement/impl/fullscreen/FullscreenAnnouncementViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.announcement.api.Announcement import io.element.android.features.announcement.impl.AnnouncementEvent import io.element.android.features.announcement.impl.AnnouncementState @@ -23,11 +22,10 @@ import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class FullscreenAnnouncementViewTest { +class FullscreenAnnouncementViewTest : RobolectricTest() { @Test fun `clicking on back sends a AnnouncementEvent`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/call/impl/build.gradle.kts b/features/call/impl/build.gradle.kts index 2843e47870..d01e31451e 100644 --- a/features/call/impl/build.gradle.kts +++ b/features/call/impl/build.gradle.kts @@ -84,7 +84,6 @@ dependencies { implementation(projects.services.toolbox.api) implementation(libs.androidx.webkit) implementation(libs.coil.compose) - implementation(libs.network.retrofit) implementation(libs.serialization.json) implementation(libs.element.call.embedded) api(projects.features.call.api) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt index febd919149..e68e57118b 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WebViewAudioManager.kt @@ -207,7 +207,6 @@ class WebViewAudioManager( } audioManager.mode = AudioManager.MODE_NORMAL - if (!hasRegisteredCallbacks) { Timber.w("Audio: tried to disable webview in-call audio mode without registering callbacks") return @@ -265,8 +264,8 @@ class WebViewAudioManager( private fun setWebViewAndroidNativeBridge() { Timber.d("Adding callback in controls.onAudioPlaybackStarted") webView.evaluateJavascript("controls.onAudioPlaybackStarted = () => { androidNativeBridge.onTrackReady(); };", null) - Timber.d("Adding callback in controls.onOutputDeviceSelect") - webView.evaluateJavascript("controls.onOutputDeviceSelect = (id) => { androidNativeBridge.setOutputDevice(id); };", null) + Timber.d("Adding callback in controls.onAudioDeviceSelect") + webView.evaluateJavascript("controls.onAudioDeviceSelect = (id) => { androidNativeBridge.setAudioDevice(id); };", null) } /** @@ -293,8 +292,8 @@ class WebViewAudioManager( ) { Timber.d("Updating available audio devices") val deviceList = json.encodeToString(devices) - webView.evaluateJavascript("controls.setAvailableOutputDevices($deviceList);", { - Timber.d("Audio: setAvailableOutputDevices result: $it") + webView.evaluateJavascript("controls.setAvailableAudioDevices($deviceList);", { + Timber.d("Audio: setAvailableAudioDevices result: $it") }) } @@ -342,6 +341,7 @@ class WebViewAudioManager( } else { // On Android 11 and lower, we don't have the concept of communication devices // We have to call the right methods based on the device type + @Suppress("DEPRECATION") if (device != null) { if (device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO && disableBluetoothAudioDevices) { Timber.w("Bluetooth audio devices are disabled on this Android version") @@ -350,11 +350,9 @@ class WebViewAudioManager( return } setAudioEnabled(true) - @Suppress("DEPRECATION") isSpeakerphoneOn = device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER isBluetoothScoOn = device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO } else { - @Suppress("DEPRECATION") isSpeakerphoneOn = false isBluetoothScoOn = false } @@ -399,7 +397,7 @@ private class AndroidWebViewAudioBridge( private val onAudioPlaybackStarted: () -> Unit, ) { @JavascriptInterface - fun setOutputDevice(id: String) { + fun setAudioDevice(id: String) { Timber.d("Audio device selected in webview, id: $id") onAudioDeviceSelected(id) } diff --git a/features/call/impl/src/main/res/values-zh/translations.xml b/features/call/impl/src/main/res/values-zh/translations.xml index 7a81fde819..8b2ae7e56e 100644 --- a/features/call/impl/src/main/res/values-zh/translations.xml +++ b/features/call/impl/src/main/res/values-zh/translations.xml @@ -1,6 +1,6 @@ - "通话进行中" + "正在进行的通话" "点击以返回通话" "☎️ 通话中" "Element Call 不支持在此 Android 版本中使用蓝牙音频设备。请选择其它音频设备。" diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt index f21447cc85..9b2ee3d923 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt @@ -21,19 +21,17 @@ 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_USER_ID_2 import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.Shadows.shadowOf import kotlin.time.Duration.Companion.seconds -@RunWith(RobolectricTestRunner::class) -class DefaultElementCallEntryPointTest { +class DefaultElementCallEntryPointTest : RobolectricTest() { @Test fun `startCall - starts ElementCallActivity setup with the needed extras`() = runTest { val entryPoint = createEntryPoint() diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt index c055b408dd..3f5c1c4e50 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/notifications/RingingCallNotificationCreatorTest.kt @@ -23,13 +23,11 @@ import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.ui.media.test.FakeImageLoaderHolder import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class RingingCallNotificationCreatorTest { +class RingingCallNotificationCreatorTest : RobolectricTest() { @Test fun `createNotification - with no associated MatrixClient does nothing`() = runTest { val notificationCreator = createRingingCallNotificationCreator( diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenViewTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenViewTest.kt index 99aaee6f39..76ce8e8ede 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenViewTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenViewTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.call.impl.pip.PictureInPictureEvent import io.element.android.features.call.impl.pip.PictureInPictureState import io.element.android.features.call.impl.pip.aPictureInPictureState @@ -26,9 +25,9 @@ import io.element.android.features.call.impl.ui.JavascriptBackHandlerBridge import io.element.android.features.call.impl.ui.aCallScreenState import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.Implementation import org.robolectric.annotation.Implements @@ -36,8 +35,7 @@ import org.robolectric.annotation.Resetter import org.robolectric.shadows.ShadowWebView @OptIn(ExperimentalTestApi::class) -@RunWith(AndroidJUnit4::class) -class CallScreenViewTest { +class CallScreenViewTest : RobolectricTest() { @Test fun `pressing back key triggers hangup when no web view is available and pip is unsupported`() = runAndroidComposeUiTest { val callEvents = EventsRecorder() diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt index 3712904b03..c95f8c5088 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt @@ -45,6 +45,7 @@ import io.element.android.services.toolbox.test.systemclock.FakeSystemClock import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.plantTestTimber +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.mockk.coVerify import io.mockk.mockk import io.mockk.verify @@ -54,12 +55,9 @@ import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.Shadows.shadowOf -@RunWith(RobolectricTestRunner::class) -class DefaultActiveCallManagerTest { +class DefaultActiveCallManagerTest : RobolectricTest() { private val notificationId = NotificationIdProvider.getForegroundServiceNotificationId(ForegroundServiceType.INCOMING_CALL) @OptIn(ExperimentalCoroutinesApi::class) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt index 0a7309a2b0..e03d36363d 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt @@ -13,6 +13,9 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter @@ -36,6 +39,13 @@ fun AddPeopleView( modifier: Modifier = Modifier, invitePeopleView: @Composable () -> Unit, ) { + val currentOnFinish by rememberUpdatedState(onFinish) + LaunchedEffect(state.sendInvitesAction, state.createRoomFromDmAction) { + if (state.sendInvitesAction.isSuccess() || state.createRoomFromDmAction.isSuccess()) { + currentOnFinish() + } + } + HeaderFooterPage( modifier = modifier, contentPadding = PaddingValues(0.dp), @@ -47,7 +57,6 @@ fun AddPeopleView( text = stringResource(CommonStrings.action_finish), onClick = { state.eventSink(InvitePeopleEvents.SendInvites) - onFinish() }, enabled = state.canInvite, modifier = Modifier diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt index 1480e57334..c96fbc4d6b 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt @@ -11,7 +11,8 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -85,9 +86,9 @@ internal fun SelectParentSpaceOptions( ) if (displaySelectSpaceBottomSheet) { - val sheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true, - confirmValueChange = { true }, + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), ) ModalBottomSheet( sheetState = sheetState, diff --git a/features/createroom/impl/src/main/res/values-be/translations.xml b/features/createroom/impl/src/main/res/values-be/translations.xml index 9669bb9090..6b254003b7 100644 --- a/features/createroom/impl/src/main/res/values-be/translations.xml +++ b/features/createroom/impl/src/main/res/values-be/translations.xml @@ -3,9 +3,15 @@ "Новы пакой" "Запрасіць карыстальнікаў" "Пры стварэнні пакоя адбылася памылка" + "Дадаць імя…" + "Новы пакой" + "Новая прастора" "Толькі запрошаныя людзі могуць атрымаць доступ да гэтага пакоя. Усе паведамленні абаронены end-to-end шыфраваннем." "Любы можа знайсці гэты пакой. Вы можаце змяніць гэта ў любы час у наладах пакоя." "Папрасіце далучыцца" + "Адрас" + "Дадаць у прастору" "Тэма (неабавязкова)" + "Дадаць апісанне…" diff --git a/features/createroom/impl/src/main/res/values-uk/translations.xml b/features/createroom/impl/src/main/res/values-uk/translations.xml index a40a2b21a5..6d43472217 100644 --- a/features/createroom/impl/src/main/res/values-uk/translations.xml +++ b/features/createroom/impl/src/main/res/values-uk/translations.xml @@ -31,6 +31,6 @@ "Не додавати до простору" "Головна" "Додати до простору" - "Тема (необов\'язково)" + "Тематика обговорень (необов’язково)" "Додати опис…" diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt index b9d7eb6e7d..c0c4a8a5fe 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt @@ -56,6 +56,7 @@ import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.test import io.mockk.mockk import kotlinx.collections.immutable.persistentMapOf @@ -66,8 +67,6 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import java.io.File import java.util.Optional @@ -75,8 +74,7 @@ private const val AN_URI_FROM_CAMERA = "content://uri_from_camera" private const val AN_URI_FROM_CAMERA_2 = "content://uri_from_camera_2" private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery" -@RunWith(RobolectricTestRunner::class) -class ConfigureRoomPresenterTest { +class ConfigureRoomPresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/deactivation/impl/src/main/kotlin/io/element/android/features/logout/impl/AccountDeactivationView.kt b/features/deactivation/impl/src/main/kotlin/io/element/android/features/logout/impl/AccountDeactivationView.kt index 352efdfb92..738046b3a3 100644 --- a/features/deactivation/impl/src/main/kotlin/io/element/android/features/logout/impl/AccountDeactivationView.kt +++ b/features/deactivation/impl/src/main/kotlin/io/element/android/features/logout/impl/AccountDeactivationView.kt @@ -8,7 +8,6 @@ package io.element.android.features.logout.impl -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -49,17 +48,18 @@ import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.deactivation.impl.R import io.element.android.features.logout.impl.ui.AccountDeactivationActionDialog import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem -import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.form.textFieldState import io.element.android.libraries.designsystem.components.list.SwitchListItem +import io.element.android.libraries.designsystem.components.visuallist.VisualList +import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.PasswordVisibilityToggle import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextField @@ -175,9 +175,9 @@ private fun Content( style = ElementTheme.typography.fontBodyMdRegular, color = ElementTheme.colors.textSecondary, ) - InfoListOrganism( + VisualList( items = persistentListOf( - InfoListItem( + VisualListItemData( message = buildAnnotatedStringWithStyledPart( R.string.screen_deactivate_account_list_item_1, R.string.screen_deactivate_account_list_item_1_bold_part, @@ -194,7 +194,7 @@ private fun Content( ) }, ), - InfoListItem( + VisualListItemData( message = stringResource(R.string.screen_deactivate_account_list_item_2), iconComposable = { Icon( @@ -205,7 +205,7 @@ private fun Content( ) }, ), - InfoListItem( + VisualListItemData( message = stringResource(R.string.screen_deactivate_account_list_item_3), iconComposable = { Icon( @@ -216,7 +216,7 @@ private fun Content( ) }, ), - InfoListItem( + VisualListItemData( message = stringResource(R.string.screen_deactivate_account_list_item_4), iconComposable = { Icon( @@ -280,14 +280,10 @@ private fun Content( placeholder = stringResource(CommonStrings.common_password), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { - val image = - if (passwordVisible) CompoundIcons.VisibilityOn() else CompoundIcons.VisibilityOff() - val description = - if (passwordVisible) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password) - - Box(modifier = Modifier.clickable { passwordVisible = !passwordVisible }) { - Icon(imageVector = image, description) - } + PasswordVisibilityToggle( + visible = passwordVisible, + onToggle = { passwordVisible = !passwordVisible }, + ) }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Password, diff --git a/features/deactivation/impl/src/main/res/values-ko/translations.xml b/features/deactivation/impl/src/main/res/values-ko/translations.xml index 42dd0aa0e2..83eaf7ff21 100644 --- a/features/deactivation/impl/src/main/res/values-ko/translations.xml +++ b/features/deactivation/impl/src/main/res/values-ko/translations.xml @@ -3,11 +3,12 @@ "계정을 비활성화하시겠습니까? 이 작업은 되돌릴 수 없습니다." "모든 내 메시지 삭제" "경고: 향후 사용자는 불완전한 대화 내용을 볼 수 있습니다." - "계정을 비활성화하는 것은 %1$s 이며, 다음과 같은 조치를 취합니다:" + "계정을 삭제하면 %1$s, 다음과 같이 처리됩니다:" "불가역적" "%1$s 귀하의 계정 (로그인할 수 없으며, 귀하의 ID는 재사용할 수 없습니다)." "영구적으로 비활성화" "모든 채팅방에서 자신을 제거하세요." "당사의 신원 서버에서 귀하의 계정 정보를 삭제하세요." "메시지는 등록된 사용자에게는 계속 표시되지만, 삭제하면 신규 또는 미등록 사용자는 볼 수 없게 됩니다." + "계정 삭제" diff --git a/features/deactivation/impl/src/main/res/values-ru/translations.xml b/features/deactivation/impl/src/main/res/values-ru/translations.xml index 79c25af475..17a5158f44 100644 --- a/features/deactivation/impl/src/main/res/values-ru/translations.xml +++ b/features/deactivation/impl/src/main/res/values-ru/translations.xml @@ -9,6 +9,6 @@ "Отключить навсегда" "Вы будете удалены из всех чатов." "Данные Вашего аккаунта будут удалены с нашего сервера идентификации." - "Ваши сообщения по-прежнему будут видны зарегистрированным пользователям, но не будут доступны новым или незарегистрированным пользователям, если вы решите удалить их." + "Ваши сообщения по-прежнему будут видны зарегистрированным пользователям, но не будут доступны новым или незарегистрированным пользователям, если Вы решите удалить их." "Удалить аккаунт" diff --git a/features/deactivation/impl/src/main/res/values-uk/translations.xml b/features/deactivation/impl/src/main/res/values-uk/translations.xml index 62cf66cec1..0f99817462 100644 --- a/features/deactivation/impl/src/main/res/values-uk/translations.xml +++ b/features/deactivation/impl/src/main/res/values-uk/translations.xml @@ -1,14 +1,14 @@ - "Будь ласка, підтвердіть, що ви хочете деактивувати свій обліковий запис. Ця дія не може бути скасована." + "Підтвердьте, що хочете видалити свій обліковий запис. Цю дію неможливо скасувати." "Видалити всі мої повідомлення" "Попередження: майбутні користувачі можуть бачити неповні розмови." - "Деактивація вашого облікового запису%1$s , це буде:" + "Видалення вашого облікового запису %1$s призведе до:" "незворотні" "%1$sваш обліковий запис (ви не можете знову увійти, а ваш ідентифікатор не може бути використаний повторно)." "Назавжди відключити" - "Видалити вас з усіх чатів." + "Вилучити вас з усіх бесід." "Видаліть інформацію свого облікового запису з нашого сервера ідентифікації." "Ваші повідомлення залишатимуться видимими для зареєстрованих користувачів, але недоступними для нових або незареєстрованих користувачів, якщо ви вирішите їх видалити." - "Відключити обліковий запис" + "Видалити обліковий запис" diff --git a/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationViewTest.kt b/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationViewTest.kt index c672fd666b..caf4c0384f 100644 --- a/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationViewTest.kt +++ b/features/deactivation/impl/src/test/kotlin/io/element/android/features/logout/impl/AccountDeactivationViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.deactivation.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.test.AN_EXCEPTION @@ -29,12 +28,11 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressTag +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class AccountDeactivationViewTest { +class AccountDeactivationViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/forward/impl/src/main/kotlin/io/element/android/features/forward/impl/ForwardMessagesNode.kt b/features/forward/impl/src/main/kotlin/io/element/android/features/forward/impl/ForwardMessagesNode.kt index eb085d19c5..1c565a390a 100644 --- a/features/forward/impl/src/main/kotlin/io/element/android/features/forward/impl/ForwardMessagesNode.kt +++ b/features/forward/impl/src/main/kotlin/io/element/android/features/forward/impl/ForwardMessagesNode.kt @@ -74,7 +74,10 @@ class ForwardMessagesNode( return roomSelectEntryPoint.createNode( parentNode = this, buildContext = buildContext, - params = RoomSelectEntryPoint.Params(mode = RoomSelectMode.Forward), + params = RoomSelectEntryPoint.Params( + mode = RoomSelectMode.Forward, + maxNumberOfRooms = RoomSelectEntryPoint.DEFAULT_MAX_NUMBER_OF_ROOMS, + ), callback = callback, ) } diff --git a/features/forward/impl/src/test/kotlin/io/element/android/features/forward/impl/ForwardMessagesViewTest.kt b/features/forward/impl/src/test/kotlin/io/element/android/features/forward/impl/ForwardMessagesViewTest.kt index 57a9f65099..a73478479e 100644 --- a/features/forward/impl/src/test/kotlin/io/element/android/features/forward/impl/ForwardMessagesViewTest.kt +++ b/features/forward/impl/src/test/kotlin/io/element/android/features/forward/impl/ForwardMessagesViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.test.AN_EXCEPTION @@ -24,11 +23,10 @@ import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressTag +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ForwardMessagesViewTest { +class ForwardMessagesViewTest : RobolectricTest() { @Test fun `cancel error emits the expected event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/ftue/impl/src/main/res/values-in/translations.xml b/features/ftue/impl/src/main/res/values-in/translations.xml index 0255251f97..007ae0a4bc 100644 --- a/features/ftue/impl/src/main/res/values-in/translations.xml +++ b/features/ftue/impl/src/main/res/values-in/translations.xml @@ -2,7 +2,7 @@ "Tidak dapat mengonfirmasi?" "Buat kunci pemulihan baru" - "Verifikasi perangkat ini untuk menyiapkan perpesanan aman." + "Pilih cara verifikasi untuk mengatur pengiriman pesan yang aman." "Konfirmasi bahwa ini Anda" "Gunakan perangkat lain" "Gunakan kunci pemulihan" diff --git a/features/ftue/impl/src/main/res/values-ru/translations.xml b/features/ftue/impl/src/main/res/values-ru/translations.xml index 34ac77ae3f..b7c0055b73 100644 --- a/features/ftue/impl/src/main/res/values-ru/translations.xml +++ b/features/ftue/impl/src/main/res/values-ru/translations.xml @@ -6,7 +6,7 @@ "Подтвердите личность" "Использовать другое устройство" "Использовать ключ восстановления" - "Теперь вы можете безопасно читать и отправлять сообщения, и все, с кем вы общаетесь в чате, также могут доверять этому устройству." + "Теперь Вы можете безопасно читать и отправлять сообщения, и все, с кем Вы общаетесь в чате, также могут доверять этому устройству." "Устройство проверено" "Использовать другое устройство" "Ожидание другого устройства…" diff --git a/features/ftue/impl/src/main/res/values-uk/translations.xml b/features/ftue/impl/src/main/res/values-uk/translations.xml index eb00ebf09d..f466bee82d 100644 --- a/features/ftue/impl/src/main/res/values-uk/translations.xml +++ b/features/ftue/impl/src/main/res/values-uk/translations.xml @@ -2,12 +2,12 @@ "Не можете підтвердити?" "Створити новий ключ відновлення" - "Верифікуйте цей пристрій, щоб налаштувати безпечний обмін повідомленнями." - "Підтвердьте, що це ви" + "Виберіть спосіб звіряння, щоб налаштувати безпечний обмін повідомленнями." + "Підтвердьте свою цифрову ідентичність" "Використовуйте інший пристрій" "Використовуйте ключ відновлення" "Тепер ви можете безпечно читати або надсилати повідомлення, і кожен, з ким ви спілкуєтесь, також може довіряти цьому пристрою." - "Пристрій перевірено" + "Пристрій звірено" "Використовуйте інший пристрій" "Чекає на інше пристрій…" "Ви можете змінити свої налаштування пізніше." diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModeViewTest.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModeViewTest.kt index 6e74f58f66..66e2eb38fe 100644 --- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModeViewTest.kt +++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModeViewTest.kt @@ -14,19 +14,17 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.ftue.impl.R import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class ChooseSessionVerificationModeViewTest { +class ChooseSessionVerificationModeViewTest : RobolectricTest() { @Config(qualifiers = "h1024dp") @Test fun `clicking on learn more invokes the expected callback`() = runAndroidComposeUiTest { diff --git a/features/home/impl/build.gradle.kts b/features/home/impl/build.gradle.kts index 0635da39a5..efdc545e61 100644 --- a/features/home/impl/build.gradle.kts +++ b/features/home/impl/build.gradle.kts @@ -57,6 +57,7 @@ dependencies { implementation(libs.androidx.datastore.preferences) implementation(libs.haze) implementation(libs.haze.materials) + implementation(projects.features.preferences.impl) implementation(projects.features.reportroom.api) implementation(projects.features.rolesandpermissions.api) implementation(projects.libraries.previewutils) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt index dee175a7b1..266b6f5a59 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt @@ -279,6 +279,7 @@ private fun RoomsViewList( hideInviteAvatars = hideInvitesAvatars, isInviteSeen = room.displayType == RoomSummaryDisplayType.INVITE && state.seenRoomInvites.contains(room.roomId), + showUnreadCount = state.showUnreadCount, onClick = onRoomClick, eventSink = eventSink, ) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt index 72ecb5046d..ba9a204a64 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomSummaryRow.kt @@ -76,8 +76,9 @@ internal fun RoomSummaryRow( hideInviteAvatars: Boolean, isInviteSeen: Boolean, onClick: (RoomListRoomSummary) -> Unit, - eventSink: (RoomListEvent) -> Unit, modifier: Modifier = Modifier, + showUnreadCount: Boolean = false, + eventSink: (RoomListEvent) -> Unit, ) { Box(modifier = modifier) { when (room.displayType) { @@ -127,7 +128,7 @@ internal fun RoomSummaryRow( timestamp = room.timestamp, isHighlighted = room.isHighlighted ) - MessagePreviewAndIndicatorRow(room = room) + MessagePreviewAndIndicatorRow(room = room, showUnreadCount = showUnreadCount) } } RoomSummaryDisplayType.KNOCKED -> { @@ -273,6 +274,7 @@ private fun InviteSubtitle( @Composable private fun MessagePreviewAndIndicatorRow( room: RoomListRoomSummary, + showUnreadCount: Boolean, modifier: Modifier = Modifier, ) { Row( @@ -360,8 +362,18 @@ private fun MessagePreviewAndIndicatorRow( } if (room.hasNewContent) { val contentDescription = stringResource(CommonStrings.a11y_notifications_new_messages) + val count = if (showUnreadCount) { + if (room.userDefinedNotificationMode == RoomNotificationMode.MUTE) { + room.numberOfUnreadMessages + } else { + room.numberOfUnreadNotifications + } + } else { + null + } UnreadIndicatorAtom( color = tint, + count = count, contentDescription = contentDescription, ) } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContentStateProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContentStateProvider.kt index c79e79be73..0ac2b7bf62 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContentStateProvider.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContentStateProvider.kt @@ -36,6 +36,7 @@ open class RoomListContentStateProvider : PreviewParameterProvider = aRoomListRoomSummaryList(), fullScreenIntentPermissionsState: FullScreenIntentPermissionsState = aFullScreenIntentPermissionsState(), batteryOptimizationState: BatteryOptimizationState = aBatteryOptimizationState(), @@ -43,6 +44,7 @@ internal fun aRoomsContentState( ) = RoomListContentState.Rooms( securityBannerState = securityBannerState, showNewNotificationSoundBanner = showNewNotificationSoundBanner, + showUnreadCount = showUnreadCount, fullScreenIntentPermissionsState = fullScreenIntentPermissionsState, batteryOptimizationState = batteryOptimizationState, summaries = summaries, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt index 66982961fd..9d6a5173ae 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt @@ -69,10 +69,6 @@ fun RoomListContextMenu( onFavoriteChange = { isFavorite -> eventSink(RoomListEvent.SetRoomIsFavorite(contextMenu.roomId, isFavorite)) }, - onClearCacheRoomClick = { - eventSink(RoomListEvent.HideContextMenu) - eventSink(RoomListEvent.ClearCacheOfRoom(contextMenu.roomId)) - }, onReportRoomClick = { eventSink(RoomListEvent.HideContextMenu) onReportRoomClick(contextMenu.roomId) @@ -90,7 +86,6 @@ private fun RoomListModalBottomSheetContent( onFavoriteChange: (isFavorite: Boolean) -> Unit, onRoomMarkReadClick: () -> Unit, onRoomMarkUnreadClick: () -> Unit, - onClearCacheRoomClick: () -> Unit, onReportRoomClick: () -> Unit, ) { Column( @@ -111,7 +106,7 @@ private fun RoomListModalBottomSheetContent( ListItem( headlineContent = { Text( - text = stringResource(id = R.string.screen_roomlist_mark_as_read), + text = stringResource(id = CommonStrings.action_mark_as_read), style = MaterialTheme.typography.bodyLarge, ) }, @@ -119,7 +114,6 @@ private fun RoomListModalBottomSheetContent( leadingContent = ListItemContent.Icon( iconSource = IconSource.Vector(CompoundIcons.MarkAsRead()) ), - style = ListItemStyle.Primary, ) } else { ListItem( @@ -133,7 +127,6 @@ private fun RoomListModalBottomSheetContent( leadingContent = ListItemContent.Icon( iconSource = IconSource.Vector(CompoundIcons.MarkAsUnread()) ), - style = ListItemStyle.Primary, ) } val (textResId, icon) = if (contextMenu.isFavorite) { @@ -159,7 +152,6 @@ private fun RoomListModalBottomSheetContent( onClick = { onFavoriteChange(!contextMenu.isFavorite) }, - style = ListItemStyle.Primary, ) ListItem( headlineContent = { @@ -174,7 +166,6 @@ private fun RoomListModalBottomSheetContent( CompoundIcons.Settings(), ) ), - style = ListItemStyle.Primary, ) if (canReportRoom) { ListItem( @@ -202,18 +193,6 @@ private fun RoomListModalBottomSheetContent( ), style = ListItemStyle.Destructive, ) - if (contextMenu.displayClearRoomCacheAction) { - ListItem( - headlineContent = { - Text(text = "Clear cache for this room") - }, - modifier = Modifier.clickable { onClearCacheRoomClick() }, - leadingContent = ListItemContent.Icon( - iconSource = IconSource.Vector(CompoundIcons.Delete()) - ), - style = ListItemStyle.Primary, - ) - } } } @@ -221,7 +200,7 @@ private fun RoomListModalBottomSheetContent( @Composable internal fun RoomListContextMenuPreview( @PreviewParameter(RoomListStateContextMenuShownProvider::class) contextMenu: RoomListState.ContextMenu.Shown -) = ElementPreview { +) = ElementPreview(fillMaxSize = true) { RoomListContextMenu( contextMenu = contextMenu, canReportRoom = true, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListEvent.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListEvent.kt index 3e82ff9809..49d033682f 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListEvent.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListEvent.kt @@ -30,5 +30,4 @@ sealed interface RoomListEvent { data class MarkAsRead(val roomId: RoomId) : ContextMenuEvent data class MarkAsUnread(val roomId: RoomId) : ContextMenuEvent data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : ContextMenuEvent - data class ClearCacheOfRoom(val roomId: RoomId) : ContextMenuEvent } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt index 2010555cd7..fe09bd7cd1 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt @@ -28,7 +28,6 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.announcement.api.Announcement import io.element.android.features.announcement.api.AnnouncementService import io.element.android.features.home.impl.datasource.RoomListDataSource -import io.element.android.features.home.impl.filters.RoomListFilter.Rooms import io.element.android.features.home.impl.filters.RoomListFiltersState import io.element.android.features.home.impl.filters.into import io.element.android.features.home.impl.search.RoomListSearchEvent @@ -42,20 +41,19 @@ import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteE import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomState +import io.element.android.features.preferences.impl.tasks.MarkRoomAsRead import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.roomlist.RoomList import io.element.android.libraries.matrix.api.roomlist.RoomListFilter -import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar -import io.element.android.libraries.preferences.api.store.AppPreferencesStore -import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.push.api.battery.BatteryOptimizationState -import io.element.android.libraries.push.api.notifications.NotificationCleaner import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.watchers.AnalyticsColdStartWatcher import io.element.android.services.analyticsproviders.api.trackers.captureInteraction @@ -65,7 +63,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -79,17 +76,16 @@ class RoomListPresenter( private val roomListDataSource: RoomListDataSource, private val filtersPresenter: Presenter, private val searchPresenter: Presenter, - private val sessionPreferencesStore: SessionPreferencesStore, private val analyticsService: AnalyticsService, private val acceptDeclineInvitePresenter: Presenter, private val fullScreenIntentPermissionsPresenter: Presenter, private val batteryOptimizationPresenter: Presenter, - private val notificationCleaner: NotificationCleaner, - private val appPreferencesStore: AppPreferencesStore, + private val markRoomAsRead: MarkRoomAsRead, private val seenInvitesStore: SeenInvitesStore, private val announcementService: AnnouncementService, private val coldStartWatcher: AnalyticsColdStartWatcher, private val spaceFiltersPresenter: Presenter, + private val featureFlagService: FeatureFlagService, ) : Presenter { private val encryptionService = client.encryptionService @@ -154,7 +150,6 @@ class RoomListPresenter( } is RoomListEvent.ShowDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Shown(event.roomSummary) RoomListEvent.HideDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Hidden - is RoomListEvent.ClearCacheOfRoom -> coroutineScope.clearCacheOfRoom(event.roomId) } } @@ -165,13 +160,17 @@ class RoomListPresenter( roomListDataSource.updateFilter(allFilters) } + val canReportRoom by produceState(false) { value = client.canReportRoom() } + val showUnreadCount by produceState(false) { + value = featureFlagService.isFeatureEnabled(FeatureFlags.UnreadIndicatorCount) + } + val contentState = roomListContentState( securityBannerDismissed, showNewNotificationSoundBanner, + showUnreadCount, ) - val canReportRoom by produceState(false) { value = client.canReportRoom() } - return RoomListState( contextMenu = contextMenu.value, declineInviteMenu = declineInviteMenu.value, @@ -226,6 +225,7 @@ class RoomListPresenter( private fun roomListContentState( securityBannerDismissed: Boolean, showNewNotificationSoundBanner: Boolean, + showUnreadCount: Boolean, ): RoomListContentState { val roomSummaries by produceState(initialValue = AsyncData.Loading()) { roomListDataSource.roomSummariesFlow.collect { value = AsyncData.Success(it) } @@ -254,6 +254,7 @@ class RoomListPresenter( RoomListContentState.Rooms( securityBannerState = securityBannerState, showNewNotificationSoundBanner = showNewNotificationSoundBanner, + showUnreadCount = showUnreadCount, fullScreenIntentPermissionsState = fullScreenIntentPermissionsPresenter.present(), batteryOptimizationState = batteryOptimizationPresenter.present(), summaries = roomSummaries.dataOrNull().orEmpty().toImmutableList(), @@ -271,7 +272,6 @@ class RoomListPresenter( isDm = event.roomSummary.isDm, isFavorite = event.roomSummary.isFavorite, hasNewContent = event.roomSummary.hasNewContent, - displayClearRoomCacheAction = appPreferencesStore.isDeveloperModeEnabledFlow().first(), ) contextMenuState.value = initialState @@ -304,19 +304,10 @@ class RoomListPresenter( } private fun CoroutineScope.markAsRead(roomId: RoomId) = launch { - notificationCleaner.clearMessagesForRoom(client.sessionId, roomId) - client.getRoom(roomId)?.use { room -> - room.setUnreadFlag(isUnread = false) - val receiptType = if (sessionPreferencesStore.isSendPublicReadReceiptsEnabled().first()) { - ReceiptType.READ - } else { - ReceiptType.READ_PRIVATE + markRoomAsRead(roomId) + .onSuccess { + analyticsService.captureInteraction(name = Interaction.Name.MobileRoomListRoomContextMenuUnreadToggle) } - room.markAsRead(receiptType) - .onSuccess { - analyticsService.captureInteraction(name = Interaction.Name.MobileRoomListRoomContextMenuUnreadToggle) - } - } } private fun CoroutineScope.markAsUnread(roomId: RoomId) = launch { @@ -327,10 +318,4 @@ class RoomListPresenter( } } } - - private fun CoroutineScope.clearCacheOfRoom(roomId: RoomId) = launch { - client.getRoom(roomId)?.use { room -> - room.clearEventCacheStorage() - } - } } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt index e0f4943621..e184a5a57f 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListState.kt @@ -44,7 +44,6 @@ data class RoomListState( val isDm: Boolean, val isFavorite: Boolean, val hasNewContent: Boolean, - val displayClearRoomCacheAction: Boolean, ) : ContextMenu } @@ -72,6 +71,7 @@ sealed interface RoomListContentState { val fullScreenIntentPermissionsState: FullScreenIntentPermissionsState, val batteryOptimizationState: BatteryOptimizationState, val showNewNotificationSoundBanner: Boolean, + val showUnreadCount: Boolean, val summaries: ImmutableList, val seenRoomInvites: ImmutableSet, ) : RoomListContentState diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateContextMenuShownProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateContextMenuShownProvider.kt index a1624e4917..eca1b63d7d 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateContextMenuShownProvider.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateContextMenuShownProvider.kt @@ -31,5 +31,4 @@ internal fun aContextMenuShown( isDm = isDm, hasNewContent = hasNewContent, isFavorite = isFavorite, - displayClearRoomCacheAction = false, ) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt index 942e924820..f67338ef21 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt @@ -33,6 +33,8 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.tokens.generated.CompoundIcons @@ -112,10 +114,12 @@ private fun RoomListSearchContent( title = { // The stateSaver will keep the selection state when returning to this UI val focusRequester = remember { FocusRequester() } + val searchLabel = stringResource(CommonStrings.action_search) FilledTextField( modifier = Modifier .fillMaxWidth() - .focusRequester(focusRequester), + .focusRequester(focusRequester) + .semantics { contentDescription = searchLabel }, state = state.query, lineLimits = TextFieldLineLimits.SingleLine, colors = TextFieldDefaults.colors( @@ -132,7 +136,7 @@ private fun RoomListSearchContent( IconButton(onClick = { state.eventSink(RoomListSearchEvent.ClearQuery) }) { Icon( imageVector = CompoundIcons.Close(), - contentDescription = stringResource(CommonStrings.action_cancel) + contentDescription = stringResource(CommonStrings.a11y_clear_search_field) ) } } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt index 8a270f1b85..c8d710fced 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt @@ -24,7 +24,7 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SheetValue -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -57,8 +57,9 @@ fun SpaceFiltersView( modifier: Modifier = Modifier ) { val isSelecting by rememberUpdatedState(state is SpaceFiltersState.Selecting) - val sheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true, + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), confirmValueChange = { sheetValueTarget -> // This ensures the hide animation is not cancelled when (sheetValueTarget) { @@ -187,6 +188,6 @@ private fun SpaceFilterItem( @PreviewsDayNight @Composable -internal fun SpaceFiltersViewPreview(@PreviewParameter(SpaceFiltersStateProvider::class) state: SpaceFiltersState) = ElementPreview { +internal fun SpaceFiltersViewPreview(@PreviewParameter(SpaceFiltersStateProvider::class) state: SpaceFiltersState) = ElementPreview(fillMaxSize = true) { SpaceFiltersView(state = state) } diff --git a/features/home/impl/src/main/res/values-in/translations.xml b/features/home/impl/src/main/res/values-in/translations.xml index 6a822e3680..a60d98babb 100644 --- a/features/home/impl/src/main/res/values-in/translations.xml +++ b/features/home/impl/src/main/res/values-in/translations.xml @@ -4,8 +4,8 @@ "Nonaktifkan optimasi" "Notifikasi tidak masuk?" "Buat kunci pemulihan baru yang dapat digunakan untuk memulihkan riwayat pesan terenkripsi Anda jika Anda kehilangan akses ke perangkat Anda." - "Siapkan pemulihan" - "Siapkan pemulihan" + "Siapkan Kunci pemulihan" + "Cadangkan obrolan Anda" "Konfirmasikan kunci pemulihan Anda untuk mempertahankan akses ke penyimpanan kunci dan riwayat pesan Anda." "Masukkan kunci pemulihan Anda" "Lupa kunci pemulihan Anda?" diff --git a/features/home/impl/src/main/res/values-ja/translations.xml b/features/home/impl/src/main/res/values-ja/translations.xml index c1c1ade1ff..855bb14533 100644 --- a/features/home/impl/src/main/res/values-ja/translations.xml +++ b/features/home/impl/src/main/res/values-ja/translations.xml @@ -1,7 +1,7 @@ "すべての通知を確実に受信するために、このアプリのバッテリー最適化を無効にしてください。" - "最適化を無効にする" + "無効にする" "通知が届いていませんか?" "通知音が更新され、より明確で速く、そして邪魔にならなくなりました。" "サウンドを刷新しました" @@ -38,7 +38,7 @@ "低い優先度のチャットはまだありません" "フィルターを解除して他のチャットを表示できます" "この選択中にチャットがありません" - "人々" + "ユーザー" "まだダイレクトメッセージは届いていません" "ルーム" "まだルームに参加していません" diff --git a/features/home/impl/src/main/res/values-pt-rBR/translations.xml b/features/home/impl/src/main/res/values-pt-rBR/translations.xml index 575cfbf6b0..1189cd8e70 100644 --- a/features/home/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/home/impl/src/main/res/values-pt-rBR/translations.xml @@ -6,7 +6,7 @@ "O seu ping de notificação foi atualizado—mais suave, mais rápido, e menos disruptivo." "Recarregamos seus sons" "Recupere sua identidade criptográfica e o histórico de mensagens com uma chave de recuperação caso você perda todos os dispositivos existentes." - "Configurar a recuperação" + "Receber chave de recuperação" "Configure a recuperação para proteger sua conta" "Confirme sua chave de recuperação para manter o acesso ao seu armazenamento de chaves e histórico de mensagens." "Digite sua chave de recuperação" diff --git a/features/home/impl/src/main/res/values-ru/translations.xml b/features/home/impl/src/main/res/values-ru/translations.xml index 233e8749b4..84a604e184 100644 --- a/features/home/impl/src/main/res/values-ru/translations.xml +++ b/features/home/impl/src/main/res/values-ru/translations.xml @@ -21,7 +21,7 @@ "Вы уверены, что хотите отказаться от личного общения с %1$s?" "Отклонить чат" "Нет приглашений" - "%1$s (%2$s) пригласил(а) вас" + "%1$s (%2$s) пригласил(а) Вас" "Это единоразовая процедура, спасибо, что подождали." "Настройка Вашего аккаунта." "Создать новую беседу или комнату" @@ -31,20 +31,20 @@ "Избранные" "Добавить чат в избранное можно в настройках чата. На данный момент вы можете убрать фильтры, чтобы увидеть другие ваши чаты." - "У вас пока нет избранных чатов" + "У Вас пока нет избранных чатов" "Приглашения" - "У вас нет приглашений." + "У Вас нет приглашений." "Низкий приоритет" - "У вас пока нет чатов с низким приоритетом." + "У Вас пока нет чатов с низким приоритетом." "Вы можете убрать фильтры, чтобы увидеть другие ваши чаты." - "У вас нет чатов, соответствующих фильтрам" + "У Вас нет чатов, соответствующих фильтрам" "Пользователи" - "У вас пока нет личных сообщений" + "У Вас пока нет личных сообщений" "Комнаты" "Вас пока нет ни в одной комнате" "Новые" "Поздравляем! -У вас нет непрочитанных сообщений!" +У Вас нет непрочитанных сообщений!" "Запрос на присоединение отправлен" "Чаты" "Пометить как прочитанное" diff --git a/features/home/impl/src/main/res/values-sk/translations.xml b/features/home/impl/src/main/res/values-sk/translations.xml index 12e6284468..aab1f6dc1d 100644 --- a/features/home/impl/src/main/res/values-sk/translations.xml +++ b/features/home/impl/src/main/res/values-sk/translations.xml @@ -6,7 +6,7 @@ "Vaše oznámenia boli aktualizované – sú prehľadnejšie, rýchlejšie a menej rušivé." "Obnovili sme vaše zvuky" "Vytvorte nový kľúč na obnovenie, ktorý môžete použiť na obnovenie vašej histórie šifrovaných správ v prípade straty prístupu k vašim zariadeniam." - "Nastaviť obnovenie" + "Získať kľúč na obnovenie" "Nastaviť obnovenie" "Potvrďte svoj kľúč na obnovenie, aby ste zachovali prístup k úložisku kľúčov a histórii správ." "Zadajte kľúč na obnovenie" diff --git a/features/home/impl/src/main/res/values-uk/translations.xml b/features/home/impl/src/main/res/values-uk/translations.xml index de30d201ca..38eeb47f56 100644 --- a/features/home/impl/src/main/res/values-uk/translations.xml +++ b/features/home/impl/src/main/res/values-uk/translations.xml @@ -5,15 +5,15 @@ "Не надходять сповіщення?" "Ваш сигнал сповіщень оновлено — він став чіткішим, швидшим і не таким надокучливим." "Ми оновили ваші звуки" - "Відновіть свою криптографічну ідентичність та історію повідомлень за допомогою ключа відновлення, якщо ви втратили всі наявні пристрої." - "Налаштувати відновлення" - "Налаштуйте відновлення для захисту свого облікового запису" + "Ваші бесіди автоматично резервуються з використанням наскрізного шифрування. Щоб відновити цю резервну копію та зберегти свою цифрову ідентичність у разі втрати доступу до всіх своїх пристроїв, вам знадобиться ключ відновлення." + "Отримати ключ відновлення" + "Створити резервну копію своїх бесід" "Підтвердіть свій ключ відновлення, щоб мати доступ до сховища ключів та історії повідомлень." "Введіть ключ відновлення" "Забули ключ відновлення?" "Ваше сховище ключів не синхронізовано" "Щоб ніколи не пропустити важливий виклик, змініть налаштування, щоб увімкнути повноекранні сповіщення, коли телефон заблоковано." - "Покращуйте досвід дзвінків" + "Покращуйте якість викликів" "Бесіди" "Простори" "Ви впевнені, що хочете відхилити запрошення приєднатися до %1$s?" @@ -51,6 +51,6 @@ "Позначити непрочитаним" "Цю кімнату оновлено" "Ваші простори" - "Схоже, ви використовуєте новий пристрій. Щоб отримати доступ до зашифрованих повідомлень, підтвердьте особу за допомогою іншого пристрою." + "Здається, ви використовуєте новий пристрій. Звірте його за допомогою іншого пристрою, щоб отримати доступ до своїх зашифрованих повідомлень." "Підтвердьте, що це ви" diff --git a/features/home/impl/src/main/res/values-zh/translations.xml b/features/home/impl/src/main/res/values-zh/translations.xml index 39900a6f0b..575adc6bb9 100644 --- a/features/home/impl/src/main/res/values-zh/translations.xml +++ b/features/home/impl/src/main/res/values-zh/translations.xml @@ -4,7 +4,7 @@ "禁用优化" "通知未送达?" "通知提示音已升级:更清晰、更快速、干扰更少。" - "我们已更新你的声音" + "我们已更新提示音" "你的聊天已被端到端加密自动备份。如果你无法访问所有设备,则需要使用恢复密钥并保留数字身份。" "获取恢复密钥" "备份聊天" diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt index 582de66414..8eee8e1ee2 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt @@ -8,7 +8,6 @@ package io.element.android.features.home.impl -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.bumble.appyx.core.modality.BuildContext import com.google.common.truth.Truth.assertThat import io.element.android.features.home.api.HomeEntryPoint @@ -18,12 +17,11 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultHomeEntryPointTest { +class DefaultHomeEntryPointTest : RobolectricTest() { @Test fun `test node builder`() = runTest { val entryPoint = DefaultHomeEntryPoint() diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersViewTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersViewTest.kt index de5760c1bd..6d68491ad1 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersViewTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersViewTest.kt @@ -13,18 +13,16 @@ package io.element.android.features.home.impl.filters import androidx.activity.ComponentActivity import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.home.impl.R import io.element.android.features.home.impl.filters.selection.FilterSelectionState import io.element.android.libraries.testtags.TestTags import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressTag +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class RoomListFiltersViewTest { +class RoomListFiltersViewTest : RobolectricTest() { @Test fun `clicking on filters generates expected Event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/FakeMarkRoomAsRead.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/FakeMarkRoomAsRead.kt new file mode 100644 index 0000000000..ace688e664 --- /dev/null +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/FakeMarkRoomAsRead.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.home.impl.roomlist + +import io.element.android.features.preferences.impl.tasks.MarkRoomAsRead +import io.element.android.libraries.matrix.api.core.RoomId + +class FakeMarkRoomAsRead( + private val invokeLambda: suspend (RoomId) -> Result = { Result.success(Unit) }, +) : MarkRoomAsRead { + val invokedRoomIds = mutableListOf() + + override suspend fun invoke(roomId: RoomId): Result { + invokedRoomIds.add(roomId) + return invokeLambda(roomId) + } +} diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenuTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenuTest.kt index 5fa2adf9d6..aa39962a2b 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenuTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenuTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.home.impl.R import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.ui.strings.CommonStrings @@ -22,12 +21,11 @@ import io.element.android.tests.testutils.EnsureCalledOnceWithParam import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class RoomListContextMenuTest { +class RoomListContextMenuTest : RobolectricTest() { @Test fun `clicking on Mark as read generates expected Events`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() @@ -36,7 +34,7 @@ class RoomListContextMenuTest { contextMenu = contextMenu, eventSink = eventsRecorder, ) - clickOn(R.string.screen_roomlist_mark_as_read) + clickOn(CommonStrings.action_mark_as_read) eventsRecorder.assertList( listOf( RoomListEvent.HideContextMenu, diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenuTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenuTest.kt index c8bba05e52..cb0226353b 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenuTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenuTest.kt @@ -12,19 +12,17 @@ package io.element.android.features.home.impl.roomlist import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.home.impl.model.aRoomListRoomSummary import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureCalledOnceWithParam import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class RoomListDeclineInviteMenuTest { +class RoomListDeclineInviteMenuTest : RobolectricTest() { @Test fun `clicking on decline emits the expected Events`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt index 5c2c3e294b..64dfc46ee2 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt @@ -30,12 +30,15 @@ import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInvit import io.element.android.features.invite.test.InMemorySeenInvitesStore import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomState +import io.element.android.features.preferences.impl.tasks.MarkRoomAsRead import io.element.android.features.rageshake.test.logs.FakeAnnouncementService import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter import io.element.android.libraries.eventformatter.test.FakeRoomLatestEventFormatter +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.fullscreenintent.api.aFullScreenIntentPermissionsState import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId @@ -61,9 +64,7 @@ import io.element.android.libraries.matrix.test.roomlist.FakeDynamicRoomList import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService -import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.preferences.api.store.SessionPreferencesStore -import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore import io.element.android.libraries.push.api.battery.aBatteryOptimizationState import io.element.android.libraries.push.api.notifications.NotificationCleaner @@ -228,7 +229,6 @@ class RoomListPresenterTest { isDm = false, isFavorite = false, hasNewContent = false, - displayClearRoomCacheAction = false, ) ) } @@ -245,35 +245,6 @@ class RoomListPresenterTest { isDm = false, isFavorite = true, hasNewContent = false, - displayClearRoomCacheAction = false, - ) - ) - } - } - } - - @Test - fun `present - show context menu with view source on`() = runTest { - val presenter = createRoomListPresenter( - appPreferencesStore = InMemoryAppPreferencesStore( - isDeveloperModeEnabled = true, - ) - ) - presenter.test { - val initialState = awaitItem() - val summary = createRoomListRoomSummary() - initialState.eventSink(RoomListEvent.ShowContextMenu(summary)) - awaitItem().also { state -> - assertThat(state.contextMenu) - .isEqualTo( - RoomListState.ContextMenu.Shown( - roomId = summary.roomId, - roomName = summary.name, - isDm = false, - isFavorite = false, - // true here. - hasNewContent = false, - displayClearRoomCacheAction = true, ) ) } @@ -301,7 +272,6 @@ class RoomListPresenterTest { isDm = false, isFavorite = false, hasNewContent = false, - displayClearRoomCacheAction = false, ) ) @@ -458,11 +428,17 @@ class RoomListPresenterTest { val notificationCleaner = FakeNotificationCleaner( clearMessagesForRoomLambda = clearMessagesForRoomLambda, ) + val markRoomAsRead = createTestMarkRoomAsRead( + client = matrixClient, + notificationCleaner = notificationCleaner, + sessionPreferencesStore = sessionPreferencesStore, + ) val presenter = createRoomListPresenter( client = matrixClient, sessionPreferencesStore = sessionPreferencesStore, analyticsService = analyticsService, notificationCleaner = notificationCleaner, + markRoomAsRead = markRoomAsRead, ) presenter.test { val initialState = awaitItem() @@ -654,6 +630,24 @@ class RoomListPresenterTest { } } + private fun createTestMarkRoomAsRead( + client: MatrixClient, + notificationCleaner: NotificationCleaner, + sessionPreferencesStore: SessionPreferencesStore, + ): MarkRoomAsRead = FakeMarkRoomAsRead { roomId -> + notificationCleaner.clearMessagesForRoom(client.sessionId, roomId) + val room = client.getRoom(roomId) ?: return@FakeMarkRoomAsRead Result.failure(IllegalStateException("Room not found")) + room.use { + it.setUnreadFlag(isUnread = false) + val receiptType = if (sessionPreferencesStore.isSendPublicReadReceiptsEnabled().first()) { + ReceiptType.READ + } else { + ReceiptType.READ_PRIVATE + } + it.markAsRead(receiptType) + } + } + private fun TestScope.createRoomListPresenter( client: MatrixClient = FakeMatrixClient(), leaveRoomState: LeaveRoomState = aLeaveRoomState(), @@ -666,9 +660,10 @@ class RoomListPresenterTest { spaceFiltersPresenter: Presenter = Presenter { aDisabledSpaceFiltersState() }, acceptDeclineInvitePresenter: Presenter = Presenter { anAcceptDeclineInviteState() }, notificationCleaner: NotificationCleaner = FakeNotificationCleaner(), - appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore(), seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore(), announcementService: AnnouncementService = FakeAnnouncementService(), + featureFlagService: FeatureFlagService = FakeFeatureFlagService(), + markRoomAsRead: MarkRoomAsRead? = null, ) = RoomListPresenter( client = client, leaveRoomPresenter = { leaveRoomState }, @@ -685,17 +680,20 @@ class RoomListPresenterTest { analyticsService = FakeAnalyticsService(), ), searchPresenter = searchPresenter, - sessionPreferencesStore = sessionPreferencesStore, filtersPresenter = filtersPresenter, spaceFiltersPresenter = spaceFiltersPresenter, analyticsService = analyticsService, acceptDeclineInvitePresenter = acceptDeclineInvitePresenter, fullScreenIntentPermissionsPresenter = { aFullScreenIntentPermissionsState() }, batteryOptimizationPresenter = { aBatteryOptimizationState() }, - notificationCleaner = notificationCleaner, - appPreferencesStore = appPreferencesStore, + markRoomAsRead = markRoomAsRead ?: createTestMarkRoomAsRead( + client = client, + notificationCleaner = notificationCleaner, + sessionPreferencesStore = sessionPreferencesStore, + ), seenInvitesStore = seenInvitesStore, announcementService = announcementService, coldStartWatcher = FakeAnalyticsColdStartWatcher(), + featureFlagService = featureFlagService, ) } diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt index b8d61994fa..773f428917 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.home.impl.HomeView import io.element.android.features.home.impl.R import io.element.android.features.home.impl.aHomeState @@ -34,13 +33,12 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class RoomListViewTest { +class RoomListViewTest : RobolectricTest() { @Config(qualifiers = "h1024dp") @Test fun `displaying the view automatically sends a couple of UpdateVisibleRangeEvents`() = runAndroidComposeUiTest { diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt index d612d765b6..9c9d13d066 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt @@ -15,14 +15,12 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.matrix.test.A_ROOM_ALIAS import io.element.android.tests.testutils.EventsRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class SpaceFiltersViewTest { +class SpaceFiltersViewTest : RobolectricTest() { @Test fun `clicking on a filter with alias shows display name and alias`() = runAndroidComposeUiTest { val filter = aSpaceServiceFilter( diff --git a/features/invite/impl/src/main/res/values-ru/translations.xml b/features/invite/impl/src/main/res/values-ru/translations.xml index 4e1104266e..8139beb885 100644 --- a/features/invite/impl/src/main/res/values-ru/translations.xml +++ b/features/invite/impl/src/main/res/values-ru/translations.xml @@ -10,7 +10,7 @@ "Вы уверены, что хотите отказаться от личного общения с %1$s?" "Отклонить чат" "Нет приглашений" - "%1$s (%2$s) пригласил(а) вас" + "%1$s (%2$s) пригласил(а) Вас" "Да, отклонить и заблокировать" "Вы действительно хотите отклонить приглашение в комнату? Также %1$s больше не сможет связаться с вами или приглашать в комнаты." "Отклонить приглашение и заблокировать" diff --git a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockViewTest.kt b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockViewTest.kt index e915696de4..55c31a09d2 100644 --- a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockViewTest.kt +++ b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/declineandblock/DeclineAndBlockViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.invite.impl.R import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -24,11 +23,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DeclineAndBlockViewTest { +class DeclineAndBlockViewTest : RobolectricTest() { @Test fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/invitepeople/impl/src/main/res/values-ko/translations.xml b/features/invitepeople/impl/src/main/res/values-ko/translations.xml index 19214c5a79..421f6d5e02 100644 --- a/features/invitepeople/impl/src/main/res/values-ko/translations.xml +++ b/features/invitepeople/impl/src/main/res/values-ko/translations.xml @@ -2,4 +2,8 @@ "이미 회원" "이미 초대됨" + "이 사용자들과의 대화 내역이 없습니다. 계속하려면 먼저 이 방으로의 초대를 확인해 주세요." + "이 사용자와의 대화 내역이 없습니다. 계속하려면 먼저 이 방으로의 초대를 확인해 주세요." + "이 방에 새 사용자를 초대할까요?" + "이 방에 새 사용자를 초대할까요?" diff --git a/features/invitepeople/impl/src/main/res/values-ru/translations.xml b/features/invitepeople/impl/src/main/res/values-ru/translations.xml index 1f2455ba72..651ec33626 100644 --- a/features/invitepeople/impl/src/main/res/values-ru/translations.xml +++ b/features/invitepeople/impl/src/main/res/values-ru/translations.xml @@ -3,7 +3,7 @@ "Уже участник" "Уже приглашен(а)" "У тебя пока нет чатов с этими контактами. Подтверди приглашение в эту комнату, прежде чем продолжить." - "У вас пока нет чатов с этим контактом. Подтверди приглашение в эту комнату, прежде чем продолжить." + "У Вас пока нет чатов с этим контактом. Подтвердите, что это действительно тот контакт, которого Вы хотите пригласить, прежде чем продолжить." "Пригласить новых участников в эту комнату?" "Пригласить нового участника в эту комнату?" diff --git a/features/invitepeople/impl/src/main/res/values-uk/translations.xml b/features/invitepeople/impl/src/main/res/values-uk/translations.xml index b7bb3c95d9..a1ebaf7854 100644 --- a/features/invitepeople/impl/src/main/res/values-uk/translations.xml +++ b/features/invitepeople/impl/src/main/res/values-uk/translations.xml @@ -2,8 +2,8 @@ "Уже учасник" "Уже запрошені" - "Наразі у вас немає чатів із цими контактами. Підтвердьте запрошення їх до цієї кімнати, перш ніж продовжувати." - "Наразі у вас немає чатів із цим контактом. Підтвердьте запрошення до цієї кімнати, перш ніж продовжувати." + "Наразі у вас немає бесід з цими контактами. Підтвердьте запрошення їх до цієї кімнати, перш ніж продовжувати." + "Наразі у вас немає бесід із цим контактом. Підтвердьте запрошення до цієї кімнати, перш ніж продовжувати." "Запросити нових контактів до цієї кімнати?" "Запросити нового контакта до цієї кімнати?" diff --git a/features/joinroom/impl/src/main/res/values-be/translations.xml b/features/joinroom/impl/src/main/res/values-be/translations.xml index f166186a1b..3f8e2bac2b 100644 --- a/features/joinroom/impl/src/main/res/values-be/translations.xml +++ b/features/joinroom/impl/src/main/res/values-be/translations.xml @@ -1,5 +1,6 @@ + "Так, адмяніць" "Адхіліць і заблакіраваць" "Далучыцца" "Націсніце, каб далучыцца" diff --git a/features/joinroom/impl/src/main/res/values-in/translations.xml b/features/joinroom/impl/src/main/res/values-in/translations.xml index b144b7f010..399cf66a94 100644 --- a/features/joinroom/impl/src/main/res/values-in/translations.xml +++ b/features/joinroom/impl/src/main/res/values-in/translations.xml @@ -15,6 +15,10 @@ "Ruangan ini hanya untuk undangan atau mungkin ada pembatasan akses pada tingkat space." "Lupa" "Anda memerlukan undangan untuk bergabung dalam ruangan ini" + + "Diundang oleh " + + "Gabung" "Anda mungkin perlu diundang atau menjadi anggota space untuk bergabung." "Ketuk untuk bergabung" diff --git a/features/joinroom/impl/src/main/res/values-ru/translations.xml b/features/joinroom/impl/src/main/res/values-ru/translations.xml index 9add5f4790..eda089b5c2 100644 --- a/features/joinroom/impl/src/main/res/values-ru/translations.xml +++ b/features/joinroom/impl/src/main/res/values-ru/translations.xml @@ -1,6 +1,6 @@ - "%1$s заблокировал(а) вас в комнате." + "%1$s заблокировал(а) Вас в комнате." "Вы были заблокированы в комнате" "Причина: %1$s." "Отменить запрос" @@ -27,7 +27,7 @@ "Не удалось показать предпросмотр комнаты" "%1$s еще не поддерживает пространства. Вы можете получить к ним доступ в веб-версии." "Пространства пока не поддерживаются" - "Нажмите кнопку ниже и администратор комнаты получит уведомление. После одобрения вы сможете присоединиться к обсуждению." + "Нажмите кнопку ниже и администратор комнаты получит уведомление. После одобрения Вы сможете присоединиться к беседе." "Вы должны быть участником этой комнаты, чтобы просмотреть историю сообщений." "Хотите присоединиться к этой комнате?" "Предпросмотр недоступен" diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt index e60d7da691..0c510cacdb 100644 --- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt +++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.invite.api.InviteData import io.element.android.features.invite.test.anInviteData import io.element.android.libraries.architecture.AsyncAction @@ -29,11 +28,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class JoinRoomViewTest { +class JoinRoomViewTest : RobolectricTest() { @Test fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/knockrequests/impl/src/main/res/values-be/translations.xml b/features/knockrequests/impl/src/main/res/values-be/translations.xml index e6f08bc320..5fcb54e9af 100644 --- a/features/knockrequests/impl/src/main/res/values-be/translations.xml +++ b/features/knockrequests/impl/src/main/res/values-be/translations.xml @@ -1,4 +1,6 @@ + "Адхіліць доступ" + "Паглядзець усе" "Прыняць" diff --git a/features/knockrequests/impl/src/main/res/values-ru/translations.xml b/features/knockrequests/impl/src/main/res/values-ru/translations.xml index 22d400cc50..ee3c31ebb3 100644 --- a/features/knockrequests/impl/src/main/res/values-ru/translations.xml +++ b/features/knockrequests/impl/src/main/res/values-ru/translations.xml @@ -4,10 +4,10 @@ "Вы действительно хотите принять все заявки на присоединение?" "Принять все запросы" "Принять все" - "Мы не смогли принять все запросы. Попробовать еще раз?" + "Мы не смогли принять все запросы. Попробовать ещё раз?" "Не удалось принять все запросы" "Принять все заявки на присоединение" - "Мы не смогли принять этот запрос. Хотите попробовать еще раз?" + "Мы не смогли принять этот запрос. Хотите попробовать ещё раз?" "Не удалось принять запрос" "Принятие заявки на присоединение" "Да, отклонить и запретить" @@ -18,7 +18,7 @@ "Вы уверены, что хотите отклонить запрос %1$s на присоединение к этой комнате?" "Отклонить доступ" "Отклонить и запретить" - "Мы не смогли отклонить этот запрос. Попробовать еще раз?" + "Мы не смогли отклонить этот запрос. Попробовать ещё раз?" "Не удалось отклонить запрос" "Отклонение заявки на присоединение" "Вы сможете увидеть запрос, когда кто-то попросит присоединиться к комнате." diff --git a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerViewTest.kt b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerViewTest.kt index fc1600d8c8..f55ccb0cef 100644 --- a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerViewTest.kt +++ b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.knockrequests.impl.R import io.element.android.features.knockrequests.impl.data.aKnockRequestPresentable import io.element.android.libraries.ui.strings.CommonStrings @@ -24,11 +23,10 @@ import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class KnockRequestsBannerViewTest { +class KnockRequestsBannerViewTest : RobolectricTest() { @Test fun `clicking on view on single request invoke the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListViewTest.kt b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListViewTest.kt index 14cac7a9b7..1fbcb67b21 100644 --- a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListViewTest.kt +++ b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/list/KnockRequestsListViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.knockrequests.impl.R import io.element.android.features.knockrequests.impl.data.aKnockRequestPresentable import io.element.android.libraries.architecture.AsyncAction @@ -25,12 +24,11 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.persistentListOf import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class KnockRequestsListViewTest { +class KnockRequestsListViewTest : RobolectricTest() { @Test fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/leaveroom/api/src/main/res/values-pl/translations.xml b/features/leaveroom/api/src/main/res/values-pl/translations.xml index 440b806311..773922623c 100644 --- a/features/leaveroom/api/src/main/res/values-pl/translations.xml +++ b/features/leaveroom/api/src/main/res/values-pl/translations.xml @@ -1,10 +1,10 @@ "Czy na pewno chcesz opuścić tę konwersację? Konwersacja nie jest publiczna i nie będziesz mógł dołączyć ponownie bez zaproszenia." - "Jesteś pewien, że chcesz opuścić ten pokój? Jesteś tu jedyną osobą. Jeśli wyjdziesz, nikt nie będzie mógł dołączyć, w tym Ty." + "Czy na pewno chcesz opuścić ten pokój? Jesteś tu jedyną osobą. Jeśli wyjdziesz, nikt nie będzie mógł dołączyć, w tym Ty." "Czy na pewno chcesz opuścić ten pokój? Ten pokój nie jest publiczny i nie będziesz mógł do niego wrócić bez zaproszenia." "Wybierz właścicieli" "Jesteś jedynym właścicielem tego pokoju. Musisz przenieść własność na kogoś innego, zanim go opuścisz." "Przenieś własność" - "Jesteś pewien, że chcesz wyjść z tego pokoju?" + "Czy na pewno chcesz wyjść z tego pokoju?" diff --git a/features/leaveroom/api/src/main/res/values-ru/translations.xml b/features/leaveroom/api/src/main/res/values-ru/translations.xml index 898dd684b8..4fc11fccf4 100644 --- a/features/leaveroom/api/src/main/res/values-ru/translations.xml +++ b/features/leaveroom/api/src/main/res/values-ru/translations.xml @@ -1,7 +1,7 @@ - "Вы уверены, что хотите покинуть беседу? Эта беседа не является общедоступной, и вы не сможете присоединиться к ней без приглашения." - "Вы уверены, что хотите покинуть эту комнату? Здесь есть только вы. Если вы покинете комнату, никто не сможет присоединиться к ней в будущем, включая вас." + "Вы уверены, что хотите покинуть беседу? Эта беседа не является общедоступной, и Вы не сможете снова присоединиться к ней без приглашения." + "Вы уверены, что хотите покинуть эту комнату? Здесь есть только Вы. Если Вы покинете комнату, никто не сможет присоединиться к ней в будущем, включая Вас." "Вы уверены, что хотите покинуть эту комнату? Эта комната не является общедоступной, и Вы не сможете присоединиться к ней без приглашения." "Назначить владельцев" "Вы единственный владелец этой комнаты. Перед тем, как её покинуть, необходимо передать владение кому-нибудь другому." diff --git a/features/linknewdevice/impl/build.gradle.kts b/features/linknewdevice/impl/build.gradle.kts index adbec91e6a..4659a2d2b8 100644 --- a/features/linknewdevice/impl/build.gradle.kts +++ b/features/linknewdevice/impl/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { // TODO Cleanup implementation(projects.appconfig) implementation(projects.features.enterprise.api) + implementation(projects.features.lockscreen.api) implementation(projects.features.rageshake.api) implementation(projects.libraries.core) implementation(projects.libraries.androidutils) @@ -53,6 +54,7 @@ dependencies { testCommonDependencies(libs, true) testImplementation(projects.features.linknewdevice.test) + testImplementation(projects.features.lockscreen.test) testImplementation(projects.features.enterprise.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.matrix.test) diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt index 61645ead9d..d686b22860 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt @@ -13,8 +13,10 @@ import androidx.activity.compose.LocalActivity import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.Modifier +import com.bumble.appyx.core.composable.PermanentChild import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack @@ -34,8 +36,10 @@ import io.element.android.features.linknewdevice.impl.screens.error.ErrorNode import io.element.android.features.linknewdevice.impl.screens.error.ErrorScreenType import io.element.android.features.linknewdevice.impl.screens.number.EnterNumberNode import io.element.android.features.linknewdevice.impl.screens.qrcode.ShowQrCodeNode +import io.element.android.features.linknewdevice.impl.screens.root.LinkDeviceType import io.element.android.features.linknewdevice.impl.screens.root.LinkNewDeviceRootNode import io.element.android.features.linknewdevice.impl.screens.scan.ScanQrCodeNode +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode @@ -67,11 +71,16 @@ class LinkNewDeviceFlowNode( private val linkNewMobileHandler: LinkNewMobileHandler, private val linkNewDesktopHandler: LinkNewDesktopHandler, private val sessionEnterpriseService: SessionEnterpriseService, + private val deviceUnlockEntryPoint: DeviceUnlockEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, savedStateMap = buildContext.savedStateMap, ), + permanentNavModel = PermanentNavModel( + navTargets = setOf(NavTarget.LockScreen), + savedStateMap = buildContext.savedStateMap, + ), buildContext = buildContext, plugins = plugins, ) { @@ -124,6 +133,9 @@ class LinkNewDeviceFlowNode( @Parcelize data object DesktopScanQrCode : NavTarget + @Parcelize + data object LockScreen : NavTarget + @Parcelize data class Error( val errorScreenType: ErrorScreenType, @@ -137,6 +149,9 @@ class LinkNewDeviceFlowNode( Timber.tag(tag.value).d("step: ${linkMobileStep::class.java.simpleName}") when (linkMobileStep) { LinkMobileStep.Uninitialized -> Unit + LinkMobileStep.CreatingQrCode -> { + // This step is handled in LinkNewDeviceRootPresenter + } LinkMobileStep.Done -> { callback.onDone() } @@ -224,13 +239,28 @@ class LinkNewDeviceFlowNode( callback.onDone() } - override fun linkDesktopDevice() { - linkNewDesktopHandler.reset() - backstack.push(NavTarget.DesktopNotice) + override fun onUnlockDevice(type: LinkDeviceType) { + val callback = object : DeviceUnlockEntryPoint.Callback { + override fun onCancel() = Unit + override fun onUnlock() = when (type) { + LinkDeviceType.Mobile -> { + linkNewMobileHandler.reset() + linkNewMobileHandler.createAndStartNewHandler() + } + LinkDeviceType.Desktop -> { + linkNewDesktopHandler.reset() + backstack.push(NavTarget.DesktopNotice) + } + } + } + deviceUnlockEntryPoint.requestUnlock(callback) } } createNode(buildContext, listOf(callback)) } + is NavTarget.LockScreen -> { + deviceUnlockEntryPoint.createNode(this, buildContext) + } NavTarget.DesktopNotice -> { val callback = object : DesktopNoticeNode.Callback { override fun navigateBack() { @@ -324,5 +354,6 @@ class LinkNewDeviceFlowNode( } } BackstackView() + PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LockScreen) } } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt index 18d67f577a..39c9c6fef3 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewMobileHandler.kt @@ -43,12 +43,15 @@ class LinkNewMobileHandler( val stepFlow: StateFlow get() = linkMobileStepFlow.asStateFlow() - fun createAndStartNewHandler() { + fun createAndStartNewHandler(forRotating: Boolean = false) { Timber.tag(loggerTag.value).d("createAndStartNewHandler()") currentJob?.cancel() handler = matrixClient.createLinkMobileHandler().getOrNull() handler?.let { h -> currentJob = sessionScope.launch { + if (!forRotating) { + linkMobileStepFlow.emit(LinkMobileStep.CreatingQrCode) + } h.linkMobileStep .onEach { linkMobileStepFlow.emit(it) @@ -68,7 +71,7 @@ class LinkNewMobileHandler( } fun rotateQrCode() { - createAndStartNewHandler() + createAndStartNewHandler(forRotating = true) } fun onTooManyRotation() { diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt index cc94951dbd..7b830626f6 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt @@ -73,10 +73,10 @@ fun ErrorView( @Composable private fun titleText(errorScreenType: ErrorScreenType, appName: String) = when (errorScreenType) { - ErrorScreenType.Cancelled -> stringResource(R.string.screen_qr_code_login_error_cancelled_title) + ErrorScreenType.Cancelled -> stringResource(R.string.screen_link_new_device_error_request_cancelled_title) ErrorScreenType.Declined -> stringResource(R.string.screen_qr_code_login_error_declined_title) - ErrorScreenType.Expired -> stringResource(R.string.screen_qr_code_login_error_expired_title) - ErrorScreenType.ProtocolNotSupported -> stringResource(R.string.screen_qr_code_login_error_linking_not_suported_title) + ErrorScreenType.Expired -> stringResource(R.string.screen_link_new_device_error_request_timeout_title) + ErrorScreenType.ProtocolNotSupported -> stringResource(R.string.screen_link_new_device_error_not_supported_title) ErrorScreenType.InsecureChannelDetected -> stringResource(id = R.string.screen_qr_code_login_connection_note_secure_state_title) ErrorScreenType.Mismatch2Digits -> stringResource(id = R.string.screen_link_new_device_wrong_number_title) ErrorScreenType.SlidingSyncNotAvailable -> stringResource(id = R.string.screen_qr_code_login_error_sliding_sync_not_supported_title, appName) @@ -86,10 +86,10 @@ private fun titleText(errorScreenType: ErrorScreenType, appName: String) = when @Composable private fun subtitleText(errorScreenType: ErrorScreenType, appName: String) = when (errorScreenType) { - ErrorScreenType.Cancelled -> stringResource(R.string.screen_qr_code_login_error_cancelled_subtitle) + ErrorScreenType.Cancelled -> stringResource(R.string.screen_link_new_device_error_request_cancelled_subtitle) ErrorScreenType.Declined -> stringResource(R.string.screen_qr_code_login_error_declined_subtitle) - ErrorScreenType.Expired -> stringResource(R.string.screen_qr_code_login_error_expired_subtitle) - ErrorScreenType.ProtocolNotSupported -> stringResource(R.string.screen_qr_code_login_error_linking_not_suported_subtitle, appName) + ErrorScreenType.Expired -> stringResource(R.string.screen_link_new_device_error_request_timeout_subtitle) + ErrorScreenType.ProtocolNotSupported -> stringResource(R.string.screen_link_new_device_error_not_supported_subtitle) ErrorScreenType.Mismatch2Digits -> stringResource(id = R.string.screen_link_new_device_wrong_number_subtitle) ErrorScreenType.InsecureChannelDetected -> stringResource(id = R.string.screen_qr_code_login_connection_note_secure_state_description) ErrorScreenType.SlidingSyncNotAvailable -> stringResource(id = R.string.screen_qr_code_login_error_sliding_sync_not_supported_subtitle, appName) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/UserCertificatesProvider.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkDeviceType.kt similarity index 60% rename from libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/UserCertificatesProvider.kt rename to features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkDeviceType.kt index 529dd4eb4e..6b26fe5e79 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/UserCertificatesProvider.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkDeviceType.kt @@ -5,8 +5,9 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.matrix.impl.certificates +package io.element.android.features.linknewdevice.impl.screens.root -interface UserCertificatesProvider { - fun provides(): List +enum class LinkDeviceType { + Mobile, + Desktop, } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt index 8ce6af90b0..97047fea9d 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootEvent.kt @@ -8,6 +8,5 @@ package io.element.android.features.linknewdevice.impl.screens.root sealed interface LinkNewDeviceRootEvent { - data object LinkMobileDevice : LinkNewDeviceRootEvent data object CloseDialog : LinkNewDeviceRootEvent } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt index f43ffa64df..dc74f1287f 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootNode.kt @@ -27,7 +27,7 @@ class LinkNewDeviceRootNode( ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun onDone() - fun linkDesktopDevice() + fun onUnlockDevice(type: LinkDeviceType) } private val callback: Callback = callback() @@ -39,7 +39,7 @@ class LinkNewDeviceRootNode( state = state, modifier = modifier, onBackClick = callback::onDone, - onLinkDesktopDeviceClick = callback::linkDesktopDevice, + onUnlockDevice = callback::onUnlockDevice, ) } } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt index a17ed88fd3..af3ede0c27 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenter.kt @@ -50,7 +50,13 @@ class LinkNewDeviceRootPresenter( LaunchedEffect(step) { when (val finalStep = step) { is LinkMobileStep.Uninitialized -> { - qrCodeData = AsyncData.Uninitialized + // Ignore this step when loading QrCode + if (!qrCodeData.isLoading()) { + qrCodeData = AsyncData.Uninitialized + } + } + is LinkMobileStep.CreatingQrCode -> { + qrCodeData = AsyncData.Loading() } is LinkMobileStep.QrReady -> { qrCodeData = AsyncData.Success(Unit) @@ -64,12 +70,6 @@ class LinkNewDeviceRootPresenter( fun handleEvent(event: LinkNewDeviceRootEvent) { when (event) { - LinkNewDeviceRootEvent.LinkMobileDevice -> coroutineScope.launch { - qrCodeData = AsyncData.Loading() - // Wait for the QrCode to be ready - linkNewMobileHandler.reset() - linkNewMobileHandler.createAndStartNewHandler() - } LinkNewDeviceRootEvent.CloseDialog -> coroutineScope.launch { linkNewMobileHandler.reset() } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt index d9249d3e89..5778abfb2c 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootView.kt @@ -41,7 +41,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun LinkNewDeviceRootView( state: LinkNewDeviceRootState, onBackClick: () -> Unit, - onLinkDesktopDeviceClick: () -> Unit, + onUnlockDevice: (type: LinkDeviceType) -> Unit, modifier: Modifier = Modifier, ) { val (title, subtitle, iconStyle) = if (state.isSupported.dataOrNull() == false) { @@ -57,6 +57,7 @@ fun LinkNewDeviceRootView( BigIcon.Style.Default(CompoundIcons.Devices()) ) } + FlowStepPage( onBackClick = onBackClick, title = title, @@ -83,40 +84,37 @@ fun LinkNewDeviceRootView( } is AsyncData.Success -> { if (state.isSupported.data) { - when (state.qrCodeData) { - AsyncData.Uninitialized, - is AsyncData.Failure -> { - Button( - onClick = { state.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) }, - text = stringResource(id = R.string.screen_link_new_device_root_mobile_device), - modifier = Modifier.fillMaxWidth(), - leadingIcon = IconSource.Vector(CompoundIcons.Mobile()), - ) - Button( - onClick = onLinkDesktopDeviceClick, - text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer), - modifier = Modifier.fillMaxWidth(), - leadingIcon = IconSource.Vector(CompoundIcons.Computer()), - ) - } - is AsyncData.Loading, - is AsyncData.Success -> { - Button( - onClick = { state.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) }, - text = stringResource(id = R.string.screen_link_new_device_root_loading_qr_code), - showProgress = true, - enabled = false, - modifier = Modifier.fillMaxWidth(), - ) - Button( - onClick = onLinkDesktopDeviceClick, - text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer), - modifier = Modifier.fillMaxWidth(), - enabled = false, - leadingIcon = IconSource.Vector(CompoundIcons.Computer()), - ) - } - } + val canClick = state.qrCodeData is AsyncData.Uninitialized + val isLoading = state.qrCodeData is AsyncData.Loading || state.qrCodeData is AsyncData.Success + Button( + onClick = { + if (canClick) { + onUnlockDevice(LinkDeviceType.Mobile) + } + }, + text = stringResource( + id = if (isLoading) { + R.string.screen_link_new_device_root_loading_qr_code + } else { + R.string.screen_link_new_device_root_mobile_device + } + ), + showProgress = isLoading, + enabled = !isLoading, + modifier = Modifier.fillMaxWidth(), + leadingIcon = IconSource.Vector(CompoundIcons.Mobile()), + ) + Button( + onClick = { + if (canClick) { + onUnlockDevice(LinkDeviceType.Desktop) + } + }, + text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer), + enabled = !isLoading, + modifier = Modifier.fillMaxWidth(), + leadingIcon = IconSource.Vector(CompoundIcons.Computer()), + ) } else { Button( onClick = onBackClick, @@ -147,6 +145,6 @@ internal fun LinkNewDeviceRootViewPreview( LinkNewDeviceRootView( state = state, onBackClick = { }, - onLinkDesktopDeviceClick = { }, + onUnlockDevice = { }, ) } diff --git a/features/linknewdevice/impl/src/main/res/values-ru/translations.xml b/features/linknewdevice/impl/src/main/res/values-ru/translations.xml index 6a8b645c4f..1382829c04 100644 --- a/features/linknewdevice/impl/src/main/res/values-ru/translations.xml +++ b/features/linknewdevice/impl/src/main/res/values-ru/translations.xml @@ -15,7 +15,7 @@ "QR-код не поддерживается" "Вход на другом устройстве был отменен." "Запрос на вход отменен" - "Срок действия входа истек. Пожалуйста, попробуйте еще раз." + "Срок действия входа истек. Пожалуйста, попробуйте ещё раз." "Вход в систему не был выполнен вовремя" "Откройте %1$s на другом устройстве" "Выберите %1$s" @@ -26,7 +26,7 @@ "Загрузка QR-кода…" "Смартфон" "Какое устройство вы хотите привязать?" - "Пожалуйста, попробуйте еще раз и убедитесь, что вы правильно ввели 2-значный код. Если цифры по-прежнему не совпадают, обратитесь к администратору сервера." + "Пожалуйста, попробуйте ещё раз и убедитесь, что Вы правильно ввели 2-значный код. Если цифры по-прежнему не совпадают, обратитесь к администратору сервера." "Цифры не совпадают" "Не удалось установить безопасное соединение с новым устройством. Не беспокойтесь, существующие устройства в безопасности." "Что теперь?" @@ -40,9 +40,9 @@ "Запрос на вход отменен" "Вход в систему был отклонен на другом устройстве." "Вход отклонен" - "На этом все." + "На этом всё." "Вход уже выполнен на другом устройстве" - "Срок действия входа истек. Пожалуйста, попробуйте еще раз." + "Срок действия входа истек. Пожалуйста, попробуйте ещё раз." "Вход в систему не был выполнен вовремя" "Другое устройство не поддерживает вход в %s с помощью QR-кода. @@ -55,6 +55,6 @@ "Неверный QR-код" "Чтобы продолжить, вам необходимо разрешить %1$s использовать камеру вашего устройства." "Разрешите доступ к камере для сканирования QR-кода" - "Произошла непредвиденная ошибка. Пожалуйста, попробуйте еще раз." + "Произошла непредвиденная ошибка. Пожалуйста, попробуйте ещё раз." "Ожидание другого устройства" diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt index 1b2af8f4c3..a198bc27d9 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/DefaultLinkNewDeviceEntryPointTest.kt @@ -13,6 +13,7 @@ import com.bumble.appyx.testing.junit4.util.MainDispatcherRule import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.features.linknewdevice.api.LinkNewDeviceEntryPoint +import io.element.android.features.lockscreen.test.FakeDeviceUnlockEntryPoint import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode @@ -39,6 +40,7 @@ class DefaultLinkNewDeviceEntryPointTest { linkNewMobileHandler = LinkNewMobileHandler(client), linkNewDesktopHandler = LinkNewDesktopHandler(client), sessionEnterpriseService = FakeSessionEnterpriseService(), + deviceUnlockEntryPoint = FakeDeviceUnlockEntryPoint(), ) } val callback: LinkNewDeviceEntryPoint.Callback = object : LinkNewDeviceEntryPoint.Callback { diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/desktop/DesktopNoticeViewTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/desktop/DesktopNoticeViewTest.kt index 7609acf809..cdb1cb6860 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/desktop/DesktopNoticeViewTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/desktop/DesktopNoticeViewTest.kt @@ -13,7 +13,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.linknewdevice.impl.R import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder @@ -21,11 +20,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DesktopNoticeViewTest { +class DesktopNoticeViewTest : RobolectricTest() { @Test fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorViewTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorViewTest.kt index b63d7471ac..74619c1b71 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorViewTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorViewTest.kt @@ -13,17 +13,15 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ErrorViewTest { +class ErrorViewTest : RobolectricTest() { @Test fun `on back pressed - calls the onCancel callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt index fe2e11e95c..b3602c81dc 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberPresenterTest.kt @@ -88,6 +88,7 @@ class EnterNumberPresenterTest { navigator = navigator, linkNewMobileHandler = linkNewMobileHandler, ).test { + skipItems(1) val initialState = awaitItem() linkMobileHandler.emitStep( LinkMobileStep.QrScanned(checkCodeSender) @@ -96,7 +97,7 @@ class EnterNumberPresenterTest { initialState.eventSink(EnterNumberEvent.UpdateNumber("88")) skipItems(1) initialState.eventSink(EnterNumberEvent.Continue) - skipItems(1) + skipItems(2) val finalState = awaitItem() assertThat(finalState.sendingCode.isLoading()).isTrue() advanceUntilIdle() @@ -130,6 +131,7 @@ class EnterNumberPresenterTest { LinkMobileStep.QrScanned(checkCodeSender) ) runCurrent() + skipItems(1) initialState.eventSink(EnterNumberEvent.UpdateNumber("88")) skipItems(1) initialState.eventSink(EnterNumberEvent.Continue) @@ -163,6 +165,7 @@ class EnterNumberPresenterTest { createPresenter( linkNewMobileHandler = linkNewMobileHandler, ).test { + skipItems(1) val initialState = awaitItem() linkMobileHandler.emitStep( LinkMobileStep.QrScanned(checkCodeSender) @@ -171,7 +174,7 @@ class EnterNumberPresenterTest { initialState.eventSink(EnterNumberEvent.UpdateNumber("88")) skipItems(1) initialState.eventSink(EnterNumberEvent.Continue) - skipItems(1) + skipItems(2) val loadingState = awaitItem() assertThat(loadingState.sendingCode.isLoading()).isTrue() expectNoEvents() diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberViewTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberViewTest.kt index 25dc9efa8a..0d6da84241 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberViewTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/number/EnterNumberViewTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder @@ -23,11 +22,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class EnterNumberViewTest { +class EnterNumberViewTest : RobolectricTest() { @Test fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/qrcode/ShowQrCodeViewTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/qrcode/ShowQrCodeViewTest.kt index 7927eeed77..6715959e0e 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/qrcode/ShowQrCodeViewTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/qrcode/ShowQrCodeViewTest.kt @@ -13,15 +13,13 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ShowQrCodeViewTest { +class ShowQrCodeViewTest : RobolectricTest() { @Test fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt index 88a68786f3..d2216c2737 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootPresenterTest.kt @@ -75,15 +75,48 @@ class LinkNewDeviceRootPresenterTest { sessionCoroutineScope = backgroundScope, createLinkMobileHandlerResult = { Result.success(linkMobileHandler) } ) + val linkNewMobileHandler = LinkNewMobileHandler(matrixClient) createPresenter( matrixClient = matrixClient, + linkNewMobileHandler = linkNewMobileHandler, ).test { skipItems(1) val initialState = awaitItem() assertThat(initialState.isSupported.dataOrNull()).isTrue() - initialState.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) + linkNewMobileHandler.createAndStartNewHandler() + skipItems(1) val loadingState = awaitItem() assertThat(loadingState.qrCodeData.isLoading()).isTrue() + skipItems(1) + } + } + + @Test + fun `present - close dialog resets qrCodeData`() = runTest { + val fakeLinkMobileHandler = FakeLinkMobileHandler(startResult = {}) + val matrixClient = FakeMatrixClient( + canLinkNewDeviceResult = { Result.success(true) }, + sessionCoroutineScope = backgroundScope, + createLinkMobileHandlerResult = { Result.success(fakeLinkMobileHandler) } + ) + val linkNewMobileHandler = LinkNewMobileHandler(matrixClient) + createPresenter( + matrixClient = matrixClient, + linkNewMobileHandler = linkNewMobileHandler, + ).test { + skipItems(1) + linkNewMobileHandler.onTooManyRotation() + var errorState = awaitItem() + while (!errorState.qrCodeData.isFailure()) { + errorState = awaitItem() + } + assertThat(errorState.qrCodeData.isFailure()).isTrue() + errorState.eventSink(LinkNewDeviceRootEvent.CloseDialog) + var resetState = awaitItem() + while (!resetState.qrCodeData.isUninitialized()) { + resetState = awaitItem() + } + assertThat(resetState.qrCodeData.isUninitialized()).isTrue() } } diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt index bceb8753b2..fd75a4d560 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/root/LinkNewDeviceRootViewTest.kt @@ -13,20 +13,20 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.linknewdevice.impl.R import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled +import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce +import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class LinkNewDeviceRootViewTest { +class LinkNewDeviceRootViewTest : RobolectricTest() { @Test fun `on back pressed - calls the onRetry callback`() = runAndroidComposeUiTest { val eventRecorder = EventsRecorder(expectEvents = false) @@ -44,29 +44,31 @@ class LinkNewDeviceRootViewTest { @Test fun `link desktop button clicked - calls the expected callback`() = runAndroidComposeUiTest { val eventRecorder = EventsRecorder(expectEvents = false) - ensureCalledOnce { callback -> + ensureCalledOnceWithParam(LinkDeviceType.Desktop) { callback -> setLinkNewDeviceRootView( state = aLinkNewDeviceRootState( isSupported = AsyncData.Success(true), eventSink = eventRecorder, ), - onLinkDesktopDeviceClick = callback, + onUnlockDevice = callback, ) clickOn(R.string.screen_link_new_device_root_desktop_computer) } } @Test - fun `link mobile button clicked - emits the expected event`() = runAndroidComposeUiTest { - val eventRecorder = EventsRecorder() - setLinkNewDeviceRootView( - state = aLinkNewDeviceRootState( - isSupported = AsyncData.Success(true), - eventSink = eventRecorder, + fun `link mobile button clicked - calls the expected callback`() = runAndroidComposeUiTest { + val eventRecorder = EventsRecorder(expectEvents = false) + ensureCalledOnceWithParam(LinkDeviceType.Mobile) { callback -> + setLinkNewDeviceRootView( + state = aLinkNewDeviceRootState( + isSupported = AsyncData.Success(true), + eventSink = eventRecorder, + ), + onUnlockDevice = callback, ) - ) - clickOn(R.string.screen_link_new_device_root_mobile_device) - eventRecorder.assertSingle(LinkNewDeviceRootEvent.LinkMobileDevice) + clickOn(R.string.screen_link_new_device_root_mobile_device) + } } @Test @@ -87,13 +89,13 @@ class LinkNewDeviceRootViewTest { private fun AndroidComposeUiTest.setLinkNewDeviceRootView( state: LinkNewDeviceRootState = aLinkNewDeviceRootState(), onBackClick: () -> Unit = EnsureNeverCalled(), - onLinkDesktopDeviceClick: () -> Unit = EnsureNeverCalled(), + onUnlockDevice: (type: LinkDeviceType) -> Unit = EnsureNeverCalledWithParam(), ) { setContent { LinkNewDeviceRootView( state = state, onBackClick = onBackClick, - onLinkDesktopDeviceClick = onLinkDesktopDeviceClick, + onUnlockDevice = onUnlockDevice, ) } } diff --git a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/scan/ScanQrCodeViewTest.kt b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/scan/ScanQrCodeViewTest.kt index 1932718fef..a8bc2b27a9 100644 --- a/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/scan/ScanQrCodeViewTest.kt +++ b/features/linknewdevice/impl/src/test/kotlin/io/element/android/features/linknewdevice/impl/screens/scan/ScanQrCodeViewTest.kt @@ -9,11 +9,13 @@ package io.element.android.features.linknewdevice.impl.screens.scan +import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE import androidx.activity.ComponentActivity +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.ui.strings.CommonStrings @@ -22,12 +24,13 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith +import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class ScanQrCodeViewTest { +class ScanQrCodeViewTest : RobolectricTest() { @Test + @Config(sdk = [UPSIDE_DOWN_CAKE]) fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest { val eventRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { callback -> @@ -42,6 +45,7 @@ class ScanQrCodeViewTest { } @Test + @Config(sdk = [UPSIDE_DOWN_CAKE]) fun `try again button clicked - emits the expected event`() = runAndroidComposeUiTest { val eventRecorder = EventsRecorder() setView( @@ -59,10 +63,12 @@ class ScanQrCodeViewTest { onBackClick: () -> Unit = EnsureNeverCalled(), ) { setContent { - ScanQrCodeView( - state = state, - onBackClick = onBackClick, - ) + CompositionLocalProvider(LocalInspectionMode provides true) { + ScanQrCodeView( + state = state, + onBackClick = onBackClick, + ) + } } } } diff --git a/features/location/api/src/main/kotlin/io/element/android/features/location/api/RenderingMapsNotSupportedDialog.kt b/features/location/api/src/main/kotlin/io/element/android/features/location/api/RenderingMapsNotSupportedDialog.kt new file mode 100644 index 0000000000..a4d65763ab --- /dev/null +++ b/features/location/api/src/main/kotlin/io/element/android/features/location/api/RenderingMapsNotSupportedDialog.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.location.api + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun RenderingMapsNotSupportedDialog(onSubmit: () -> Unit) { + ErrorDialog( + title = stringResource(CommonStrings.vulkan_not_supported_dialog_title_android), + content = stringResource(CommonStrings.vulkan_not_supported_dialog_content_android), + onSubmit = onSubmit, + ) +} + +@PreviewsDayNight +@Composable +internal fun RenderingMapsNotSupportedDialogPreview() = ElementPreview { + RenderingMapsNotSupportedDialog(onSubmit = {}) +} diff --git a/features/location/api/src/main/kotlin/io/element/android/features/location/api/StaticMapView.kt b/features/location/api/src/main/kotlin/io/element/android/features/location/api/StaticMapView.kt index a61cbe1c24..c16b1ae560 100644 --- a/features/location/api/src/main/kotlin/io/element/android/features/location/api/StaticMapView.kt +++ b/features/location/api/src/main/kotlin/io/element/android/features/location/api/StaticMapView.kt @@ -8,6 +8,7 @@ package io.element.android.features.location.api +import android.graphics.Bitmap import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints @@ -24,13 +25,17 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.core.graphics.createBitmap import coil3.Extras +import coil3.asImage import coil3.compose.AsyncImagePainter import coil3.compose.rememberAsyncImagePainter import coil3.request.ImageRequest +import coil3.request.SuccessResult import io.element.android.compound.theme.ElementTheme import io.element.android.features.location.api.internal.StaticMapPlaceholder import io.element.android.features.location.api.internal.StaticMapUrlBuilder @@ -39,6 +44,7 @@ import io.element.android.libraries.designsystem.components.LocationPin import io.element.android.libraries.designsystem.components.PinVariant import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.utils.CommonDrawables /** * Shows a static map image downloaded via a third party service's static maps API. @@ -128,32 +134,46 @@ private fun BoxWithConstraintsScope.LoadableMapContent( var retryHash by remember { mutableIntStateOf(0) } val builder = remember { StaticMapUrlBuilder() } - val painter = rememberAsyncImagePainter( - model = if (constraints.isZero) { - // Avoid building a URL if any of the size constraints is zero - null - } else { - ImageRequest.Builder(context) - .data( - builder.build( - lat = location.lat, - lon = location.lon, - zoom = zoom, - darkMode = darkMode, - width = constraints.maxWidth, - height = constraints.maxHeight, - density = LocalDensity.current.density, + val (painter, state, contentScale) = if (LocalInspectionMode.current) { + val painter = painterResource(CommonDrawables.sample_map) + val state = AsyncImagePainter.State.Success( + painter = painter, + result = SuccessResult( + image = createBitmap(1, 1, Bitmap.Config.ALPHA_8).asImage(), + request = ImageRequest.Builder(context).build() + ) + ) + Triple(painter, state, ContentScale.Crop) + } else { + val painter = rememberAsyncImagePainter( + model = if (constraints.isZero) { + // Avoid building a URL if any of the size constraints is zero + null + } else { + ImageRequest.Builder(context) + .data( + builder.build( + lat = location.lat, + lon = location.lon, + zoom = zoom, + darkMode = darkMode, + width = constraints.maxWidth, + height = constraints.maxHeight, + density = LocalDensity.current.density, + ) ) - ) - .size(width = constraints.maxWidth, height = constraints.maxHeight) - .apply { - extras.set(Extras.Key("retry_hash"), retryHash).build() - } - .build() - } - ) + .size(width = constraints.maxWidth, height = constraints.maxHeight) + .apply { + extras.set(Extras.Key("retry_hash"), retryHash).build() + } + .build() + } + ) + + val state by painter.state.collectAsState() + Triple(painter, state, ContentScale.Fit) + } - val state by painter.state.collectAsState() when (state) { is AsyncImagePainter.State.Success -> { Image( @@ -162,7 +182,7 @@ private fun BoxWithConstraintsScope.LoadableMapContent( modifier = Modifier.size(width = maxWidth, height = maxHeight), // The returned image can be smaller than the requested size due to the static maps API having // a max width and height of 2048 px. We apply ContentScale.Fit to handle this. - contentScale = ContentScale.Fit, + contentScale = contentScale, ) LocationPin(variant = pinVariant, modifier = Modifier.centerBottomEdge(this)) } diff --git a/features/location/impl/src/main/AndroidManifest.xml b/features/location/impl/src/main/AndroidManifest.xml index e92ca68077..e56a13e644 100644 --- a/features/location/impl/src/main/AndroidManifest.xml +++ b/features/location/impl/src/main/AndroidManifest.xml @@ -5,13 +5,21 @@ ~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. ~ Please see LICENSE files in the repository root for full details. --> - + + + + LocationConstraintsCheck.PermissionRationale + !permissionsState.permissionsAlreadyRequested -> LocationConstraintsCheck.PermissionShouldBeRequested else -> LocationConstraintsCheck.PermissionDenied } } @@ -41,6 +43,7 @@ fun checkLocationConstraints( fun LocationConstraintsCheck.toDialogState(): LocationConstraintsDialogState { return when (this) { LocationConstraintsCheck.Success -> LocationConstraintsDialogState.None + LocationConstraintsCheck.PermissionShouldBeRequested -> LocationConstraintsDialogState.None LocationConstraintsCheck.PermissionRationale -> LocationConstraintsDialogState.PermissionRationale LocationConstraintsCheck.PermissionDenied -> LocationConstraintsDialogState.PermissionDenied LocationConstraintsCheck.LocationServiceDisabled -> LocationConstraintsDialogState.LocationServiceDisabled diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/DefaultPermissionsPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/DefaultPermissionsPresenter.kt index 1aa2e1269d..5aa7ae6f63 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/DefaultPermissionsPresenter.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/DefaultPermissionsPresenter.kt @@ -9,6 +9,10 @@ package io.element.android.features.location.impl.common.permissions import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberMultiplePermissionsState @@ -32,11 +36,16 @@ class DefaultPermissionsPresenter( @OptIn(ExperimentalPermissionsApi::class) @Composable override fun present(): PermissionsState { - val multiplePermissionsState = rememberMultiplePermissionsState(permissions = permissions) + var permissionsRequested by remember { mutableStateOf(false) } + val multiplePermissionsState = rememberMultiplePermissionsState(permissions = permissions) { + permissionsRequested = true + } fun handleEvent(event: PermissionsEvents) { when (event) { - PermissionsEvents.RequestPermissions -> multiplePermissionsState.launchMultiplePermissionRequest() + PermissionsEvents.RequestPermissions -> { + multiplePermissionsState.launchMultiplePermissionRequest() + } } } @@ -47,6 +56,7 @@ class DefaultPermissionsPresenter( else -> PermissionsState.Permissions.NoneGranted }, shouldShowRationale = multiplePermissionsState.shouldShowRationale, + permissionsAlreadyRequested = permissionsRequested, eventSink = ::handleEvent, ) } diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt index 91191280d0..25ceb3ba29 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt @@ -11,6 +11,7 @@ package io.element.android.features.location.impl.common.permissions data class PermissionsState( val permissions: Permissions, val shouldShowRationale: Boolean, + val permissionsAlreadyRequested: Boolean, val eventSink: (PermissionsEvents) -> Unit, ) { sealed interface Permissions { diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/MapBottomSheetScaffold.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/MapBottomSheetScaffold.kt index 5f09bcedb2..0eff1b6028 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/MapBottomSheetScaffold.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/MapBottomSheetScaffold.kt @@ -30,7 +30,7 @@ import androidx.compose.material3.SheetValue import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.rememberBottomSheetScaffoldState -import androidx.compose.material3.rememberStandardBottomSheetState +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -86,7 +86,9 @@ fun MapBottomSheetScaffold( customMapStyleUrl: AsyncData, modifier: Modifier = Modifier, scaffoldState: BottomSheetScaffoldState = rememberBottomSheetScaffoldState( - bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.PartiallyExpanded) + bottomSheetState = rememberBottomSheetState( + initialValue = SheetValue.PartiallyExpanded, + ) ), cameraState: CameraState = rememberCameraState(), mapOptions: MapOptions = MapDefaults.options, diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/UserLocationPuck.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/UserLocationPuck.kt index 7bad736911..074404a4cc 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/UserLocationPuck.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/UserLocationPuck.kt @@ -7,77 +7,35 @@ package io.element.android.features.location.impl.common.ui -import android.annotation.SuppressLint import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme -import io.element.android.features.location.impl.common.MapDefaults import org.maplibre.compose.camera.CameraState -import org.maplibre.compose.location.DesiredAccuracy +import org.maplibre.compose.location.Location import org.maplibre.compose.location.LocationPuck import org.maplibre.compose.location.LocationPuckColors import org.maplibre.compose.location.LocationPuckSizes -import org.maplibre.compose.location.UserLocationState -import org.maplibre.compose.location.rememberAndroidLocationProvider -import org.maplibre.compose.location.rememberNullLocationProvider -import org.maplibre.compose.location.rememberUserLocationState -import org.maplibre.spatialk.units.extensions.meters -import kotlin.time.Duration.Companion.seconds @Composable fun UserLocationPuck( cameraState: CameraState, - locationState: UserLocationState, - trackUserLocation: Boolean, + location: Location?, ) { - SimpleLocationTrackingEffect( - locationState = locationState, - enabled = trackUserLocation, - ) { currentLocation -> - val target = currentLocation?.position?.value ?: cameraState.position.target - val newPosition = cameraState.position.copy( - target = target, - // Force pointing to NORTH - bearing = 0.0, - zoom = cameraState.position.zoom.coerceAtLeast(MapDefaults.DEFAULT_ZOOM) + LocationPuck( + idPrefix = "user-location", + location = location, + cameraState = cameraState, + accuracyThreshold = Float.POSITIVE_INFINITY, + showBearingAccuracy = false, + showBearing = false, + sizes = LocationPuckSizes( + dotRadius = 8.dp, + dotStrokeWidth = 2.dp, + ), + colors = LocationPuckColors( + dotFillColorCurrentLocation = ElementTheme.colors.iconAccentPrimary, + dotFillColorOldLocation = ElementTheme.colors.iconAccentTertiary, + dotStrokeColor = ElementTheme.colors.bgCanvasDefault, ) - cameraState.animateTo(newPosition) - } - val location = locationState.location - if (location != null) { - LocationPuck( - idPrefix = "user-location", - location = location, - cameraState = cameraState, - accuracyThreshold = Float.POSITIVE_INFINITY, - showBearingAccuracy = false, - showBearing = false, - sizes = LocationPuckSizes( - dotRadius = 8.dp, - dotStrokeWidth = 2.dp, - ), - colors = LocationPuckColors( - dotFillColorCurrentLocation = ElementTheme.colors.iconAccentPrimary, - dotFillColorOldLocation = ElementTheme.colors.iconAccentTertiary, - dotStrokeColor = ElementTheme.colors.bgCanvasDefault, - ) - ) - } -} - -@SuppressLint("MissingPermission") -@Composable -fun rememberUserLocationState(hasLocationPermission: Boolean): UserLocationState { - val isPreview = LocalInspectionMode.current - val locationProvider = if (isPreview || !hasLocationPermission) { - rememberNullLocationProvider() - } else { - rememberAndroidLocationProvider( - updateInterval = 5.seconds, - desiredAccuracy = DesiredAccuracy.High, - minDistance = 5.meters, - ) - } - return rememberUserLocationState(locationProvider) + ) } diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/DefaultUserLocationStateFactory.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/DefaultUserLocationStateFactory.kt new file mode 100644 index 0000000000..01a2b92d4a --- /dev/null +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/DefaultUserLocationStateFactory.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.location.impl.common.userlocation + +import android.annotation.SuppressLint +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.di.RoomScope +import org.maplibre.compose.location.DesiredAccuracy +import org.maplibre.compose.location.rememberNullLocationProvider +import org.maplibre.spatialk.units.extensions.meters +import kotlin.time.Duration.Companion.seconds + +@ContributesBinding(RoomScope::class) +class DefaultUserLocationStateFactory : UserLocationState.Factory { + @Composable + override fun create(hasLocationPermission: Boolean): UserLocationState { + val locationProvider = if (!hasLocationPermission) { + rememberNullLocationProvider() + } else { + @SuppressLint("MissingPermission") + rememberPlatformLocationProvider( + updateInterval = 5.seconds, + desiredAccuracy = DesiredAccuracy.High, + minDistance = 5.meters, + ) + } + val location by locationProvider.location.collectAsState() + return UserLocationState(location) + } +} diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/Location.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/Location.kt new file mode 100644 index 0000000000..9777e14af5 --- /dev/null +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/Location.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.location.impl.common.userlocation + +import io.element.android.features.location.api.Location +import org.maplibre.compose.location.PositionWithAccuracy +import org.maplibre.spatialk.geojson.Position +import org.maplibre.spatialk.units.extensions.meters +import kotlin.time.TimeSource +import org.maplibre.compose.location.Location as MapLibreLocation + +fun Location.asMapLibreLocation(): MapLibreLocation { + return MapLibreLocation( + position = PositionWithAccuracy( + value = Position(latitude = lat, longitude = lon), + accuracy = accuracy?.toDouble()?.meters + ), + // Not relevant as not used + timestamp = TimeSource.Monotonic.markNow(), + ) +} diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/PlatformLocationProvider.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/PlatformLocationProvider.kt new file mode 100644 index 0000000000..54e6d19cf6 --- /dev/null +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/PlatformLocationProvider.kt @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.location.impl.common.userlocation + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Context +import android.content.pm.PackageManager +import android.location.LocationManager +import android.os.Handler +import android.os.HandlerThread +import androidx.annotation.RequiresPermission +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.platform.LocalContext +import androidx.core.location.LocationListenerCompat +import androidx.core.location.LocationManagerCompat +import androidx.core.location.LocationRequestCompat +import androidx.core.os.ExecutorCompat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.stateIn +import org.maplibre.compose.location.DesiredAccuracy +import org.maplibre.compose.location.Location +import org.maplibre.compose.location.LocationProvider +import org.maplibre.compose.location.PermissionException +import org.maplibre.compose.location.asMapLibreLocation +import org.maplibre.spatialk.units.Length +import org.maplibre.spatialk.units.extensions.inMeters +import kotlin.time.Duration + +@SuppressLint("InlinedApi") +class PlatformLocationProvider( + context: Context, + private val updateInterval: Duration, + private val minDistance: Length, + private val desiredAccuracy: DesiredAccuracy = DesiredAccuracy.High, + coroutineScope: CoroutineScope, + sharingStarted: SharingStarted = SharingStarted.WhileSubscribed(stopTimeoutMillis = 1000), +) : LocationProvider { + override val location: StateFlow + + init { + if (!handlerThread.isAlive) handlerThread.start() + if ( + context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && + context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED + ) { + throw PermissionException() + } + val locationManager = context.getSystemService(LocationManager::class.java) + val provider = PROVIDERS_BY_PRIORITY.firstOrNull { LocationManagerCompat.hasProvider(locationManager, it) } + val locationFlow = if (provider != null) { + createProviderFlow(locationManager, provider) + } else { + emptyFlow() + } + location = locationFlow.stateIn(coroutineScope, sharingStarted, null) + } + + @RequiresPermission( + anyOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION] + ) + private fun createProviderFlow(locationManager: LocationManager, provider: String) = callbackFlow { + send(locationManager.getLastKnownLocation(provider)?.asMapLibreLocation()) + val listener = LocationListenerCompat { trySend(it.asMapLibreLocation()) } + val request = LocationRequestCompat.Builder(updateInterval.inWholeMilliseconds) + .setQuality(desiredAccuracy.toLocationRequestQuality()) + .setMinUpdateDistanceMeters(minDistance.inMeters.toFloat()) + .build() + LocationManagerCompat.requestLocationUpdates( + locationManager, + provider, + request, + ExecutorCompat.create(Handler(handlerThread.looper)), + listener, + ) + awaitClose { LocationManagerCompat.removeUpdates(locationManager, listener) } + } + + private companion object { + private val PROVIDERS_BY_PRIORITY = listOf( + LocationManager.FUSED_PROVIDER, + LocationManager.GPS_PROVIDER, + LocationManager.NETWORK_PROVIDER, + ) + private val handlerThread by lazy { HandlerThread("PlatformLocationProvider") } + } +} + +private fun DesiredAccuracy.toLocationRequestQuality(): Int = when (this) { + DesiredAccuracy.Highest, DesiredAccuracy.High -> LocationRequestCompat.QUALITY_HIGH_ACCURACY + DesiredAccuracy.Balanced -> LocationRequestCompat.QUALITY_BALANCED_POWER_ACCURACY + DesiredAccuracy.Low, DesiredAccuracy.Lowest -> LocationRequestCompat.QUALITY_LOW_POWER +} + +@Composable +@RequiresPermission( + anyOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION] +) +fun rememberPlatformLocationProvider( + updateInterval: Duration, + minDistance: Length, + desiredAccuracy: DesiredAccuracy = DesiredAccuracy.High, + context: Context = LocalContext.current, + coroutineScope: CoroutineScope = rememberCoroutineScope(), + sharingStarted: SharingStarted = SharingStarted.WhileSubscribed(stopTimeoutMillis = 1000), +): PlatformLocationProvider { + return remember(context, updateInterval, minDistance, desiredAccuracy, coroutineScope, sharingStarted) { + PlatformLocationProvider( + context = context, + updateInterval = updateInterval, + minDistance = minDistance, + desiredAccuracy = desiredAccuracy, + coroutineScope = coroutineScope, + sharingStarted = sharingStarted, + ) + } +} diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/UserLocationState.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/UserLocationState.kt new file mode 100644 index 0000000000..d9dc2037a6 --- /dev/null +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/UserLocationState.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.location.impl.common.userlocation + +import androidx.compose.runtime.Composable +import org.maplibre.compose.location.Location + +data class UserLocationState(val location: Location?) { + fun interface Factory { + @Composable + fun create(hasLocationPermission: Boolean): UserLocationState + } +} diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/SimpleLocationTrackingEffect.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/UserLocationTrackingEffect.kt similarity index 60% rename from features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/SimpleLocationTrackingEffect.kt rename to features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/UserLocationTrackingEffect.kt index 7a7a1551cf..ca6c10b7fa 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/ui/SimpleLocationTrackingEffect.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/userlocation/UserLocationTrackingEffect.kt @@ -5,16 +5,17 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.location.impl.common.ui +package io.element.android.features.location.impl.common.userlocation import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.snapshotFlow +import io.element.android.features.location.impl.common.MapDefaults import kotlinx.coroutines.flow.distinctUntilChanged +import org.maplibre.compose.camera.CameraState import org.maplibre.compose.location.Location -import org.maplibre.compose.location.UserLocationState import kotlin.math.abs /** @@ -22,17 +23,17 @@ import kotlin.math.abs * TODO remove once https://github.com/maplibre/maplibre-compose/issues/808 is fixed */ @Composable -internal fun SimpleLocationTrackingEffect( +internal fun UserLocationTrackingEffect( locationState: UserLocationState, enabled: Boolean = true, precision: Double = 0.00001, onLocationChange: suspend (Location?) -> Unit, ) { val latestOnLocationChange by rememberUpdatedState(onLocationChange) - - LaunchedEffect(locationState, enabled) { + val latestLocationState by rememberUpdatedState(locationState) + LaunchedEffect(enabled) { if (!enabled) return@LaunchedEffect - val locationStateFlow = snapshotFlow { locationState.location } + val locationStateFlow = snapshotFlow { latestLocationState.location } locationStateFlow .distinctUntilChanged { oldLocation, newLocation -> if (oldLocation != null && newLocation != null) { @@ -50,3 +51,27 @@ internal fun SimpleLocationTrackingEffect( } } } + +@Composable +internal fun UserLocationTrackingEffect( + cameraState: CameraState, + locationState: UserLocationState, + enabled: Boolean = true, + precision: Double = 0.00001, +) { + UserLocationTrackingEffect( + locationState = locationState, + enabled = enabled, + precision = precision + ) { location -> + val target = location?.position?.value ?: cameraState.position.target + cameraState.animateTo( + cameraState.position.copy( + target = target, + // Force pointing to NORTH + bearing = 0.0, + zoom = cameraState.position.zoom.coerceAtLeast(MapDefaults.DEFAULT_ZOOM) + ) + ) + } +} diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/DefaultActiveLiveLocationShareManager.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/DefaultActiveLiveLocationShareManager.kt index fd16bea515..c24d3f9cc2 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/DefaultActiveLiveLocationShareManager.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/DefaultActiveLiveLocationShareManager.kt @@ -133,6 +133,11 @@ class DefaultActiveLiveLocationShareManager( } } + override suspend fun onUnrecoverableError() { + Timber.d("ActiveLiveLocationShareManager unrecoverable error, stopping all shares") + localSharingRoomIds.value.toList().forEach { stopShare(it) } + } + override suspend fun onLocationUpdate(location: Location) { val activeSharesCount = localSharingRoomIds.value.size Timber.d("ActiveLiveLocationShareManager received location update for $activeSharesCount active share(s)") diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationReceiver.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationReceiver.kt index adba75730c..697a074093 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationReceiver.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationReceiver.kt @@ -9,6 +9,7 @@ package io.element.android.features.location.impl.live.service import io.element.android.features.location.api.Location -fun interface LiveLocationReceiver { +interface LiveLocationReceiver { suspend fun onLocationUpdate(location: Location) + suspend fun onUnrecoverableError() } diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingCoordinator.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingCoordinator.kt index e39acb14e8..63618baa3c 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingCoordinator.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingCoordinator.kt @@ -77,6 +77,17 @@ class LiveLocationSharingCoordinator internal constructor( } } + suspend fun dispatchUnrecoverableError() { + Timber.d("LiveLocationSharingCoordinator dispatching unrecoverable error") + receivers.forEach { (sessionId, receiver) -> + runCatchingExceptions { + receiver.onUnrecoverableError() + }.onFailure { + Timber.e(it, "Failed to dispatch unrecoverable error for session $sessionId") + } + } + } + suspend fun dispatch(location: Location) { val currentTimeMillis = nowMillis() val millisSincePrevious = currentTimeMillis - lastDispatchMillis.load() diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingService.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingService.kt index a926f1255b..21a0a081d8 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingService.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/live/service/LiveLocationSharingService.kt @@ -14,6 +14,7 @@ import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION import android.os.IBinder import androidx.core.app.ServiceCompat import dev.zacsweers.metro.Inject +import io.element.android.features.location.impl.common.userlocation.PlatformLocationProvider import io.element.android.features.location.impl.di.LocationBindings import io.element.android.features.location.impl.live.notification.LiveLocationSharingNotificationCreator import io.element.android.libraries.architecture.bindings @@ -29,13 +30,15 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach -import org.maplibre.compose.location.AndroidLocationProvider +import kotlinx.coroutines.launch import org.maplibre.compose.location.DesiredAccuracy +import org.maplibre.compose.location.PermissionException import org.maplibre.spatialk.units.extensions.inMeters import org.maplibre.spatialk.units.extensions.meters import timber.log.Timber @@ -48,7 +51,6 @@ class LiveLocationSharingService : Service() { @Inject lateinit var coordinator: LiveLocationSharingCoordinator @Inject lateinit var notificationCreator: LiveLocationSharingNotificationCreator @Inject lateinit var appPreferencesStore: AppPreferencesStore - @Inject lateinit var appForegroundStateService: AppForegroundStateService @AppCoroutineScope @@ -62,8 +64,8 @@ class LiveLocationSharingService : Service() { override fun onCreate() { super.onCreate() Timber.d("LiveLocationSharingService onCreate") + bindings().inject(this) runCatchingExceptions { - bindings().inject(this) appForegroundStateService.updateIsSharingLiveLocation(true) coroutineScope = appCoroutineScope.childScope(Dispatchers.Default, "LiveLocationSharingService") val notificationId = NotificationIdProvider.getForegroundServiceNotificationId(ForegroundServiceType.LIVE_LOCATION) @@ -81,6 +83,7 @@ class LiveLocationSharingService : Service() { startLocationUpdatesListener() }.onFailure { Timber.e(it, "Failed to start live location sharing service") + appCoroutineScope.launch { coordinator.dispatchUnrecoverableError() } stopSelf() } } @@ -90,14 +93,19 @@ class LiveLocationSharingService : Service() { Timber.d("LiveLocationSharingService listening to location updates") appPreferencesStore.getLiveLocationMinimumDistanceInMetersUpdateFlow() .flatMapLatest { minDistanceMeters -> - val locationProvider = AndroidLocationProvider( - context = applicationContext, - updateInterval = UPDATE_INTERVAL_IN_SECOND.seconds, - minDistance = minDistanceMeters.meters, - desiredAccuracy = DesiredAccuracy.Balanced, - coroutineScope = coroutineScope - ) - locationProvider.location + try { + PlatformLocationProvider( + context = applicationContext, + updateInterval = UPDATE_INTERVAL_IN_SECOND.seconds, + minDistance = minDistanceMeters.meters, + desiredAccuracy = DesiredAccuracy.Balanced, + coroutineScope = coroutineScope + ).location + } catch (exception: PermissionException) { + Timber.e(exception, "Failed to create PlatformLocationProvider") + coordinator.dispatchUnrecoverableError() + emptyFlow() + } } .filterNotNull() .map { location -> diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenter.kt index 6a769f8958..a3f3cac432 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenter.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenter.kt @@ -33,6 +33,7 @@ import io.element.android.features.location.impl.common.permissions.PermissionsP import io.element.android.features.location.impl.common.permissions.PermissionsState import io.element.android.features.location.impl.common.sendLiveLocationPermissions import io.element.android.features.location.impl.common.toDialogState +import io.element.android.features.location.impl.common.userlocation.UserLocationState import io.element.android.features.location.impl.live.LiveLocationStore import io.element.android.features.messages.api.MessageComposerContext import io.element.android.libraries.architecture.AsyncAction @@ -70,6 +71,7 @@ class ShareLocationPresenter( private val durationFormatter: DurationFormatter, private val liveLocationShareManager: ActiveLiveLocationShareManager, private val liveLocationStore: LiveLocationStore, + private val userLocationStateFactory: UserLocationState.Factory, ) : Presenter { @AssistedFactory fun interface Factory { @@ -86,6 +88,8 @@ class ShareLocationPresenter( var dialogState: ShareLocationState.Dialog by remember { mutableStateOf(ShareLocationState.Dialog.None) } + // true when trying to initiate the live location share + var pendingLiveLocationShare by remember { mutableStateOf(false) } val startLiveLocationAction = remember { mutableStateOf>(AsyncAction.Uninitialized) } val currentUser by client.userProfile.collectAsState() val customMapStyleUrl by produceState(AsyncData.Loading()) { @@ -98,32 +102,55 @@ class ShareLocationPresenter( val scope = rememberCoroutineScope() fun checkLocationConstraints() { - // No need to check SendLiveLocationPermissions here - val locationConstraints = checkLocationConstraints(permissionsState, locationActions, SendLiveLocationPermissions.GRANTED) + val locationConstraints = checkLocationConstraints( + permissionsState = permissionsState, + locationActions = locationActions, + // No need to check SendLiveLocationPermissions here + sendLiveLocationPermissions = SendLiveLocationPermissions.GRANTED + ) + if (locationConstraints is LocationConstraintsCheck.PermissionShouldBeRequested) { + permissionsState.eventSink(PermissionsEvents.RequestPermissions) + } trackUserPosition = locationConstraints is LocationConstraintsCheck.Success dialogState = ShareLocationState.Dialog.Constraints(locationConstraints.toDialogState()) } - suspend fun computeLiveLocationDialogState(): ShareLocationState.Dialog { - val hasAcceptedDisclaimer = liveLocationStore.hasAcceptedLiveLocationDisclaimer() - val constraintsResult = checkLocationConstraints(permissionsState, locationActions, sendLiveLocationPermissions) - return when { - !hasAcceptedDisclaimer -> { - ShareLocationState.Dialog.LiveLocationDisclaimer - } - constraintsResult is LocationConstraintsCheck.Success -> { - val durations = LIVE_LOCATION_DURATIONS.map { - LiveLocationDuration(duration = it, formatted = durationFormatter.format(it)) + suspend fun checkLiveLocationConstraints() { + val locationConstraints = checkLocationConstraints( + permissionsState = permissionsState, + locationActions = locationActions, + sendLiveLocationPermissions = sendLiveLocationPermissions, + ) + when (locationConstraints) { + LocationConstraintsCheck.Success -> { + val hasAcceptedDisclaimer = liveLocationStore.hasAcceptedLiveLocationDisclaimer() + dialogState = if (!hasAcceptedDisclaimer) { + ShareLocationState.Dialog.LiveLocationDisclaimer + } else { + val durations = LIVE_LOCATION_DURATIONS.map { + LiveLocationDuration(duration = it, formatted = durationFormatter.format(it)) + } + ShareLocationState.Dialog.LiveLocationDurations(durations.toImmutableList()) } - ShareLocationState.Dialog.LiveLocationDurations(durations.toImmutableList()) } else -> { - ShareLocationState.Dialog.Constraints(constraintsResult.toDialogState()) + if (locationConstraints is LocationConstraintsCheck.PermissionShouldBeRequested) { + permissionsState.eventSink(PermissionsEvents.RequestPermissions) + } + dialogState = ShareLocationState.Dialog.Constraints(locationConstraints.toDialogState()) } } } - LaunchedEffect(permissionsState.permissions) { checkLocationConstraints() } + val userLocationState = userLocationStateFactory.create(permissionsState.isAnyGranted) + + LaunchedEffect(permissionsState) { + if (pendingLiveLocationShare) { + checkLiveLocationConstraints() + } else { + checkLocationConstraints() + } + } fun handleEvent(event: ShareLocationEvent) { when (event) { @@ -132,7 +159,10 @@ class ShareLocationPresenter( } ShareLocationEvent.StartTrackingUserLocation -> checkLocationConstraints() ShareLocationEvent.StopTrackingUserLocation -> trackUserPosition = false - ShareLocationEvent.DismissDialog -> dialogState = ShareLocationState.Dialog.None + ShareLocationEvent.DismissDialog -> { + pendingLiveLocationShare = false + dialogState = ShareLocationState.Dialog.None + } ShareLocationEvent.OpenAppSettings -> { locationActions.openAppSettings() dialogState = ShareLocationState.Dialog.None @@ -142,15 +172,17 @@ class ShareLocationPresenter( dialogState = ShareLocationState.Dialog.None } ShareLocationEvent.InitiateLiveLocationShare -> scope.launch { - dialogState = computeLiveLocationDialogState() + pendingLiveLocationShare = true + checkLiveLocationConstraints() } ShareLocationEvent.AcceptLiveLocationDisclaimer -> scope.launch { liveLocationStore.setAcceptedLiveLocationDisclaimer() .onSuccess { - dialogState = computeLiveLocationDialogState() + checkLiveLocationConstraints() } } is ShareLocationEvent.StartLiveLocationShare -> scope.launch { + pendingLiveLocationShare = false dialogState = ShareLocationState.Dialog.None startLiveLocationAction.runUpdatingState { liveLocationShareManager.startShare( @@ -171,7 +203,7 @@ class ShareLocationPresenter( currentUser = currentUser, dialogState = dialogState, trackUserLocation = trackUserPosition, - hasLocationPermission = permissionsState.isAnyGranted, + userLocationState = userLocationState, canShareLiveLocation = timelineMode.canShareLiveLocation(), appName = appName, startLiveLocationAction = startLiveLocationAction.value, diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationState.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationState.kt index 9e78345bab..fb1b803435 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationState.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationState.kt @@ -9,6 +9,7 @@ package io.element.android.features.location.impl.share import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState +import io.element.android.features.location.impl.common.userlocation.UserLocationState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.user.MatrixUser @@ -19,7 +20,7 @@ data class ShareLocationState( val currentUser: MatrixUser, val dialogState: Dialog, val trackUserLocation: Boolean, - val hasLocationPermission: Boolean, + val userLocationState: UserLocationState, val appName: String, val canShareLiveLocation: Boolean, val startLiveLocationAction: AsyncAction, diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationStateProvider.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationStateProvider.kt index e7942b12df..ed8d46afd3 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationStateProvider.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationStateProvider.kt @@ -10,6 +10,7 @@ package io.element.android.features.location.impl.share import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState +import io.element.android.features.location.impl.common.userlocation.UserLocationState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.core.UserId @@ -26,43 +27,35 @@ class ShareLocationStateProvider : PreviewParameterProvider aShareLocationState( dialogState = ShareLocationState.Dialog.None, trackUserPosition = false, - hasLocationPermission = false, ), aShareLocationState( dialogState = ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.PermissionDenied), trackUserPosition = false, - hasLocationPermission = false, ), aShareLocationState( dialogState = ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.PermissionRationale), trackUserPosition = false, - hasLocationPermission = false, ), aShareLocationState( dialogState = ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.LocationServiceDisabled), trackUserPosition = false, - hasLocationPermission = true, ), aShareLocationState( dialogState = ShareLocationState.Dialog.None, trackUserPosition = false, - hasLocationPermission = true, ), aShareLocationState( dialogState = ShareLocationState.Dialog.None, trackUserPosition = true, - hasLocationPermission = true, ), aShareLocationState( dialogState = ShareLocationState.Dialog.None, trackUserPosition = true, - hasLocationPermission = true, canShareLiveLocation = true, ), aShareLocationState( dialogState = ShareLocationState.Dialog.LiveLocationDisclaimer, trackUserPosition = true, - hasLocationPermission = true, canShareLiveLocation = true, ), aShareLocationState( @@ -74,7 +67,6 @@ class ShareLocationStateProvider : PreviewParameterProvider ) ), trackUserPosition = true, - hasLocationPermission = true, canShareLiveLocation = true, ), aShareLocationState( @@ -88,7 +80,7 @@ fun aShareLocationState( currentUser: MatrixUser = MatrixUser(UserId("@user:matrix.org")), dialogState: ShareLocationState.Dialog = ShareLocationState.Dialog.None, trackUserPosition: Boolean = false, - hasLocationPermission: Boolean = false, + userLocationState: UserLocationState = UserLocationState(null), canShareLiveLocation: Boolean = false, appName: String = APP_NAME, startLiveLocationAction: AsyncAction = AsyncAction.Uninitialized, @@ -99,7 +91,7 @@ fun aShareLocationState( currentUser = currentUser, dialogState = dialogState, trackUserLocation = trackUserPosition, - hasLocationPermission = hasLocationPermission, + userLocationState = userLocationState, canShareLiveLocation = canShareLiveLocation, appName = appName, startLiveLocationAction = startLiveLocationAction, diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationView.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationView.kt index 68dcee36ac..dc857b37a6 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationView.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/share/ShareLocationView.kt @@ -20,7 +20,7 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SheetValue import androidx.compose.material3.rememberBottomSheetScaffoldState -import androidx.compose.material3.rememberStandardBottomSheetState +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -43,7 +43,7 @@ import io.element.android.features.location.impl.common.ui.LocationConstraintsDi import io.element.android.features.location.impl.common.ui.LocationFloatingActionButton import io.element.android.features.location.impl.common.ui.MapBottomSheetScaffold import io.element.android.features.location.impl.common.ui.UserLocationPuck -import io.element.android.features.location.impl.common.ui.rememberUserLocationState +import io.element.android.features.location.impl.common.userlocation.UserLocationTrackingEffect import io.element.android.features.location.impl.share.ShareLocationEvent.StartLiveLocationShare import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.components.LocationPin @@ -69,7 +69,6 @@ import kotlinx.collections.immutable.ImmutableList import org.maplibre.compose.camera.CameraMoveReason import org.maplibre.compose.camera.CameraState import org.maplibre.compose.camera.rememberCameraState -import org.maplibre.compose.location.UserLocationState import kotlin.time.Duration @OptIn(ExperimentalMaterial3Api::class) @@ -106,10 +105,11 @@ fun ShareLocationView( } val scaffoldState = rememberBottomSheetScaffoldState( - bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.Expanded) + bottomSheetState = rememberBottomSheetState( + initialValue = SheetValue.Expanded, + ) ) val cameraState = rememberCameraState(firstPosition = MapDefaults.defaultCameraPosition) - val userLocationState = rememberUserLocationState(state.hasLocationPermission) LaunchedEffect(cameraState.isCameraMoving) { if (cameraState.moveReason == CameraMoveReason.GESTURE) { @@ -136,15 +136,18 @@ fun ShareLocationView( BottomSheetContent( cameraState = cameraState, state = state, - userLocationState = userLocationState, navigateUp = navigateUp ) }, mapContent = { + UserLocationTrackingEffect( + cameraState = cameraState, + locationState = state.userLocationState, + enabled = state.trackUserLocation, + ) UserLocationPuck( cameraState = cameraState, - locationState = userLocationState, - trackUserLocation = state.trackUserLocation + location = state.userLocationState.location, ) }, overlayContent = { sheetPadding -> @@ -215,11 +218,10 @@ private fun StartLiveLocationActionView( private fun BottomSheetContent( cameraState: CameraState, state: ShareLocationState, - userLocationState: UserLocationState, navigateUp: () -> Unit, ) { Spacer(Modifier.height(20.dp)) - val userLocation = userLocationState.location + val userLocation = state.userLocationState.location if (state.trackUserLocation && userLocation != null) { ShareCurrentLocationItem { state.eventSink( diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt index bdb6dd26b8..f187e91c53 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt @@ -10,12 +10,14 @@ package io.element.android.features.location.impl.show import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedFactory @@ -23,6 +25,7 @@ import dev.zacsweers.metro.AssistedInject import io.element.android.features.location.api.Location import io.element.android.features.location.api.ShowLocationMode import io.element.android.features.location.api.live.ActiveLiveLocationShareManager +import io.element.android.features.location.api.live.isCurrentlySharing import io.element.android.features.location.impl.common.LocationConstraintsCheck import io.element.android.features.location.impl.common.MapDefaults import io.element.android.features.location.impl.common.SendLiveLocationPermissions @@ -33,6 +36,8 @@ import io.element.android.features.location.impl.common.permissions.PermissionsP import io.element.android.features.location.impl.common.permissions.PermissionsState import io.element.android.features.location.impl.common.toDialogState import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState +import io.element.android.features.location.impl.common.userlocation.UserLocationState +import io.element.android.features.location.impl.common.userlocation.asMapLibreLocation import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.mapState @@ -52,8 +57,7 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch -@AssistedInject -class ShowLocationPresenter( +@AssistedInject class ShowLocationPresenter( @Assisted private val mode: ShowLocationMode, permissionsPresenterFactory: PermissionsPresenter.Factory, private val locationActions: LocationActions, @@ -63,9 +67,9 @@ class ShowLocationPresenter( private val client: MatrixClient, private val joinedRoom: JoinedRoom, private val liveLocationShareManager: ActiveLiveLocationShareManager, + private val userLocationStateFactory: UserLocationState.Factory, ) : Presenter { - @AssistedFactory - fun interface Factory { + @AssistedFactory fun interface Factory { fun create(mode: ShowLocationMode): ShowLocationPresenter } @@ -86,10 +90,22 @@ class ShowLocationPresenter( value = AsyncData.Success(client.getMapStyleUrl().getOrNull()) } - LaunchedEffect(permissionsState.permissions) { - if (permissionsState.isAnyGranted) { - dialogState = LocationConstraintsDialogState.None + fun checkLocationConstraints() { + val locationConstraints = checkLocationConstraints( + permissionsState = permissionsState, + locationActions = locationActions, + // No need to check SendLiveLocationPermissions here + sendLiveLocationPermissions = SendLiveLocationPermissions.GRANTED + ) + if (locationConstraints is LocationConstraintsCheck.PermissionShouldBeRequested) { + permissionsState.eventSink(PermissionsEvents.RequestPermissions) } + isTrackMyLocation = locationConstraints is LocationConstraintsCheck.Success + dialogState = locationConstraints.toDialogState() + } + + LaunchedEffect(permissionsState) { + checkLocationConstraints() } fun handleEvent(event: ShowLocationEvent) { @@ -99,9 +115,7 @@ class ShowLocationPresenter( } is ShowLocationEvent.TrackMyLocation -> { if (event.enabled) { - val locationConstraints = checkLocationConstraints(permissionsState, locationActions, SendLiveLocationPermissions.GRANTED) - isTrackMyLocation = locationConstraints is LocationConstraintsCheck.Success - dialogState = locationConstraints.toDialogState() + checkLocationConstraints() } else { isTrackMyLocation = false } @@ -155,55 +169,66 @@ class ShowLocationPresenter( val liveLocationSharesFlow = joinedRoom.subscribeToLiveLocationShares() val membersStateFlow = joinedRoom.membersStateFlow.mapState { it.joinedRoomMembers() } combine(liveLocationSharesFlow, membersStateFlow) { liveShares, members -> - liveShares - .sortedWith(comparator) - .mapNotNull { share -> - val lastLocation = share.lastLocation ?: return@mapNotNull null - val location = Location.fromGeoUri(lastLocation.geoUri) ?: return@mapNotNull null - val member = members.find { it.userId == share.userId } - val displayName = member?.getBestName() ?: share.userId.value - val avatarUrl = member?.avatarUrl - val relativeTime = dateFormatter.format(timestamp = lastLocation.timestamp, mode = DateFormatterMode.Full, useRelative = true) - val formattedTimestamp = stringProvider.getString( - CommonStrings.screen_static_location_sheet_timestamp_description, - relativeTime - ) - LocationShareItem( - userId = share.userId, - displayName = displayName, - avatarData = AvatarData( - id = share.userId.value, - name = displayName, - url = avatarUrl, - size = AvatarSize.UserListItem, - ), - formattedTimestamp = formattedTimestamp, - location = location, - isLive = true, - assetType = lastLocation.assetType, - isOwnUser = share.userId == joinedRoom.sessionId - ) - } - .toImmutableList() + liveShares.sortedWith(comparator).mapNotNull { share -> + val lastLocation = share.lastLocation ?: return@mapNotNull null + val location = Location.fromGeoUri(lastLocation.geoUri) ?: return@mapNotNull null + val member = members.find { it.userId == share.userId } + val displayName = member?.getBestName() ?: share.userId.value + val avatarUrl = member?.avatarUrl + val relativeTime = dateFormatter.format(timestamp = lastLocation.timestamp, mode = DateFormatterMode.Full, useRelative = true) + val formattedTimestamp = stringProvider.getString( + CommonStrings.screen_static_location_sheet_timestamp_description, + relativeTime + ) + LocationShareItem( + userId = share.userId, + displayName = displayName, + avatarData = AvatarData( + id = share.userId.value, + name = displayName, + url = avatarUrl, + size = AvatarSize.UserListItem, + ), + formattedTimestamp = formattedTimestamp, + location = location, + isLive = true, + assetType = lastLocation.assetType, + isOwnUser = share.userId == joinedRoom.sessionId + ) + }.toImmutableList() }.collect { value = it } }.value } } - val focusedLocation = when (mode) { - is ShowLocationMode.Static -> locationShares.firstOrNull() - is ShowLocationMode.Live -> locationShares.firstOrNull { it.userId == mode.senderId } + val updatedLocationShares by rememberUpdatedState(locationShares) + val focusedLocation by remember { + derivedStateOf { + when (mode) { + is ShowLocationMode.Static -> updatedLocationShares.firstOrNull() + is ShowLocationMode.Live -> updatedLocationShares.firstOrNull { it.userId == mode.senderId } + } + } + } + val isCurrentlySharing by liveLocationShareManager.isCurrentlySharing(roomId = joinedRoom.roomId).collectAsState() + val hideUserLocationPuck = mode is ShowLocationMode.Live && isCurrentlySharing + val userLocationState = if (hideUserLocationPuck) { + // When sharing with this device, use the user LocationShareItem as source of data instead of the device. + val ownLocationShare by remember { derivedStateOf { updatedLocationShares.find { it.isOwnUser }?.location?.asMapLibreLocation() } } + UserLocationState(ownLocationShare) + } else { + userLocationStateFactory.create(hasLocationPermission = permissionsState.isAnyGranted) } - return ShowLocationState( customMapStyleUrl = customMapStyleUrl, dialogState = dialogState, locationShares = locationShares, focusedLocation = focusedLocation, - hasLocationPermission = permissionsState.isAnyGranted, isTrackMyLocation = isTrackMyLocation, + userLocationState = userLocationState, isLive = mode is ShowLocationMode.Live, appName = appName, + hideUserLocationPuck = hideUserLocationPuck, eventSink = ::handleEvent, ) } diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt index 478a3bd730..e5ddf589b0 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt @@ -11,6 +11,7 @@ package io.element.android.features.location.impl.show import io.element.android.features.location.api.Location import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState import io.element.android.features.location.impl.common.ui.LocationMarkerData +import io.element.android.features.location.impl.common.userlocation.UserLocationState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.PinVariant import io.element.android.libraries.designsystem.components.avatar.AvatarData @@ -24,9 +25,10 @@ data class ShowLocationState( val dialogState: LocationConstraintsDialogState, val locationShares: ImmutableList, val focusedLocation: LocationShareItem?, - val hasLocationPermission: Boolean, val isTrackMyLocation: Boolean, + val userLocationState: UserLocationState, val appName: String, + val hideUserLocationPuck: Boolean, val eventSink: (ShowLocationEvent) -> Unit, ) { val isSheetDraggable = isLive && locationShares.isNotEmpty() diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt index 85eacd3ce4..cd7ea108bb 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt @@ -11,6 +11,7 @@ package io.element.android.features.location.impl.show import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.location.api.Location import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState +import io.element.android.features.location.impl.common.userlocation.UserLocationState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize @@ -33,18 +34,9 @@ class ShowLocationStateProvider : PreviewParameterProvider { ), aShowLocationState( constraintsDialogState = LocationConstraintsDialogState.LocationServiceDisabled, - hasLocationPermission = true, - ), - aShowLocationState( - hasLocationPermission = true, - ), - aShowLocationState( - hasLocationPermission = true, - isTrackMyLocation = true, - ), - aShowLocationState( - customMapStyleUrl = AsyncData.Loading(), ), + aShowLocationState(isTrackMyLocation = true), + aShowLocationState(customMapStyleUrl = AsyncData.Loading()), ) } @@ -56,9 +48,10 @@ fun aShowLocationState( constraintsDialogState: LocationConstraintsDialogState = LocationConstraintsDialogState.None, locationShares: List = listOf(aLocationShareItem(isLive = isLive)), focusedLocation: LocationShareItem? = locationShares.firstOrNull(), - hasLocationPermission: Boolean = false, isTrackMyLocation: Boolean = false, + userLocationState: UserLocationState = UserLocationState(null), appName: String = APP_NAME, + hideUserLocationPuck: Boolean = false, eventSink: (ShowLocationEvent) -> Unit = {}, ): ShowLocationState { return ShowLocationState( @@ -66,8 +59,9 @@ fun aShowLocationState( dialogState = constraintsDialogState, locationShares = locationShares.toImmutableList(), focusedLocation = focusedLocation, - hasLocationPermission = hasLocationPermission, isTrackMyLocation = isTrackMyLocation, + userLocationState = userLocationState, + hideUserLocationPuck = hideUserLocationPuck, appName = appName, isLive = isLive, eventSink = eventSink, diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationView.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationView.kt index 5d5295871c..9fdbe3aac8 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationView.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationView.kt @@ -21,7 +21,7 @@ import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SheetValue import androidx.compose.material3.rememberBottomSheetScaffoldState -import androidx.compose.material3.rememberStandardBottomSheetState +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -43,7 +43,7 @@ import io.element.android.features.location.impl.common.ui.LocationPinMarkers import io.element.android.features.location.impl.common.ui.LocationShareRow import io.element.android.features.location.impl.common.ui.MapBottomSheetScaffold import io.element.android.features.location.impl.common.ui.UserLocationPuck -import io.element.android.features.location.impl.common.ui.rememberUserLocationState +import io.element.android.features.location.impl.common.userlocation.UserLocationTrackingEffect import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight @@ -91,9 +91,10 @@ fun ShowLocationView( } } - val userLocationState = rememberUserLocationState(state.hasLocationPermission) val scaffoldState = rememberBottomSheetScaffoldState( - bottomSheetState = rememberStandardBottomSheetState(SheetValue.Expanded) + bottomSheetState = rememberBottomSheetState( + initialValue = SheetValue.Expanded, + ) ) LaunchedEffect(state.isSheetDraggable) { if (!state.isSheetDraggable) { @@ -169,11 +170,17 @@ fun ShowLocationView( } }, mapContent = { - UserLocationPuck( + UserLocationTrackingEffect( cameraState = cameraState, - locationState = userLocationState, - trackUserLocation = state.isTrackMyLocation + locationState = state.userLocationState, + enabled = state.isTrackMyLocation, ) + if (!state.hideUserLocationPuck) { + UserLocationPuck( + cameraState = cameraState, + location = state.userLocationState.location, + ) + } val markers = remember(state.locationShares) { state.locationShares.map { it.toMarkerData() }.toImmutableList() } diff --git a/features/location/impl/src/main/res/values-fr/translations.xml b/features/location/impl/src/main/res/values-fr/translations.xml index 043c180dbc..802b869271 100644 --- a/features/location/impl/src/main/res/values-fr/translations.xml +++ b/features/location/impl/src/main/res/values-fr/translations.xml @@ -2,4 +2,5 @@ "Votre historique de localisation en direct sera enregistré dans le salon et visible par les membres après la fin de la session." "Choisissez la durée pendant laquelle vous partagerez votre position en direct." + "Vous n’êtes pas autorisé à partager votre position en direct dans ce salon." diff --git a/features/location/impl/src/main/res/values-ko/translations.xml b/features/location/impl/src/main/res/values-ko/translations.xml index e283d20b9c..aa23450335 100644 --- a/features/location/impl/src/main/res/values-ko/translations.xml +++ b/features/location/impl/src/main/res/values-ko/translations.xml @@ -2,4 +2,5 @@ "실시간 위치 기록은 대화방에 저장되며, 공유 종료 후에도 멤버들이 확인할 수 있습니다." "실시간 위치를 공유할 시간을 선택해 주세요." + "이 방에서는 실시간 위치를 공유할 권한이 없습니다." diff --git a/features/location/impl/src/main/res/values-uk/translations.xml b/features/location/impl/src/main/res/values-uk/translations.xml index 3c8155817a..08d205d925 100644 --- a/features/location/impl/src/main/res/values-uk/translations.xml +++ b/features/location/impl/src/main/res/values-uk/translations.xml @@ -2,4 +2,5 @@ "Ваша історія поточного місцезнаходження зберігатиметься у кімнаті та буде доступна учасникам після завершення сеансу." "Виберіть, як довго ділитися своїм місцезнаходженням." + "У вас немає дозволу ділитися своїм місцезнаходженням у реальному часі в цій кімнаті" diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/PermissionsStateFactory.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/PermissionsStateFactory.kt index a4352444dc..5c7bacb91a 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/PermissionsStateFactory.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/PermissionsStateFactory.kt @@ -13,10 +13,12 @@ import io.element.android.features.location.impl.common.permissions.PermissionsS fun aPermissionsState( permissions: PermissionsState.Permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale: Boolean = false, + permissionsRequested: Boolean = false, ): PermissionsState { return PermissionsState( permissions = permissions, shouldShowRationale = shouldShowRationale, + permissionsAlreadyRequested = permissionsRequested, eventSink = {}, ) } diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/FakeUserLocationStateFactory.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/FakeUserLocationStateFactory.kt new file mode 100644 index 0000000000..f6855c5667 --- /dev/null +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/FakeUserLocationStateFactory.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.location.impl.common + +import androidx.compose.runtime.Composable +import io.element.android.features.location.impl.common.userlocation.UserLocationState + +class FakeUserLocationStateFactory : UserLocationState.Factory { + @Composable + override fun create(hasLocationPermission: Boolean): UserLocationState { + return UserLocationState(null) + } +} diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/LocationConstraintsCheckTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/LocationConstraintsCheckTest.kt index debe95b464..40362bda3c 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/LocationConstraintsCheckTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/LocationConstraintsCheckTest.kt @@ -64,10 +64,25 @@ class LocationConstraintsCheckTest { } @Test - fun `checkLocationConstraints returns PermissionDenied when permissions denied without rationale`() { + fun `checkLocationConstraints returns PermissionShouldBeRequested when permissions not yet requested`() { val permissionsState = aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, + permissionsRequested = false, + ) + val locationActions = FakeLocationActions(isLocationEnabled = true) + + val result = checkLocationConstraints(permissionsState, locationActions, SendLiveLocationPermissions.GRANTED) + + assertThat(result).isEqualTo(LocationConstraintsCheck.PermissionShouldBeRequested) + } + + @Test + fun `checkLocationConstraints returns PermissionDenied when permissions already requested and denied without rationale`() { + val permissionsState = aPermissionsState( + permissions = PermissionsState.Permissions.NoneGranted, + shouldShowRationale = false, + permissionsRequested = true, ) val locationActions = FakeLocationActions(isLocationEnabled = true) diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/FakePermissionsPresenter.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/FakePermissionsPresenter.kt index 94d909a7ef..9b8ff7a29a 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/FakePermissionsPresenter.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/FakePermissionsPresenter.kt @@ -20,6 +20,7 @@ class FakePermissionsPresenter : PermissionsPresenter { private var state = PermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, + permissionsAlreadyRequested = false, eventSink = ::handleEvent, ) set(value) { diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/live/LiveLocationSharingCoordinatorTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/live/LiveLocationSharingCoordinatorTest.kt index f74322b4c5..6cee53a482 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/live/LiveLocationSharingCoordinatorTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/live/LiveLocationSharingCoordinatorTest.kt @@ -27,7 +27,7 @@ class LiveLocationSharingCoordinatorTest { nowMillis = { 0L }, ) - coordinator.register(A_SESSION_ID, LiveLocationReceiver { }) + coordinator.register(A_SESSION_ID, liveLocationReceiver()) coordinator.unregister(A_SESSION_ID) assertThat(startCount).isEqualTo(1) @@ -43,8 +43,8 @@ class LiveLocationSharingCoordinatorTest { nowMillis = { 4_000L }, ) - coordinator.register(A_SESSION_ID) { error("boom") } - coordinator.register(A_SESSION_ID_2) { location -> delivered += location } + coordinator.register(A_SESSION_ID, liveLocationReceiver { error("boom") }) + coordinator.register(A_SESSION_ID_2, liveLocationReceiver { delivered += it }) coordinator.dispatch(Location(lat = 1.0, lon = 2.0, accuracy = 3f)) assertThat(delivered).containsExactly(Location(lat = 1.0, lon = 2.0, accuracy = 3f)) @@ -60,7 +60,7 @@ class LiveLocationSharingCoordinatorTest { nowMillis = { nowMillis }, ) - coordinator.register(A_SESSION_ID) { location -> delivered += location } + coordinator.register(A_SESSION_ID, liveLocationReceiver { delivered += it }) val firstLocation = Location(lat = 1.0, lon = 2.0, accuracy = 3f) @@ -79,7 +79,7 @@ class LiveLocationSharingCoordinatorTest { nowMillis = { nowMillis }, ) - coordinator.register(A_SESSION_ID) { location -> delivered += location } + coordinator.register(A_SESSION_ID, liveLocationReceiver { delivered += it }) val firstLocation = Location(lat = 1.0, lon = 2.0, accuracy = 3f) val secondLocation = Location(lat = 4.0, lon = 5.0, accuracy = 6f) @@ -101,7 +101,7 @@ class LiveLocationSharingCoordinatorTest { nowMillis = { nowMillis }, ) - coordinator.register(A_SESSION_ID) { location -> delivered += location } + coordinator.register(A_SESSION_ID, liveLocationReceiver { delivered += it }) val firstLocation = Location(lat = 1.0, lon = 2.0, accuracy = 3f) val secondLocation = Location(lat = 4.0, lon = 5.0, accuracy = 6f) @@ -113,3 +113,10 @@ class LiveLocationSharingCoordinatorTest { assertThat(delivered).containsExactly(firstLocation, secondLocation).inOrder() } } + +private fun liveLocationReceiver( + onLocation: suspend (Location) -> Unit = {}, +) = object : LiveLocationReceiver { + override suspend fun onLocationUpdate(location: Location) = onLocation(location) + override suspend fun onUnrecoverableError() = Unit +} diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/DefaultShareLocationEntryPointTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/DefaultShareLocationEntryPointTest.kt index 6f20e296d9..49df684666 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/DefaultShareLocationEntryPointTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/DefaultShareLocationEntryPointTest.kt @@ -11,6 +11,7 @@ package io.element.android.features.location.impl.share import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.bumble.appyx.core.modality.BuildContext import com.google.common.truth.Truth.assertThat +import io.element.android.features.location.impl.common.FakeUserLocationStateFactory import io.element.android.features.location.impl.common.actions.FakeLocationActions import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter import io.element.android.features.location.impl.live.LiveLocationStore @@ -56,6 +57,7 @@ class DefaultShareLocationEntryPointTest { preferenceDataStoreFactory = FakePreferenceDataStoreFactory(), sessionId = room.sessionId, ), + userLocationStateFactory = FakeUserLocationStateFactory(), ) }, analyticsService = FakeAnalyticsService(), diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenterTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenterTest.kt index 5be96a50c5..f4cc135e9e 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenterTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationPresenterTest.kt @@ -21,6 +21,7 @@ import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.Composer import io.element.android.features.location.api.Location import io.element.android.features.location.impl.aPermissionsState +import io.element.android.features.location.impl.common.FakeUserLocationStateFactory import io.element.android.features.location.impl.common.actions.FakeLocationActions import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter import io.element.android.features.location.impl.common.permissions.PermissionsEvents @@ -102,6 +103,7 @@ class ShareLocationPresenterTest { durationFormatter = durationFormatter, liveLocationShareManager = liveLocationShareManager, liveLocationStore = liveLocationStore, + userLocationStateFactory = FakeUserLocationStateFactory(), ) @Test @@ -118,7 +120,6 @@ class ShareLocationPresenterTest { val state = awaitFirstItem() assertThat(state.customMapStyleUrl.isLoading()).isFalse() assertThat(state.trackUserLocation).isTrue() - assertThat(state.hasLocationPermission).isTrue() assertThat(state.dialogState).isEqualTo(ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.None)) } } @@ -155,11 +156,28 @@ class ShareLocationPresenterTest { }.test { val initialState = awaitFirstItem() assertThat(initialState.trackUserLocation).isTrue() - assertThat(initialState.hasLocationPermission).isTrue() assertThat(initialState.dialogState).isEqualTo(ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.None)) } } + @Test + fun `initial state with permissions not yet requested triggers permission request`() = runTest { + val shareLocationPresenter = createShareLocationPresenter() + fakePermissionsPresenter.givenState( + aPermissionsState( + permissions = PermissionsState.Permissions.NoneGranted, + shouldShowRationale = false, + permissionsRequested = false, + ) + ) + + shareLocationPresenter.test { + skipItems(2) + cancelAndIgnoreRemainingEvents() + assertThat(fakePermissionsPresenter.events).contains(PermissionsEvents.RequestPermissions) + } + } + @Test fun `initial state with permissions denied`() = runTest { val shareLocationPresenter = createShareLocationPresenter() @@ -167,6 +185,7 @@ class ShareLocationPresenterTest { aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, + permissionsRequested = true, ) ) @@ -175,7 +194,6 @@ class ShareLocationPresenterTest { }.test { val initialState = awaitFirstItem() assertThat(initialState.trackUserLocation).isFalse() - assertThat(initialState.hasLocationPermission).isFalse() assertThat(initialState.dialogState).isEqualTo( ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.PermissionDenied) ) @@ -195,7 +213,6 @@ class ShareLocationPresenterTest { shareLocationPresenter.test { val initialState = awaitFirstItem() assertThat(initialState.trackUserLocation).isFalse() - assertThat(initialState.hasLocationPermission).isFalse() assertThat(initialState.dialogState).isEqualTo( ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.PermissionRationale) ) @@ -216,7 +233,6 @@ class ShareLocationPresenterTest { shareLocationPresenter.test { val initialState = awaitFirstItem() assertThat(initialState.trackUserLocation).isFalse() - assertThat(initialState.hasLocationPermission).isTrue() assertThat(initialState.dialogState).isEqualTo( ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.LocationServiceDisabled) ) @@ -294,6 +310,7 @@ class ShareLocationPresenterTest { aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, + permissionsRequested = true, ) ) @@ -362,7 +379,12 @@ class ShareLocationPresenterTest { @Test fun `ShowLiveLocationDurationPicker shows disclaimer when acceptance is missing`() = runTest { - val presenter = createShareLocationPresenter() + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + roomPermissions = grantedSendLiveLocationPermissions() + ) + ) + val presenter = createShareLocationPresenter(joinedRoom = room) fakePermissionsPresenter.givenState( aPermissionsState( permissions = PermissionsState.Permissions.AllGranted, @@ -465,7 +487,12 @@ class ShareLocationPresenterTest { @Test fun `ShowLiveLocationDurationPicker uses the active session disclaimer state`() = runTest { - val joinedRoom = FakeJoinedRoom(baseRoom = FakeBaseRoom(sessionId = SessionId("@alice:server"))) + val joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + sessionId = SessionId("@alice:server"), + roomPermissions = grantedSendLiveLocationPermissions() + ), + ) createLiveLocationStore(sessionId = SessionId("@bob:server")) .setAcceptedLiveLocationDisclaimer() .getOrThrow() @@ -508,12 +535,13 @@ class ShareLocationPresenterTest { aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, + permissionsRequested = true, ) ) shareLocationPresenter.test { val initialState = awaitFirstItem() - // Dismiss initial dialog + // Dismiss initial dialog to allow re-triggering it initialState.eventSink(ShareLocationEvent.DismissDialog) val dismissedState = awaitItem() diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationViewTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationViewTest.kt index 370ccac8ab..c53e463280 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationViewTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/share/ShareLocationViewTest.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.ui.strings.CommonStrings @@ -26,11 +25,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ShareLocationViewTest { +class ShareLocationViewTest : RobolectricTest() { @Test fun `test back action`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) @@ -120,7 +118,6 @@ class ShareLocationViewTest { setShareLocationView( aShareLocationState( dialogState = ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.LocationServiceDisabled), - hasLocationPermission = true, eventSink = eventsRecorder ), navigateUp = EnsureNeverCalled(), @@ -135,7 +132,6 @@ class ShareLocationViewTest { setShareLocationView( aShareLocationState( dialogState = ShareLocationState.Dialog.Constraints(LocationConstraintsDialogState.LocationServiceDisabled), - hasLocationPermission = true, eventSink = eventsRecorder ), navigateUp = EnsureNeverCalled(), diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/DefaultShowLocationEntryPointTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/DefaultShowLocationEntryPointTest.kt index 8f55510128..23b7e9bf4d 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/DefaultShowLocationEntryPointTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/DefaultShowLocationEntryPointTest.kt @@ -14,6 +14,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.location.api.Location import io.element.android.features.location.api.ShowLocationEntryPoint import io.element.android.features.location.api.ShowLocationMode +import io.element.android.features.location.impl.common.FakeUserLocationStateFactory import io.element.android.features.location.impl.common.actions.FakeLocationActions import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter import io.element.android.features.location.test.FakeActiveLiveLocationShareManager @@ -51,6 +52,7 @@ class DefaultShowLocationEntryPointTest { joinedRoom = joinedRoom, client = FakeMatrixClient(), liveLocationShareManager = FakeActiveLiveLocationShareManager(), + userLocationStateFactory = FakeUserLocationStateFactory(), ) }, analyticsService = FakeAnalyticsService(), diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt index da3cea88f6..b579a79e4f 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt @@ -15,6 +15,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.location.api.Location import io.element.android.features.location.api.ShowLocationMode import io.element.android.features.location.impl.aPermissionsState +import io.element.android.features.location.impl.common.FakeUserLocationStateFactory import io.element.android.features.location.impl.common.actions.FakeLocationActions import io.element.android.features.location.impl.common.permissions.FakePermissionsPresenter import io.element.android.features.location.impl.common.permissions.PermissionsEvents @@ -36,11 +37,11 @@ import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.test import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test +import kotlin.time.Duration.Companion.hours @OptIn(ExperimentalCoroutinesApi::class) class ShowLocationPresenterTest { @@ -76,26 +77,9 @@ class ShowLocationPresenterTest { joinedRoom = joinedRoom, client = client, liveLocationShareManager = liveLocationShareManager, + userLocationStateFactory = FakeUserLocationStateFactory(), ) - @Test - fun `emits initial state with no location permission`() = runTest { - fakePermissionsPresenter.givenState( - aPermissionsState( - permissions = PermissionsState.Permissions.NoneGranted, - shouldShowRationale = false, - ) - ) - - val presenter = createShowLocationPresenter() - presenter.test { - val initialState = awaitItem() - assertThat(initialState.customMapStyleUrl.isLoading()).isTrue() - assertThat(initialState.hasLocationPermission).isFalse() - assertThat(initialState.isTrackMyLocation).isFalse() - } - } - @Test fun `present - non-null customMapStyleUrl`() = runTest { val shareLocationPresenter = createShowLocationPresenter( @@ -112,44 +96,14 @@ class ShowLocationPresenterTest { } } - @Test - fun `emits initial state location permission denied once`() = runTest { - fakePermissionsPresenter.givenState( - aPermissionsState( - permissions = PermissionsState.Permissions.NoneGranted, - shouldShowRationale = true, - ) - ) - - val presenter = createShowLocationPresenter() - presenter.test { - val initialState = awaitItem() - assertThat(initialState.hasLocationPermission).isFalse() - assertThat(initialState.isTrackMyLocation).isFalse() - } - } - - @Test - fun `emits initial state with location permission`() = runTest { - fakePermissionsPresenter.givenState(aPermissionsState(permissions = PermissionsState.Permissions.AllGranted)) - - val presenter = createShowLocationPresenter() - presenter.test { - val initialState = awaitItem() - assertThat(initialState.hasLocationPermission).isTrue() - assertThat(initialState.isTrackMyLocation).isFalse() - } - } - @Test fun `emits initial state with partial location permission`() = runTest { fakePermissionsPresenter.givenState(aPermissionsState(permissions = PermissionsState.Permissions.SomeGranted)) val presenter = createShowLocationPresenter() presenter.test { - val initialState = awaitItem() - assertThat(initialState.hasLocationPermission).isTrue() - assertThat(initialState.isTrackMyLocation).isFalse() + assertThat(awaitItem().isTrackMyLocation).isFalse() + assertThat(awaitItem().isTrackMyLocation).isTrue() } } @@ -174,17 +128,12 @@ class ShowLocationPresenterTest { ) ) presenter.test { - skipItems(1) val initialState = awaitItem() - assertThat(initialState.hasLocationPermission).isTrue() assertThat(initialState.isTrackMyLocation).isFalse() initialState.eventSink(ShowLocationEvent.TrackMyLocation(true)) val trackMyLocationState = awaitItem() - delay(1) - - assertThat(trackMyLocationState.hasLocationPermission).isTrue() assertThat(trackMyLocationState.isTrackMyLocation).isTrue() // Swipe the map to switch mode @@ -192,7 +141,6 @@ class ShowLocationPresenterTest { val trackLocationDisabledState = awaitItem() assertThat(trackLocationDisabledState.dialogState).isEqualTo(LocationConstraintsDialogState.None) assertThat(trackLocationDisabledState.isTrackMyLocation).isFalse() - assertThat(trackLocationDisabledState.hasLocationPermission).isTrue() } } @@ -215,14 +163,12 @@ class ShowLocationPresenterTest { val trackLocationState = awaitItem() assertThat(trackLocationState.dialogState).isEqualTo(LocationConstraintsDialogState.PermissionRationale) assertThat(trackLocationState.isTrackMyLocation).isFalse() - assertThat(trackLocationState.hasLocationPermission).isFalse() // Dismiss the dialog initialState.eventSink(ShowLocationEvent.DismissDialog) val dialogDismissedState = awaitItem() assertThat(dialogDismissedState.dialogState).isEqualTo(LocationConstraintsDialogState.None) assertThat(dialogDismissedState.isTrackMyLocation).isFalse() - assertThat(dialogDismissedState.hasLocationPermission).isFalse() } } @@ -244,7 +190,6 @@ class ShowLocationPresenterTest { val trackLocationState = awaitItem() assertThat(trackLocationState.dialogState).isEqualTo(LocationConstraintsDialogState.PermissionRationale) assertThat(trackLocationState.isTrackMyLocation).isFalse() - assertThat(trackLocationState.hasLocationPermission).isFalse() // Continue the dialog sends permission request to the permissions presenter trackLocationState.eventSink(ShowLocationEvent.RequestPermissions) @@ -252,12 +197,34 @@ class ShowLocationPresenterTest { } } + @Test + fun `TrackMyLocation with permissions not yet requested triggers permission request`() = runTest { + fakePermissionsPresenter.givenState( + aPermissionsState( + permissions = PermissionsState.Permissions.NoneGranted, + shouldShowRationale = false, + permissionsRequested = false, + ) + ) + + val presenter = createShowLocationPresenter() + presenter.test { + val initialState = awaitItem() + + initialState.eventSink(ShowLocationEvent.TrackMyLocation(true)) + + assertThat(fakePermissionsPresenter.events).contains(PermissionsEvents.RequestPermissions) + cancelAndIgnoreRemainingEvents() + } + } + @Test fun `permission denied dialog dismiss`() = runTest { fakePermissionsPresenter.givenState( aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, + permissionsRequested = true, ) ) @@ -271,14 +238,12 @@ class ShowLocationPresenterTest { val trackLocationState = awaitItem() assertThat(trackLocationState.dialogState).isEqualTo(LocationConstraintsDialogState.PermissionDenied) assertThat(trackLocationState.isTrackMyLocation).isFalse() - assertThat(trackLocationState.hasLocationPermission).isFalse() // Dismiss the dialog initialState.eventSink(ShowLocationEvent.DismissDialog) val dialogDismissedState = awaitItem() assertThat(dialogDismissedState.dialogState).isEqualTo(LocationConstraintsDialogState.None) assertThat(dialogDismissedState.isTrackMyLocation).isFalse() - assertThat(dialogDismissedState.hasLocationPermission).isFalse() } } @@ -288,6 +253,7 @@ class ShowLocationPresenterTest { aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, + permissionsRequested = true, ) ) @@ -326,7 +292,6 @@ class ShowLocationPresenterTest { val presenter = createShowLocationPresenter() presenter.test { val initialState = awaitItem() - assertThat(initialState.hasLocationPermission).isTrue() // Try to track location when location services are disabled initialState.eventSink(ShowLocationEvent.TrackMyLocation(true)) @@ -493,4 +458,51 @@ class ShowLocationPresenterTest { assertThat(state.isSheetDraggable).isFalse() } } + + @Test + fun `static mode never hides user location puck`() = runTest { + val presenter = createShowLocationPresenter() + presenter.test { + val state = awaitItem() + assertThat(state.hideUserLocationPuck).isFalse() + } + } + + @Test + fun `live mode does not hide user location puck when not sharing`() = runTest { + val presenter = createShowLocationPresenter( + mode = ShowLocationMode.Live(senderId = A_USER_ID), + ) + presenter.test { + val state = awaitItem() + assertThat(state.hideUserLocationPuck).isFalse() + } + } + + @Test + fun `live mode user location state uses own share position when sharing`() = runTest { + val ownLiveLocationShare = aLiveLocationShare() + val fakeRoom = FakeJoinedRoom( + liveLocationSharesFlow = MutableStateFlow(listOf(ownLiveLocationShare)) + ) + val manager = FakeActiveLiveLocationShareManager( + startShareLambda = { _, _ -> Result.success(Unit) } + ) + manager.startShare(fakeRoom.roomId, 1.hours) + + val presenter = createShowLocationPresenter( + mode = ShowLocationMode.Live(senderId = A_USER_ID), + joinedRoom = fakeRoom, + liveLocationShareManager = manager, + ) + val ownLocation = ownLiveLocationShare.lastLocation?.geoUri?.let(Location::fromGeoUri) + presenter.test { + skipItems(1) + val state = awaitItem() + assertThat(state.hideUserLocationPuck).isTrue() + val location = requireNotNull(state.userLocationState.location) + assertThat(location.position.value.latitude).isEqualTo(ownLocation?.lat) + assertThat(location.position.value.longitude).isEqualTo(ownLocation?.lon) + } + } } diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationViewTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationViewTest.kt index 45ed894f97..053c26c179 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationViewTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationViewTest.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.location.api.Location import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState import io.element.android.libraries.testtags.TestTags @@ -29,11 +28,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ShowLocationViewTest { +class ShowLocationViewTest : RobolectricTest() { @Test fun `test back action`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt new file mode 100644 index 0000000000..d67668caf1 --- /dev/null +++ b/features/lockscreen/api/src/main/kotlin/io/element/android/features/lockscreen/api/DeviceUnlockEntryPoint.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import io.element.android.libraries.architecture.FeatureEntryPoint + +/** + * An entry point for features that want to lock the screen and require + * the user to unlock it before they can interact with the app. + * - if the system lock is available, it will be used to unlock the screen. + * - if the system lock is not available, but app lock is available, it will be used to unlock the screen. + * - if neither is available, the screen will be unlocked immediately. + * + * The Node provided by [createNode] has to be added as a PermanentChild. + */ +interface DeviceUnlockEntryPoint : FeatureEntryPoint { + fun createNode( + parentNode: Node, + buildContext: BuildContext, + ): Node + + fun requestUnlock(callback: Callback) + + interface Callback { + fun onCancel() + fun onUnlock() + } +} diff --git a/features/lockscreen/impl/build.gradle.kts b/features/lockscreen/impl/build.gradle.kts index 63aec590de..414b4b5909 100644 --- a/features/lockscreen/impl/build.gradle.kts +++ b/features/lockscreen/impl/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(libs.androidx.biometric) testCommonDependencies(libs, true) + testImplementation(projects.features.lockscreen.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.cryptography.test) testImplementation(projects.libraries.cryptography.impl) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultDeviceUnlockEntryPoint.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultDeviceUnlockEntryPoint.kt new file mode 100644 index 0000000000..f4b78968f8 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultDeviceUnlockEntryPoint.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import io.element.android.features.lockscreen.impl.device.DeviceUnlockCallbackHolder +import io.element.android.features.lockscreen.impl.device.DeviceUnlockNode +import io.element.android.libraries.architecture.createNode + +@ContributesBinding(AppScope::class) +class DefaultDeviceUnlockEntryPoint( + private val deviceUnlockCallbackHolder: DeviceUnlockCallbackHolder, +) : DeviceUnlockEntryPoint { + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + ): Node { + return parentNode.createNode( + buildContext = buildContext, + ) + } + + override fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) { + deviceUnlockCallbackHolder.requestUnlock(callback) + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt index d18d9b73b7..74d36b0834 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticator.kt @@ -59,6 +59,7 @@ class DefaultBiometricAuthentication( private var cryptoObject: CryptoObject? = null override suspend fun setup() { + if (cryptoObject != null) return try { val secretKey = ensureKey() val cipher = encryptionDecryptionService.createEncryptionCipher(secretKey) @@ -109,7 +110,9 @@ private class AuthenticationCallback( override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { super.onAuthenticationSucceeded(result) - if (result.cryptoObject?.cipher.isValid()) { + if (result.authenticationType == BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC && + result.cryptoObject?.cipher.isValid() || + result.authenticationType == BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL) { callbacks.forEach { it.onBiometricAuthenticationSuccess() } deferredAuthenticationResult.complete(BiometricAuthenticator.AuthenticationResult.Success) } else { diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt index 2ea0ed7d05..cccfa143b9 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/BiometricAuthenticatorManager.kt @@ -21,6 +21,11 @@ interface BiometricAuthenticatorManager { */ val hasAvailableAuthenticator: Boolean + /** + * If the device is secured for example with a pin, a pattern, a password, or biometric. + */ + val canUseDeviceUnlock: Boolean + fun addCallback(callback: BiometricAuthenticator.Callback) fun removeCallback(callback: BiometricAuthenticator.Callback) @@ -35,6 +40,12 @@ interface BiometricAuthenticatorManager { @Composable fun rememberUnlockBiometricAuthenticator(): BiometricAuthenticator + /** + * Remember a biometric authenticator ready for unlocking the app, using the device settings. + */ + @Composable + fun rememberUnlockDeviceBiometricAuthenticator(): BiometricAuthenticator + /** * Remember a biometric authenticator ready for confirmation. */ diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt index 117323ec0a..80ea43b44d 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt @@ -35,6 +35,7 @@ import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.di.annotations.ApplicationContext import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch import java.util.concurrent.CopyOnWriteArrayList @@ -69,6 +70,12 @@ class DefaultBiometricAuthenticatorManager( get() = lockScreenConfig.isStrongBiometricsEnabled && biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS + /** + * Returns true if a device credential method (i.e.: pattern, pin) can be used. + */ + private val canUseDeviceCredentialAuth: Boolean + get() = biometricManager.canAuthenticate(BiometricManager.Authenticators.DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS + /** * Returns true if any biometric method (weak or strong) can be used. */ @@ -78,6 +85,9 @@ class DefaultBiometricAuthenticatorManager( override val isDeviceSecured: Boolean get() = keyguardManager.isDeviceSecure + override val canUseDeviceUnlock: Boolean + get() = isDeviceSecured && (canUseWeakBiometricAuth || canUseStrongBiometricAuth || canUseDeviceCredentialAuth) + private val internalCallback = object : DefaultBiometricUnlockCallback() { override fun onBiometricSetupError() { coroutineScope.launch { disable() } @@ -99,6 +109,28 @@ class DefaultBiometricAuthenticatorManager( isAvailable = isAvailable, promptTitle = promptTitle, promptNegative = promptNegative, + forDeviceUnlock = false, + ) + } + + @Composable + override fun rememberUnlockDeviceBiometricAuthenticator(): BiometricAuthenticator { + val isAvailableTrigger by remember { + // Need to trigger the creation of BiometricAuthenticator twice, else the callback will not be ready. + // (the issue already exists in [rememberUnlockBiometricAuthenticator]) + flowOf(false, true) + }.collectAsState(initial = false) + val lifecycleState by LocalLifecycleOwner.current.lifecycle.currentStateFlow.collectAsState() + val isAvailable by remember(lifecycleState) { + derivedStateOf { isAvailableTrigger && canUseDeviceUnlock } + } + val promptTitle = stringResource(id = R.string.screen_app_lock_biometric_unlock_title_android) + val promptNegative = null + return rememberBiometricAuthenticator( + isAvailable = isAvailable, + promptTitle = promptTitle, + promptNegative = promptNegative, + forDeviceUnlock = true, ) } @@ -114,6 +146,7 @@ class DefaultBiometricAuthenticatorManager( isAvailable = isAvailable, promptTitle = promptTitle, promptNegative = promptNegative, + forDeviceUnlock = false, ) } @@ -126,7 +159,8 @@ class DefaultBiometricAuthenticatorManager( private fun rememberBiometricAuthenticator( isAvailable: Boolean, promptTitle: String, - promptNegative: String, + promptNegative: String?, + forDeviceUnlock: Boolean, ): BiometricAuthenticator { val activity = LocalContext.current.findFragmentActivity() return remember(isAvailable) { @@ -136,11 +170,21 @@ class DefaultBiometricAuthenticatorManager( canUseWeakBiometricAuth -> BiometricManager.Authenticators.BIOMETRIC_WEAK else -> 0 } - val promptInfo = BiometricPrompt.PromptInfo.Builder().apply { - setTitle(promptTitle) - setNegativeButtonText(promptNegative) - setAllowedAuthenticators(authenticators) - }.build() + val promptInfo = BiometricPrompt.PromptInfo.Builder() + .setTitle(promptTitle) + .apply { + if (promptNegative != null) { + setNegativeButtonText(promptNegative) + } + if (forDeviceUnlock) { + setAllowedAuthenticators( + authenticators or if (canUseDeviceCredentialAuth) BiometricManager.Authenticators.DEVICE_CREDENTIAL else 0 + ) + } else { + setAllowedAuthenticators(authenticators) + } + } + .build() DefaultBiometricAuthentication( activity = activity, promptInfo = promptInfo, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockCallbackHolder.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockCallbackHolder.kt new file mode 100644 index 0000000000..cf8b23d3f6 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockCallbackHolder.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.Inject +import dev.zacsweers.metro.SingleIn +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +@Inject +@SingleIn(AppScope::class) +class DeviceUnlockCallbackHolder { + private val _deviceUnlockCallback = MutableStateFlow(null) + val deviceUnlockCallback: StateFlow = _deviceUnlockCallback + + fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) { + _deviceUnlockCallback.value = callback + } + + fun onDone() { + _deviceUnlockCallback.value = null + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockEvent.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockEvent.kt new file mode 100644 index 0000000000..8b894875cb --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockEvent.kt @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +sealed interface DeviceUnlockEvent { + data object CancelPinCode : DeviceUnlockEvent +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt new file mode 100644 index 0000000000..9b73239725 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockNode.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedInject +import io.element.android.annotations.ContributesNode +import io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter +import io.element.android.features.lockscreen.impl.unlock.PinUnlockView +import io.element.android.libraries.di.SessionScope + +@ContributesNode(SessionScope::class) +@AssistedInject +class DeviceUnlockNode( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val presenter: DeviceUnlockPresenter, + private val pinUnlockPresenterFactory: PinUnlockPresenter.Factory, +) : Node(buildContext, plugins = plugins) { + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + if (state.showApplicationPinCode) { + val pinUnlockPresenter = remember { + pinUnlockPresenterFactory.create(forDeviceUnlock = true) + } + val pinState = pinUnlockPresenter.present() + PinUnlockView( + state = pinState, + isInAppUnlock = true, + onCancel = { + state.eventSink(DeviceUnlockEvent.CancelPinCode) + }, + modifier = modifier, + ) + } + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt new file mode 100644 index 0000000000..676340764e --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenter.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import dev.zacsweers.metro.Inject +import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticatorManager +import io.element.android.features.lockscreen.impl.pin.PinCodeManager +import io.element.android.features.lockscreen.impl.unlock.PinUnlockHelper +import io.element.android.libraries.architecture.Presenter +import kotlinx.coroutines.flow.first + +@Inject +class DeviceUnlockPresenter( + private val pinUnlockHelper: PinUnlockHelper, + private val biometricAuthenticatorManager: BiometricAuthenticatorManager, + private val deviceUnlockCallbackHolder: DeviceUnlockCallbackHolder, + private val pinCodeManager: PinCodeManager, +) : Presenter { + @Composable + override fun present(): DeviceUnlockState { + var showApplicationPinCode by remember { + mutableStateOf(false) + } + + val biometricUnlock = biometricAuthenticatorManager.rememberUnlockDeviceBiometricAuthenticator() + val deviceUnlockCallback by deviceUnlockCallbackHolder.deviceUnlockCallback.collectAsState() + val canUseDeviceUnlock = biometricAuthenticatorManager.canUseDeviceUnlock + + fun setUnlock(isUnlock: Boolean) { + deviceUnlockCallback?.let { + if (isUnlock) { + it.onUnlock() + } else { + it.onCancel() + } + } + showApplicationPinCode = false + deviceUnlockCallbackHolder.onDone() + } + + LaunchedEffect(biometricUnlock, canUseDeviceUnlock, deviceUnlockCallback) { + if (deviceUnlockCallback != null) { + if (canUseDeviceUnlock) { + biometricUnlock.setup() + biometricUnlock.authenticate() + } else if (pinCodeManager.hasPinCode().first()) { + showApplicationPinCode = true + } else { + // No security, unlock immediately + setUnlock(true) + } + } + } + + pinUnlockHelper.OnUnlockEffect { isUnlock -> + setUnlock(isUnlock) + } + + fun handleEvent(event: DeviceUnlockEvent) { + when (event) { + DeviceUnlockEvent.CancelPinCode -> { + showApplicationPinCode = false + setUnlock(false) + } + } + } + + return DeviceUnlockState( + showApplicationPinCode = showApplicationPinCode, + eventSink = ::handleEvent, + ) + } +} diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockState.kt new file mode 100644 index 0000000000..48d2181605 --- /dev/null +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockState.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.impl.device + +data class DeviceUnlockState( + val showApplicationPinCode: Boolean, + val eventSink: (DeviceUnlockEvent) -> Unit, +) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt index 0bd26729d5..a6e2c1265c 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt @@ -103,8 +103,15 @@ class LockScreenSettingsFlowNode( override fun onUnlock() { backstack.newRoot(NavTarget.Settings) } + + override fun onCancel() { + // Should not happen in this context. + } } - createNode(buildContext, plugins = listOf(callback)) + val inputs = PinUnlockNode.Inputs( + forDeviceUnlock = false, + ) + createNode(buildContext, plugins = listOf(callback, inputs)) } NavTarget.SetupPin -> { createNode(buildContext) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt index 2a475814c9..10de1f23a5 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockHelper.kt @@ -24,17 +24,23 @@ class PinUnlockHelper( private val pinCodeManager: PinCodeManager ) { @Composable - fun OnUnlockEffect(onUnlock: () -> Unit) { + fun OnUnlockEffect(onUnlock: (Boolean) -> Unit) { val latestOnUnlock by rememberUpdatedState(onUnlock) DisposableEffect(Unit) { val biometricUnlockCallback = object : DefaultBiometricUnlockCallback() { override fun onBiometricAuthenticationSuccess() { - latestOnUnlock() + latestOnUnlock(true) + } + + override fun onBiometricAuthenticationFailed(error: Exception?) { + if (error != null) { + latestOnUnlock(false) + } } } val pinCodeVerifiedCallback = object : DefaultPinCodeManagerCallback() { override fun onPinCodeVerified() { - latestOnUnlock() + latestOnUnlock(true) } } biometricAuthenticatorManager.addCallback(biometricUnlockCallback) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt index 459e165e00..47e7715ea5 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockNode.kt @@ -17,7 +17,9 @@ import com.bumble.appyx.core.plugin.Plugin import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode +import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.callback +import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope @ContributesNode(SessionScope::class) @@ -25,13 +27,23 @@ import io.element.android.libraries.di.SessionScope class PinUnlockNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: PinUnlockPresenter, + presenterFactory: PinUnlockPresenter.Factory, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun onUnlock() + + // For feature unlock + fun onCancel() } + data class Inputs( + val forDeviceUnlock: Boolean, + ) : NodeInputs + private val callback: Callback = callback() + private val inputs: Inputs = inputs() + + private val presenter: PinUnlockPresenter = presenterFactory.create(inputs.forDeviceUnlock) @Composable override fun View(modifier: Modifier) { @@ -46,6 +58,7 @@ class PinUnlockNode( // UnlockNode is only used for in-app unlock, so we can safely set isInAppUnlock to true. // It's set to false in PinUnlockActivity. isInAppUnlock = true, + onCancel = callback::onCancel, modifier = modifier ) } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt index c8dd8916f9..65afba669d 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt @@ -16,7 +16,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import dev.zacsweers.metro.Inject +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedFactory +import dev.zacsweers.metro.AssistedInject import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticator import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticatorManager import io.element.android.features.lockscreen.impl.pin.PinCodeManager @@ -32,8 +34,9 @@ import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -@Inject +@AssistedInject class PinUnlockPresenter( + @Assisted private val forDeviceUnlock: Boolean, private val pinCodeManager: PinCodeManager, private val biometricAuthenticatorManager: BiometricAuthenticatorManager, private val logoutUseCase: LogoutUseCase, @@ -41,6 +44,11 @@ class PinUnlockPresenter( private val coroutineScope: CoroutineScope, private val pinUnlockHelper: PinUnlockHelper, ) : Presenter { + @AssistedFactory + interface Factory { + fun create(forDeviceUnlock: Boolean): PinUnlockPresenter + } + @Composable override fun present(): PinUnlockState { val pinEntryState = remember { @@ -98,7 +106,7 @@ class PinUnlockPresenter( } } pinUnlockHelper.OnUnlockEffect { - isUnlocked.value = true + isUnlocked.value = it } fun handleEvent(event: PinUnlockEvent) { @@ -128,6 +136,7 @@ class PinUnlockPresenter( } } return PinUnlockState( + canNavigateBack = forDeviceUnlock, pinEntry = pinEntry, showWrongPinTitle = showWrongPinTitle, remainingAttempts = remainingAttempts, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt index 037aa87dec..1aae6afa51 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockState.kt @@ -15,6 +15,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData data class PinUnlockState( + val canNavigateBack: Boolean, val pinEntry: AsyncData, val showWrongPinTitle: Boolean, val remainingAttempts: AsyncData, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt index 1b8166a8ac..aef2c057a2 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockStateProvider.kt @@ -38,10 +38,20 @@ open class PinUnlockStateProvider : PreviewParameterProvider { showWrongPinTitle = true, isUnlocked = true, ), + aPinUnlockState(canNavigateBack = true), + ) +} + +open class PinUnlockStateCompactProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aPinUnlockState(), + aPinUnlockState(canNavigateBack = true) ) } fun aPinUnlockState( + canNavigateBack: Boolean = false, pinEntry: AsyncData = AsyncData.Success(PinEntry.createEmpty(4)), remainingAttempts: AsyncData = AsyncData.Success(3), showWrongPinTitle: Boolean = false, @@ -51,6 +61,7 @@ fun aPinUnlockState( isUnlocked: Boolean = false, signOutAction: AsyncAction = AsyncAction.Uninitialized, ) = PinUnlockState( + canNavigateBack = canNavigateBack, pinEntry = pinEntry, showWrongPinTitle = showWrongPinTitle, remainingAttempts = remainingAttempts, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt index 6749697b64..0292b29a0f 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle @@ -50,6 +51,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.components.ProgressDialog +import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog import io.element.android.libraries.designsystem.preview.ElementPreview @@ -65,6 +67,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun PinUnlockView( state: PinUnlockState, isInAppUnlock: Boolean, + onCancel: () -> Unit, modifier: Modifier = Modifier, ) { OnLifecycleEvent { _, event -> @@ -74,7 +77,7 @@ fun PinUnlockView( } } Surface(modifier) { - PinUnlockPage(state = state, isInAppUnlock = isInAppUnlock) + PinUnlockPage(state = state, isInAppUnlock = isInAppUnlock, onCancel = onCancel) if (state.showSignOutPrompt) { SignOutPrompt( isCancellable = state.isSignOutPromptCancellable, @@ -105,13 +108,14 @@ fun PinUnlockView( private fun PinUnlockPage( state: PinUnlockState, isInAppUnlock: Boolean, + onCancel: () -> Unit, ) { BoxWithConstraints { val commonModifier = Modifier - .fillMaxSize() - .systemBarsPadding() - .imePadding() - .padding(all = 20.dp) + .fillMaxSize() + .systemBarsPadding() + .imePadding() + .padding(all = 20.dp) val header = @Composable { PinUnlockHeader( @@ -147,8 +151,8 @@ private fun PinUnlockPage( state.eventSink(PinUnlockEvent.OnPinEntryChanged(it)) }, modifier = Modifier - .focusRequester(focusRequester) - .fillMaxWidth() + .focusRequester(focusRequester) + .fillMaxWidth() ) } } else { @@ -177,6 +181,15 @@ private fun PinUnlockPage( modifier = commonModifier, ) } + if (state.canNavigateBack) { + BackButton( + onClick = onCancel, + modifier = Modifier + .align(Alignment.TopStart) + .systemBarsPadding() + .padding(8.dp), + ) + } } } @@ -217,8 +230,8 @@ private fun PinUnlockCompactView( } BoxWithConstraints( modifier = Modifier - .weight(1f) - .fillMaxHeight(), + .weight(1f) + .fillMaxHeight(), contentAlignment = Alignment.Center, ) { content() @@ -239,9 +252,9 @@ private fun PinUnlockExpandedView( header() BoxWithConstraints( modifier = Modifier - .weight(1f) - .fillMaxWidth() - .padding(top = 40.dp), + .weight(1f) + .fillMaxWidth() + .padding(top = 40.dp), ) { content() } @@ -274,8 +287,8 @@ private fun PinDot( } Box( modifier = Modifier - .size(14.dp) - .background(backgroundColor, CircleShape) + .size(14.dp) + .background(backgroundColor, CircleShape) ) } @@ -373,6 +386,7 @@ internal fun PinUnlockViewInAppPreview(@PreviewParameter(PinUnlockStateProvider: PinUnlockView( state = state, isInAppUnlock = true, + onCancel = {}, ) } } @@ -384,6 +398,19 @@ internal fun PinUnlockViewPreview(@PreviewParameter(PinUnlockStateProvider::clas PinUnlockView( state = state, isInAppUnlock = false, + onCancel = {}, + ) + } +} + +@Composable +@Preview(heightDp = 480, widthDp = 800) +internal fun PinUnlockViewCompactPreview(@PreviewParameter(PinUnlockStateCompactProvider::class) state: PinUnlockState) { + ElementPreview { + PinUnlockView( + state = state, + isInAppUnlock = false, + onCancel = {}, ) } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt index 34adfeca99..613b1cf79e 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/activity/PinUnlockActivity.kt @@ -41,7 +41,7 @@ class PinUnlockActivity : AppCompatActivity() { } } - @Inject lateinit var presenter: PinUnlockPresenter + @Inject lateinit var presenterFactory: PinUnlockPresenter.Factory @Inject lateinit var lockScreenService: LockScreenService @Inject lateinit var appPreferencesStore: AppPreferencesStore @Inject lateinit var featureFlagService: FeatureFlagService @@ -52,6 +52,7 @@ class PinUnlockActivity : AppCompatActivity() { enableEdgeToEdge() super.onCreate(savedInstanceState) bindings().inject(this) + val presenter = presenterFactory.create(forDeviceUnlock = false) setContent { val colors by remember { enterpriseService.semanticColorsFlow(sessionId = null) @@ -67,6 +68,9 @@ class PinUnlockActivity : AppCompatActivity() { PinUnlockView( state = state, isInAppUnlock = false, + onCancel = { + // Should not happen + }, ) } } diff --git a/features/lockscreen/impl/src/main/res/values-be/translations.xml b/features/lockscreen/impl/src/main/res/values-be/translations.xml index 7667034623..7b714d329d 100644 --- a/features/lockscreen/impl/src/main/res/values-be/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-be/translations.xml @@ -35,5 +35,5 @@ "Выкарыстоўваць біяметрыю" "Выкарыстоўваць PIN-код" - "Выхад…" + "Выдаленне прылады…" diff --git a/features/lockscreen/impl/src/main/res/values-in/translations.xml b/features/lockscreen/impl/src/main/res/values-in/translations.xml index e0054cda62..5cd461b477 100644 --- a/features/lockscreen/impl/src/main/res/values-in/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-in/translations.xml @@ -23,7 +23,7 @@ Pilih sesuatu yang mudah untuk diingat. Jika Anda lupa PIN ini, Anda akan dikelu "Silakan masukkan PIN yang sama dua kali" "PIN tidak cocok" "Anda harus masuk ulang dan membuat PIN baru untuk melanjutkan" - "Anda sedang dikeluarkan" + "Perangkat ini sedang dilepas" "Anda memiliki %1$d percobaan lagi untuk membuka kunci" diff --git a/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml b/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml index f2f67dca6d..56f113c2fb 100644 --- a/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-pt-rBR/translations.xml @@ -23,7 +23,7 @@ Escolha algo memorável. Se você esquecer este PIN, você será desconectado do "Por favor, digite o mesmo PIN duas vezes" "Os PINs não correspondem" "Você terá que entrar novamente e criar um PIN novo para continuar" - "Você está sendo desconectado" + "Este dispositivo está sendo removido" "Você tem %1$d tentativa de desbloqueio" "Você tem %1$d tentativas de desbloqueio" @@ -34,5 +34,5 @@ Escolha algo memorável. Se você esquecer este PIN, você será desconectado do "Usar biometria" "Usar PIN" - "Saindo…" + "Removendo dispositivo…" diff --git a/features/lockscreen/impl/src/main/res/values-ru/translations.xml b/features/lockscreen/impl/src/main/res/values-ru/translations.xml index cb71dfc88c..7bbdef1594 100644 --- a/features/lockscreen/impl/src/main/res/values-ru/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-ru/translations.xml @@ -15,9 +15,9 @@ "Используйте %1$s для разблокировки приложения" "Выберите PIN-код" "Подтвердите PIN-код" - "Установите блокировку на %1$s, чтобы повысить безопасность ваших чатов. + "Установите блокировку на %1$s, чтобы повысить безопасность Ваших чатов. -Выберите код, который трудно забыть. Если вы забудете PIN-код, вам придется выйти из приложения." +Выберите код, который трудно забыть. Если Вы забудете PIN-код, Вам придется выйти из аккаунта." "Этот PIN-код небезопасен." "Выбрать другой PIN-код" "Повторите PIN-код" @@ -25,14 +25,14 @@ "Чтобы продолжить, вам необходимо повторно войти в систему и создать новый PIN-код" "Это устройство удаляется" - "У вас осталась %1$d попытка разблокировки" - "У вас остались %1$d попытки разблокировки" - "У вас осталось %1$d попыток разблокировки" + "У Вас осталась %1$d попытка разблокировки" + "У Вас остались %1$d попытки разблокировки" + "У Вас осталось %1$d попыток разблокировки" - "Неверный PIN-код. У вас осталась %1$d попытка" - "Неверный PIN-код. У вас остались %1$d попытки" - "Неверный PIN-код. У вас осталось %1$d попыток" + "Неверный PIN-код. У Вас осталась %1$d попытка" + "Неверный PIN-код. У Вас остались %1$d попытки" + "Неверный PIN-код. У Вас осталось %1$d попыток" "Использовать биометрию" "Использовать PIN-код" diff --git a/features/lockscreen/impl/src/main/res/values-sk/translations.xml b/features/lockscreen/impl/src/main/res/values-sk/translations.xml index 14687f9272..e8fdf50bfd 100644 --- a/features/lockscreen/impl/src/main/res/values-sk/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-sk/translations.xml @@ -23,7 +23,7 @@ Vyberte si niečo zapamätateľné. Ak tento kód PIN zabudnete, budete z aplik "Zadajte prosím ten istý PIN dvakrát" "PIN kódy sa nezhodujú" "Ak chcete pokračovať, musíte sa znovu prihlásiť a vytvoriť nový PIN kód." - "Prebieha odhlasovanie" + "Toto zariadenie sa odstraňuje" "Máte %1$d pokus na odomknutie" "Máte %1$d pokusy na odomknutie" diff --git a/features/lockscreen/impl/src/main/res/values-uk/translations.xml b/features/lockscreen/impl/src/main/res/values-uk/translations.xml index 25e96003c8..e200a4ac21 100644 --- a/features/lockscreen/impl/src/main/res/values-uk/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-uk/translations.xml @@ -15,15 +15,15 @@ "Заощаджуйте час і використовуйте %1$s для розблокування застосунку щоразу" "Виберіть PIN-код" "Підтвердити PIN-код" - "Заблокуйте %1$s, щоб додати додаткову безпеку вашим чатам. + "Додаткове блокування %1$s поліпшить захист ваших бесід. -Виберіть щось, що запам\'ятовується. Але якщо ви забудете PIN-код, ви вийдете з застосунку." +Виберіть щось, що запам’ятовується. Але якщо ви забудете PIN-код, ви вийдете із застосунку." "Ви не можете вибрати його своїм PIN-кодом з міркувань безпеки" "Виберіть інший PIN-код" "Будь ласка, введіть один і той самий PIN-код двічі" "PIN-коди не збігаються" "Щоб продовжити, вам потрібно повторно ввійти та створити новий PIN-код" - "Ви виходите з системи" + "Цей пристрій вилучається" "Ви маєте %1$d спробу" "Ви маєте %1$d спроби" diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointIntentTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointIntentTest.kt index e99223735f..e2b410e663 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointIntentTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenEntryPointIntentTest.kt @@ -8,15 +8,13 @@ package io.element.android.features.lockscreen.impl -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.google.common.truth.Truth.assertThat import io.element.android.features.lockscreen.impl.unlock.activity.PinUnlockActivity +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultLockScreenEntryPointIntentTest { +class DefaultLockScreenEntryPointIntentTest : RobolectricTest() { @Test fun `test pin unlock intent`() { val entryPoint = DefaultLockScreenEntryPoint() diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt index 63729f941a..0fb2e9df8b 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticator.kt @@ -8,10 +8,18 @@ package io.element.android.features.lockscreen.impl.biometric +import io.element.android.tests.testutils.simulateLongTask + class FakeBiometricAuthenticator( override val isActive: Boolean = false, - private val authenticateLambda: suspend () -> BiometricAuthenticator.AuthenticationResult = { BiometricAuthenticator.AuthenticationResult.Success }, + private val setupLambda: () -> Unit = { }, + private val authenticateLambda: () -> BiometricAuthenticator.AuthenticationResult = { BiometricAuthenticator.AuthenticationResult.Success }, ) : BiometricAuthenticator { - override suspend fun setup() = Unit - override suspend fun authenticate() = authenticateLambda() + override suspend fun setup() = simulateLongTask { + setupLambda() + } + + override suspend fun authenticate() = simulateLongTask { + authenticateLambda() + } } diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt index 0ae8552334..1a70f25d30 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/biometric/FakeBiometricAuthenticatorManager.kt @@ -12,8 +12,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember class FakeBiometricAuthenticatorManager( - override var isDeviceSecured: Boolean = true, - override var hasAvailableAuthenticator: Boolean = false, + override val isDeviceSecured: Boolean = true, + override val canUseDeviceUnlock: Boolean = true, + override val hasAvailableAuthenticator: Boolean = false, private val createBiometricAuthenticator: () -> BiometricAuthenticator = { FakeBiometricAuthenticator() }, private val disableLambda: suspend () -> Unit = { }, ) : BiometricAuthenticatorManager { @@ -28,7 +29,14 @@ class FakeBiometricAuthenticatorManager( @Composable override fun rememberUnlockBiometricAuthenticator(): BiometricAuthenticator { return remember { - createBiometricAuthenticator() + createBiometricAuthenticator() + } + } + + @Composable + override fun rememberUnlockDeviceBiometricAuthenticator(): BiometricAuthenticator { + return remember { + createBiometricAuthenticator() } } diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt new file mode 100644 index 0000000000..52aeaa04a8 --- /dev/null +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/device/DeviceUnlockPresenterTest.kt @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package io.element.android.features.lockscreen.impl.device + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.lockscreen.impl.biometric.BiometricAuthenticator +import io.element.android.features.lockscreen.impl.biometric.FakeBiometricAuthenticator +import io.element.android.features.lockscreen.impl.biometric.FakeBiometricAuthenticatorManager +import io.element.android.features.lockscreen.impl.fixtures.aPinCodeManager +import io.element.android.features.lockscreen.impl.pin.PinCodeManager +import io.element.android.features.lockscreen.impl.unlock.PinUnlockHelper +import io.element.android.features.lockscreen.test.FakeDeviceUnlockEntryPointCallback +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.test +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class DeviceUnlockPresenterTest { + @Test + fun `present - when unlock requested and device unlock available, use biometric authenticator`() = runTest { + val setupLambda = lambdaRecorder { } + val authenticateLambda = lambdaRecorder { + BiometricAuthenticator.AuthenticationResult.Success + } + val fakeBiometricAuthenticator = FakeBiometricAuthenticator( + setupLambda = setupLambda, + authenticateLambda = authenticateLambda, + ) + val biometricAuthenticatorManager = FakeBiometricAuthenticatorManager( + canUseDeviceUnlock = true, + createBiometricAuthenticator = { fakeBiometricAuthenticator }, + ) + val callbackHolder = DeviceUnlockCallbackHolder() + val callback = FakeDeviceUnlockEntryPointCallback() + + createDeviceUnlockPresenter( + biometricAuthenticatorManager = biometricAuthenticatorManager, + callbackHolder = callbackHolder, + ).test { + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + callbackHolder.requestUnlock(callback) + advanceUntilIdle() + setupLambda.assertions().isCalledOnce() + authenticateLambda.assertions().isCalledOnce() + skipItems(1) + } + } + + @Test + fun `present - when unlock requested and device unlock unavailable and app pin is configured, show app pin`() = runTest { + val callbackHolder = DeviceUnlockCallbackHolder() + val callback = FakeDeviceUnlockEntryPointCallback() + val pinCodeManager = aPinCodeManager().apply { + createPinCode("1234") + } + createDeviceUnlockPresenter( + biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), + callbackHolder = callbackHolder, + pinCodeManager = pinCodeManager, + ).test { + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + + callbackHolder.requestUnlock(callback) + skipItems(1) + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isTrue() + } + } + } + + @Test + fun `present - when unlock requested and no security, unlock immediately`() = runTest { + val callbackHolder = DeviceUnlockCallbackHolder() + val onUnlockedLambda = lambdaRecorder { } + val callback = FakeDeviceUnlockEntryPointCallback( + onUnlockedLambda = onUnlockedLambda, + ) + createDeviceUnlockPresenter( + biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), + callbackHolder = callbackHolder, + ).test { + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + callbackHolder.requestUnlock(callback) + skipItems(2) + assertThat(callbackHolder.deviceUnlockCallback.value).isNull() + onUnlockedLambda.assertions().isCalledOnce() + } + } + + @Test + fun `present - CancelPinCode event cancels unlock request`() = runTest { + val callbackHolder = DeviceUnlockCallbackHolder() + val onCancelLambda = lambdaRecorder { } + val callback = FakeDeviceUnlockEntryPointCallback( + onCancelLambda = onCancelLambda, + ) + val pinCodeManager = aPinCodeManager().apply { + createPinCode("1234") + } + createDeviceUnlockPresenter( + biometricAuthenticatorManager = FakeBiometricAuthenticatorManager(canUseDeviceUnlock = false), + callbackHolder = callbackHolder, + pinCodeManager = pinCodeManager, + ).test { + awaitItem() + callbackHolder.requestUnlock(callback) + skipItems(1) + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isTrue() + state.eventSink(DeviceUnlockEvent.CancelPinCode) + } + awaitItem().also { state -> + assertThat(state.showApplicationPinCode).isFalse() + } + skipItems(1) + onCancelLambda.assertions().isCalledOnce() + assertThat(callbackHolder.deviceUnlockCallback.value).isNull() + } + } + + private fun createDeviceUnlockPresenter( + biometricAuthenticatorManager: FakeBiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(), + callbackHolder: DeviceUnlockCallbackHolder = DeviceUnlockCallbackHolder(), + pinCodeManager: PinCodeManager = aPinCodeManager(), + ): DeviceUnlockPresenter { + val pinUnlockHelper = PinUnlockHelper( + biometricAuthenticatorManager = biometricAuthenticatorManager, + pinCodeManager = pinCodeManager, + ) + return DeviceUnlockPresenter( + pinUnlockHelper = pinUnlockHelper, + biometricAuthenticatorManager = biometricAuthenticatorManager, + deviceUnlockCallbackHolder = callbackHolder, + pinCodeManager = pinCodeManager, + ) + } +} diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt index fa7d05b5cb..b20a99d27f 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenterTest.kt @@ -147,11 +147,37 @@ class PinUnlockPresenterTest { } } + @Test + fun `present - forDeviceUnlock is exposed in state`() = runTest { + val presenter = createPinUnlockPresenter(forDeviceUnlock = true) + presenter.test { + skipItems(1) + awaitItem().also { state -> + assertThat(state.canNavigateBack).isTrue() + } + } + } + + @Test + fun `present - pin entry changed event updates pin entry`() = runTest { + val presenter = createPinUnlockPresenter() + presenter.test { + skipItems(1) + awaitItem().also { state -> + state.eventSink(PinUnlockEvent.OnPinEntryChanged(halfCompletePin)) + } + awaitItem().also { state -> + state.pinEntry.assertText(halfCompletePin) + } + } + } + private fun AsyncData.assertText(text: String) { dataOrNull()?.assertText(text) } private suspend fun TestScope.createPinUnlockPresenter( + forDeviceUnlock: Boolean = false, biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(), callback: PinCodeManager.Callback = DefaultPinCodeManagerCallback(), logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase(logoutLambda = {}), @@ -162,6 +188,7 @@ class PinUnlockPresenterTest { createPinCode(completePin) } return PinUnlockPresenter( + forDeviceUnlock = forDeviceUnlock, pinCodeManager = pinCodeManager, biometricAuthenticatorManager = biometricAuthenticatorManager, logoutUseCase = logoutUseCase, diff --git a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypadTest.kt b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypadTest.kt index e6d1659778..fb7d3aa372 100644 --- a/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypadTest.kt +++ b/features/lockscreen/impl/src/test/kotlin/io/element/android/features/lockscreen/impl/unlock/keypad/PinKeypadTest.kt @@ -28,12 +28,10 @@ import androidx.compose.ui.unit.dp import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class PinKeypadTest { +class PinKeypadTest : RobolectricTest() { @Test fun `clicking on a number emits the expected event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPoint.kt b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPoint.kt new file mode 100644 index 0000000000..8278fc882f --- /dev/null +++ b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPoint.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.test + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import io.element.android.tests.testutils.lambda.lambdaError + +class FakeDeviceUnlockEntryPoint : DeviceUnlockEntryPoint { + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + ): Node = lambdaError() + + override fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) = lambdaError() +} diff --git a/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt new file mode 100644 index 0000000000..3b7394cae0 --- /dev/null +++ b/features/lockscreen/test/src/main/kotlin/io/element/android/features/lockscreen/test/FakeDeviceUnlockEntryPointCallback.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.lockscreen.test + +import io.element.android.features.lockscreen.api.DeviceUnlockEntryPoint +import io.element.android.tests.testutils.EnsureNeverCalled + +class FakeDeviceUnlockEntryPointCallback( + private val onCancelLambda: () -> Unit = EnsureNeverCalled(), + private val onUnlockedLambda: () -> Unit = EnsureNeverCalled(), +) : DeviceUnlockEntryPoint.Callback { + override fun onCancel() = onCancelLambda() + override fun onUnlock() = onUnlockedLambda() +} diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt index d3641ea749..feb1d3d53a 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt @@ -60,6 +60,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.PasswordVisibilityToggle import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.designsystem.theme.components.TopAppBar @@ -249,16 +250,10 @@ private fun LoginForm( placeholder = stringResource(CommonStrings.common_password), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { - val image = - if (passwordVisible) CompoundIcons.VisibilityOn() else CompoundIcons.VisibilityOff() - val description = - if (passwordVisible) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password) - Box(Modifier.clickable { passwordVisible = !passwordVisible }) { - Icon( - imageVector = image, - contentDescription = description, - ) - } + PasswordVisibilityToggle( + visible = passwordVisible, + onToggle = { passwordVisible = !passwordVisible }, + ) }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Password, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt index 53c36ac4f8..420bb61475 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.login.impl.R @@ -55,11 +54,9 @@ import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings -// Refs: -// FTUE: -// - https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?type=design&node-id=133-5427&t=5SHVppfYzjvkEywR-0 -// ElementX: -// - https://www.figma.com/file/0MMNu7cTOzLOlWb7ctTkv3/Element-X?type=design&node-id=1816-97419 +/** + * Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=41-6503 + */ @Composable fun OnBoardingView( state: OnBoardingState, @@ -223,14 +220,14 @@ private fun OnBoardingContent(state: OnBoardingState) { text = stringResource(id = R.string.screen_onboarding_welcome_title), color = ElementTheme.colors.textPrimary, style = ElementTheme.typography.fontHeadingLgBold, - textAlign = TextAlign.Center + textAlign = TextAlign.Center, ) Spacer(modifier = Modifier.height(8.dp)) Text( text = stringResource(id = R.string.screen_onboarding_welcome_message, state.productionApplicationName), - color = ElementTheme.colors.textSecondary, - style = ElementTheme.typography.fontBodyLgRegular.copy(fontSize = 17.sp), - textAlign = TextAlign.Center + color = ElementTheme.colors.textPrimary, + style = ElementTheme.typography.fontBodyLgRegular, + textAlign = TextAlign.Center, ) } } diff --git a/features/login/impl/src/main/res/values-be/translations.xml b/features/login/impl/src/main/res/values-be/translations.xml index d9d69503c5..5018377eb0 100644 --- a/features/login/impl/src/main/res/values-be/translations.xml +++ b/features/login/impl/src/main/res/values-be/translations.xml @@ -20,7 +20,7 @@ "Які адрас вашага сервера?" "Выберыце свой сервер" "Стварыць уліковы запіс" - "Гэты ўліковы запіс быў дэактываваны." + "Гэты ўліковы запіс быў выдалены." "Няправільнае імя карыстальніка і/або пароль" "Гэта несапраўдны ідэнтыфікатар карыстальніка. Чаканы фармат: ‘@user:homeserver.org’" "Гэты сервер настроены на выкарыстанне маркераў абнаўлення. Яны не падтрымліваюцца пры ўваходзе на аснове пароля." @@ -29,6 +29,7 @@ "Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі." "Сардэчна запрашаем!" "Увайсці ў %1$s" + "Версія %1$s" "Увайсці ўручную" "Увайсці ў %1$s" "Увайсці з QR-кодам" diff --git a/features/login/impl/src/main/res/values-el/translations.xml b/features/login/impl/src/main/res/values-el/translations.xml index 045465902b..9852eac5cc 100644 --- a/features/login/impl/src/main/res/values-el/translations.xml +++ b/features/login/impl/src/main/res/values-el/translations.xml @@ -45,6 +45,7 @@ "Επιστρέψτε στο %1$s" "Ενεργοποιήστε την αποθήκευση κλειδιών σας πριν προχωρήσετε στο %1$s" "Έκδοση %1$s" + "Έλεγχος λογαριασμού" "Σύνδεση χειροκίνητα" "Συνδέσου στο %1$s" "Συνδέσου με κωδικό QR" diff --git a/features/login/impl/src/main/res/values-ko/translations.xml b/features/login/impl/src/main/res/values-ko/translations.xml index 338ba628c9..8f313b15ee 100644 --- a/features/login/impl/src/main/res/values-ko/translations.xml +++ b/features/login/impl/src/main/res/values-ko/translations.xml @@ -28,7 +28,7 @@ "서버의 주소는 무엇인가요?" "서버 선택" "계정 만들기" - "계정이 비활성화되었습니다." + "삭제된 계정입니다." "잘못된 아이디/비밀번호" "이 사용자 ID는 유효하지 않습니다. 예상 형식: ‘@user:homeserver.org’" "이 서버는 새로 고침 토큰을 사용하도록 구성되어 있습니다. 비밀번호 기반 로그인을 사용하는 경우 이 기능은 지원되지 않습니다." @@ -45,6 +45,7 @@ "%1$s(으)로 돌아가기" "%1$s(으)로 진행하기 전에 키 저장소를 활성화해 주세요." "버전 %1$s" + "계정 확인 중" "수동으로 로그인" "%1$s 에 로그인합니다" "QR 코드로 로그인" diff --git a/features/login/impl/src/main/res/values-pl/translations.xml b/features/login/impl/src/main/res/values-pl/translations.xml index ca0d035fe0..634d856cdf 100644 --- a/features/login/impl/src/main/res/values-pl/translations.xml +++ b/features/login/impl/src/main/res/values-pl/translations.xml @@ -97,7 +97,7 @@ Spróbuj zalogować się ręcznie lub zeskanuj kod QR na innym urządzeniu.""Zacznij od nowa" "Wystąpił nieoczekiwany błąd. Spróbuj ponownie." "Oczekiwanie na drugie urządzenie" - "Twój dostawca konta może poprosić o podany kod, aby zweryfikować logowanie." + "Twój dostawca konta może poprosić o podany kod w celu weryfikacji logowania." "Twój kod weryfikacyjny" "Zmień dostawcę konta" "Serwer prywatny dla pracowników Element." diff --git a/features/login/impl/src/main/res/values-pt-rBR/translations.xml b/features/login/impl/src/main/res/values-pt-rBR/translations.xml index ad2ad2b5fb..a789cc766c 100644 --- a/features/login/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/login/impl/src/main/res/values-pt-rBR/translations.xml @@ -28,7 +28,7 @@ "Qual é o endereço do seu servidor?" "Selecione seu servidor" "Criar conta" - "Essa conta foi desativada." + "Essa conta foi apagada." "Nome de usuário e/ou senha incorretos" "Esse não é um identificador de usuário válido. Formato esperado: \'@usuário:servidor.org\'" "Este servidor está configurado para usar tokens recarregados. Não há suporte a eles ao entrar por uma senha." diff --git a/features/login/impl/src/main/res/values-ru/translations.xml b/features/login/impl/src/main/res/values-ru/translations.xml index 564fc87cac..5afbe1f513 100644 --- a/features/login/impl/src/main/res/values-ru/translations.xml +++ b/features/login/impl/src/main/res/values-ru/translations.xml @@ -35,7 +35,7 @@ "Выбранный сервер не поддерживает вход по паролю и OAuth. Пожалуйста, свяжитесь с администратором или выберите другой сервер." "Введите свои данные" "Matrix — это открытая сеть для безопасной децентрализованной связи." - "Рады видеть вас снова!" + "Рады видеть Вас снова!" "Войти в %1$s" "Открыть Element Classic" "Откройте Element Classic на своем устройстве." @@ -69,9 +69,9 @@ "Запрос на вход отменен" "Вход в систему был отклонен на другом устройстве." "Вход отклонен" - "На этом все." + "На этом всё." "Вход уже выполнен на другом устройстве" - "Срок действия входа истек. Пожалуйста, попробуйте еще раз." + "Срок действия входа истек. Пожалуйста, попробуйте ещё раз." "Вход в систему не был выполнен вовремя" "Другое устройство не поддерживает вход в %s с помощью QR-кода. @@ -95,7 +95,7 @@ "Разрешите доступ к камере для сканирования QR-кода" "Сканировать QR-код" "Начать заново" - "Произошла непредвиденная ошибка. Пожалуйста, попробуйте еще раз." + "Произошла непредвиденная ошибка. Пожалуйста, попробуйте ещё раз." "Ожидание другого устройства" "Сервер для аккаунта может запросить следующий код для подтверждения входа." "Ваш код подтверждения" diff --git a/features/login/impl/src/main/res/values-uk/translations.xml b/features/login/impl/src/main/res/values-uk/translations.xml index 17632cc4fc..60959c80d4 100644 --- a/features/login/impl/src/main/res/values-uk/translations.xml +++ b/features/login/impl/src/main/res/values-uk/translations.xml @@ -51,9 +51,9 @@ "Увійти за допомогою QR-коду" "Створити обліковий запис" "З поверненням!" - "Ласкаво просимо до найшвидшого %1$s. Заряджений для швидкості та простоти." - "Ласкаво просимо до %1$s. Заряджений, для швидкості та простоти." - "Будьте у своєму element" + "Вітаємо в %1$s. Сфокусованому на швидкості та простоті." + "Вітаємо у %1$s. Сфокусованому на швидкості та простоті." + "Спілкуйтесь елементарно" "Встановлення безпечного з\'єднання" "Не вдалося встановити безпечне з\'єднання з новим пристроєм. Ваші наявні пристрої досі в безпеці, і вам не потрібно про них турбуватися." "Що тепер?" diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt index 21b3cca600..feeeb982c4 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginIntentResolverTest.kt @@ -8,14 +8,12 @@ package io.element.android.features.login.impl -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.features.login.api.LoginParams +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultLoginIntentResolverTest { +class DefaultLoginIntentResolverTest : RobolectricTest() { @Test fun `nominal case`() { val sut = DefaultLoginIntentResolver() diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/classic/DefaultElementClassicConnectionTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/classic/DefaultElementClassicConnectionTest.kt index 8ea1b2e3d3..702adaaa6d 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/classic/DefaultElementClassicConnectionTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/classic/DefaultElementClassicConnectionTest.kt @@ -28,17 +28,15 @@ import io.element.android.libraries.matrix.test.auth.FakeHomeServerLoginCompatib import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultElementClassicConnectionTest { +class DefaultElementClassicConnectionTest : RobolectricTest() { @Test fun `connection can be started Element Classic service can be bound`() = runTest { val connection = createDefaultElementClassicConnection( diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt index 112d8d7108..c56b4d5208 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt @@ -8,7 +8,6 @@ package io.element.android.features.login.impl.qrcode -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.bumble.appyx.core.modality.AncestryInfo import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.utils.customisations.NodeCustomisationDirectoryImpl @@ -22,16 +21,15 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.matrix.test.auth.qrlogin.FakeMatrixQrCodeLoginData import io.element.android.tests.testutils.lambda.lambdaError +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class QrCodeLoginFlowNodeTest { +class QrCodeLoginFlowNodeTest : RobolectricTest() { @Test fun `backstack changes when confirmation steps are received`() = runTest { val qrCodeLoginManager = FakeQrCodeLoginManager() diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt index 61ec7cc698..b036e07e92 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.login.impl.accountprovider.anAccountProvider import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.auth.OAuthDetails @@ -28,12 +27,11 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class ChooseAccountProviderViewTest { +class ChooseAccountProviderViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventSink = EventsRecorder(expectEvents = false) diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNodeHelperTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNodeHelperTest.kt index 017fd1b633..805e3c10b6 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNodeHelperTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNodeHelperTest.kt @@ -10,7 +10,6 @@ package io.element.android.features.login.impl.screens.classic import androidx.core.graphics.createBitmap -import androidx.test.ext.junit.runners.AndroidJUnit4 import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.login.impl.classic.ElementClassicConnection @@ -26,16 +25,15 @@ import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.test.InMemorySessionStore import io.element.android.libraries.sessionstorage.test.aSessionData import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -// Use AndroidJUnit4 for the test with the Bitmap. -@RunWith(AndroidJUnit4::class) -class ClassicFlowNodeHelperTest { +// Use RobolectricTest for the test with the Bitmap. +class ClassicFlowNodeHelperTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordViewTest.kt index c0e7e5c378..3a128f2e4f 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordViewTest.kt @@ -23,7 +23,6 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.matrix.test.A_PASSWORD import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.testtags.TestTags @@ -33,12 +32,11 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class LoginPasswordViewTest { +class LoginPasswordViewTest : RobolectricTest() { @Test fun `clicking on back invoke back callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/DefaultOnBoardingLogoResIdProviderTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/DefaultOnBoardingLogoResIdProviderTest.kt index 6e67925444..337f2d659c 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/DefaultOnBoardingLogoResIdProviderTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/DefaultOnBoardingLogoResIdProviderTest.kt @@ -8,14 +8,12 @@ package io.element.android.features.login.impl.screens.onboarding -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.google.common.truth.Truth.assertThat +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultOnBoardingLogoResIdProviderTest { +class DefaultOnBoardingLogoResIdProviderTest : RobolectricTest() { @Test fun `when onboarding_logo resource does not exist, get() returns null`() { val context = InstrumentationRegistry.getInstrumentation().context diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt index bcb62ea707..52d1667687 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt @@ -32,12 +32,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTestParameter import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestParameterInjector -@RunWith(RobolectricTestParameterInjector::class) -class OnboardingViewTest { +class OnboardingViewTest : RobolectricTestParameter() { @Test fun `when can create account - clicking on create account calls the expected callback`() = runAndroidComposeUiTest { val eventSink = EventsRecorder(expectEvents = false) diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/confirmation/QrCodeConfirmationViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/confirmation/QrCodeConfirmationViewTest.kt index 79566625c5..8c1802a3c5 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/confirmation/QrCodeConfirmationViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/confirmation/QrCodeConfirmationViewTest.kt @@ -14,16 +14,14 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class QrCodeConfirmationViewTest { +class QrCodeConfirmationViewTest : RobolectricTest() { @Test fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/error/QrCodeErrorViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/error/QrCodeErrorViewTest.kt index 2ae68c3485..976d98c594 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/error/QrCodeErrorViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/error/QrCodeErrorViewTest.kt @@ -14,18 +14,16 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.login.impl.qrcode.QrCodeErrorScreenType import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class QrCodeErrorViewTest { +class QrCodeErrorViewTest : RobolectricTest() { @Test fun `on back pressed - calls the onCancel callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt index c6812d3759..5720c68ab4 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/intro/QrCodeIntroViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.login.impl.R import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder @@ -22,11 +21,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class QrCodeIntroViewTest { +class QrCodeIntroViewTest : RobolectricTest() { @Test fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/scan/QrCodeScanViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/scan/QrCodeScanViewTest.kt index bde960ef1a..c0c7c084a8 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/scan/QrCodeScanViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/qrcode/scan/QrCodeScanViewTest.kt @@ -15,7 +15,6 @@ import androidx.camera.lifecycle.ProcessCameraProvider import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData @@ -25,13 +24,12 @@ import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.After import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class QrCodeScanViewTest { +class QrCodeScanViewTest : RobolectricTest() { private var provider: ProcessCameraProvider? = null @Before diff --git a/features/logout/impl/src/main/res/values-be/translations.xml b/features/logout/impl/src/main/res/values-be/translations.xml index bc005e2bd2..0aab51833f 100644 --- a/features/logout/impl/src/main/res/values-be/translations.xml +++ b/features/logout/impl/src/main/res/values-be/translations.xml @@ -1,9 +1,9 @@ - "Вы ўпэўнены, што хочаце выйсці?" + "Вы ўпэўненыя, што хочаце выдаліць гэту прыладу?" "Выйсці" "Выйсці" - "Выхад…" + "Выдаленне прылады…" "Вы збіраецеся выйсці з апошняга сеанса. Калі вы выйдзеце з сістэмы зараз, вы страціце доступ да зашыфраваных паведамленняў." "Вы адключылі рэзервовае капіраванне" "Вашы ключы ўсё яшчэ захоўваліся, калі вы выйшлі з сеткі. Паўторна падключыцеся, каб можна было стварыць рэзервовую копію вашых ключоў перад выхадам." diff --git a/features/logout/impl/src/main/res/values-in/translations.xml b/features/logout/impl/src/main/res/values-in/translations.xml index 9d63573973..718cadd21b 100644 --- a/features/logout/impl/src/main/res/values-in/translations.xml +++ b/features/logout/impl/src/main/res/values-in/translations.xml @@ -5,14 +5,14 @@ "Hapus device dari akun" "Mengeluarkan device dari akun…" "Anda akan keluar dari sesi terakhir Anda. Jika Anda keluar sekarang, Anda akan kehilangan akses ke pesan terenkripsi Anda." - "Anda telah menonaktifkan pencadangan" - "Kunci Anda masih dicadangkan saat Anda luring. Sambungkan kembali sehingga kunci Anda dapat dicadangkan sebelum keluar." + "Anda akan segera kehilangan akses ke obrolan terenkripsi Anda." + "Kunci Anda masih dalam proses pencadangan saat Anda offline. Sambungkan kembali agar kunci Anda dapat dicadangkan sebelum Anda menghapus perangkat ini." "Kunci Anda masih dicadangkan" - "Mohon tunggu hingga proses ini selesai sebelum keluar." + "Harap tunggu hingga proses ini selesai sebelum melepas perangkat ini." "Kunci Anda masih dicadangkan" "Hapus device dari akun" "Anda akan keluar dari sesi Anda yang terakhir. Jika Anda keluar sekarang, Anda akan kehilangan akses ke pesan terenkripsi Anda." - "Pemulihan belum disiapkan" + "Anda akan segera kehilangan akses ke obrolan terenkripsi Anda." "Anda akan keluar dari sesi terakhir Anda. Jika Anda keluar sekarang, Anda mungkin kehilangan akses ke pesan terenkripsi Anda." - "Apakah Anda sudah menyimpan kunci pemulihan Anda?" + "Pastikan Anda memiliki akses ke kunci pemulihan sebelum mencabut perangkat ini." diff --git a/features/logout/impl/src/main/res/values-pt-rBR/translations.xml b/features/logout/impl/src/main/res/values-pt-rBR/translations.xml index b12a2aa470..b7b1728313 100644 --- a/features/logout/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/logout/impl/src/main/res/values-pt-rBR/translations.xml @@ -1,18 +1,18 @@ - "Você tem certeza que deseja sair?" - "Sair" - "Sair" - "Saindo…" + "Você tem certeza que deseja remover este dispositivo?" + "Remover este dispositivo" + "Remover este dispositivo" + "Removendo dispositivo…" "Você está prestes a sair da sua última sessão. Se você sair agora, perderá o acesso às suas mensagens criptografadas." "Você desativou o backup" "O backup das suas chaves ainda estava sendo feito quando você ficou off-line. Reconecte-se para que você possa fazer o backup de suas chaves antes de sair." "O backup das suas chaves ainda está em andamento" "Aguarde até que isso seja concluído antes de sair." "O backup das suas chaves ainda está em andamento" - "Sair" + "Remover este dispositivo" "Você está prestes a sair da sua última sessão. Se você sair agora, perderá o acesso às suas mensagens criptografadas." - "A recuperação não está configurada" + "Você está prestes a perder o acesso às suas conversas criptografadas" "Você está prestes a sair da sua última sessão. Se você sair agora, poderá perder o acesso às suas mensagens criptografadas." "Você salvou sua chave de recuperação?" diff --git a/features/logout/impl/src/main/res/values-ru/translations.xml b/features/logout/impl/src/main/res/values-ru/translations.xml index d96b8f24f2..fde2aadcab 100644 --- a/features/logout/impl/src/main/res/values-ru/translations.xml +++ b/features/logout/impl/src/main/res/values-ru/translations.xml @@ -7,9 +7,9 @@ "Это ваше единственное устройство. Если вы его удалите, вам потребуется ключ восстановления, чтобы подтвердить свою цифровую личность и восстановить зашифрованные чаты при следующем входе в систему." "Вы потеряете доступ к своим зашифрованным чатам" "Когда вы отключились от сети, резервное копирование ваших ключей продолжалось. Подключитесь снова, чтобы резервная копия ваших ключей была создана, прежде чем вы отключите это устройство." - "Резервное копирование ключей все еще продолжается" + "Резервное копирование ключей всё ещё продолжается" "Пожалуйста, дождитесь завершения процесса, прежде чем выходить из системы." - "Резервное копирование ключей все еще продолжается" + "Резервное копирование ключей всё ещё продолжается" "Удалить это устройство" "Это ваше единственное устройство. Если вы его удалите, вам потребуется ключ восстановления, чтобы подтвердить свою цифровую личность и восстановить зашифрованные чаты при следующем входе в систему." "Вы потеряете доступ к своим зашифрованным чатам" diff --git a/features/logout/impl/src/main/res/values-sk/translations.xml b/features/logout/impl/src/main/res/values-sk/translations.xml index 4fe07b2fa7..28e0a05c2f 100644 --- a/features/logout/impl/src/main/res/values-sk/translations.xml +++ b/features/logout/impl/src/main/res/values-sk/translations.xml @@ -12,7 +12,7 @@ "Vaše kľúče sa ešte stále zálohujú" "Odstrániť toto zariadenie" "Chystáte sa odhlásiť z vašej poslednej relácie. Ak sa teraz odhlásite, stratíte prístup k svojim šifrovaným správam." - "Obnovenie nie je nastavené" + "Čoskoro stratíte prístup k svojim zašifrovaným konverzáciám" "Chystáte sa odhlásiť z vašej poslednej relácie. Ak sa teraz odhlásite, môžete stratiť prístup k svojim šifrovaným správam." "Uložili ste si kľúč na obnovenie?" diff --git a/features/logout/impl/src/main/res/values-uk/translations.xml b/features/logout/impl/src/main/res/values-uk/translations.xml index f012603533..c227ffeee6 100644 --- a/features/logout/impl/src/main/res/values-uk/translations.xml +++ b/features/logout/impl/src/main/res/values-uk/translations.xml @@ -1,18 +1,18 @@ "Ви впевнені, що хочете видалити цей пристрій?" - "Вийти" - "Вийти" + "Вилучити цей пристрій" + "Вилучити цей пристрій" "Видалення пристрою…" - "Ви збираєтеся вийти зі свого останнього сеансу. Якщо ви вийдете зараз, ви втратите доступ до своїх зашифрованих повідомлень." - "Ви вимкнули резервне копіювання" - "Коли ви вийшли з мережі, резервна копія ваших ключів все ще створювалася. Повторно під\'єднайтеся, щоб зберегти резервну копію ключів перед виходом." + "Це ваш єдиний пристрій. Якщо ви його вилучите, вам знадобиться ключ відновлення, щоб підтвердити свою цифрову ідентичність і відновити зашифровані бесіди під час наступного входу." + "Ви втратите доступ до своїх зашифрованих бесід" + "Резервні копії ваших ключів продовжували створюватися після вашого виходу з мережі. Під\'єднайтеся знову, щоб створити резервні копії ключів, перш ніж вилучати цей пристрій." "Резервне копіювання ваших ключів ще триває" - "Дочекайтеся завершення процесу, перш ніж вийти." + "Дочекайтесь завершення, перш ніж вилучити цей пристрій." "Резервне копіювання ваших ключів ще триває" - "Вийти" - "Ви збираєтеся вийти зі свого останнього сеансу. Якщо ви вийдете зараз, ви втратите доступ до своїх зашифрованих повідомлень." - "Відновлення не налаштовано" - "Ви збираєтеся вийти зі свого останнього сеансу. Якщо вийти зараз, ви можете втратити доступ до зашифрованих повідомлень." - "Ви зберегли ключ відновлення?" + "Вилучити цей пристрій" + "Це ваш єдиний пристрій. Якщо ви вилучите його, вам знадобиться ключ відновлення, щоб підтвердити свою цифрову ідентичність і відновити зашифровані бесіди під час наступного входу." + "Ви втратите доступ до своїх зашифрованих бесід" + "Це ваш єдиний пристрій. Якщо ви його вилучите, вам знадобиться ключ відновлення, щоб підтвердити свою цифрову ідентичність і відновити зашифровані бесіди під час наступного входу." + "Переконайтеся, що у вас є доступ до ключа відновлення, перш ніж вилучити цей пристрій" diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt index a42fd891d4..3fbae4bbc5 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.ui.strings.CommonStrings @@ -24,11 +23,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressTag +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class LogoutViewTest { +class LogoutViewTest : RobolectricTest() { @Test fun `clicking on logout sends a LogoutEvents`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutViewTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutViewTest.kt index 99860259c4..db8eed2a54 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutViewTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.logout.api.direct.DirectLogoutEvents import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.features.logout.api.direct.aDirectLogoutState @@ -23,12 +22,11 @@ import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Ignore import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultDirectLogoutViewTest { +class DefaultDirectLogoutViewTest : RobolectricTest() { @Test fun `clicking on confirm logout sends expected Event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index d20dc4b38e..cbab26fe54 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -11,6 +11,9 @@ package io.element.android.features.messages.impl import android.os.Parcelable import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.lifecycle.lifecycleScope import com.bumble.appyx.core.lifecycle.subscribe @@ -29,6 +32,7 @@ import io.element.android.features.call.api.ElementCallEntryPoint import io.element.android.features.forward.api.ForwardEntryPoint import io.element.android.features.knockrequests.api.list.KnockRequestsListEntryPoint import io.element.android.features.location.api.LocationService +import io.element.android.features.location.api.RenderingMapsNotSupportedDialog import io.element.android.features.location.api.ShareLocationEntryPoint import io.element.android.features.location.api.ShowLocationEntryPoint import io.element.android.features.location.api.ShowLocationMode @@ -43,9 +47,12 @@ import io.element.android.features.messages.impl.threads.list.ThreadsListNode import io.element.android.features.messages.impl.timeline.TimelineController import io.element.android.features.messages.impl.timeline.debug.EventDebugInfoNode import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.model.event.GalleryItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent @@ -53,6 +60,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.duration import io.element.android.features.poll.api.create.CreatePollEntryPoint import io.element.android.features.poll.api.create.CreatePollMode +import io.element.android.libraries.androidutils.system.DeviceHasVulkanSupport import io.element.android.libraries.architecture.BackstackWithOverlayBox import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.callback @@ -81,6 +89,8 @@ import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache import io.element.android.libraries.matrix.ui.messages.RoomNamesCache +import io.element.android.libraries.mediaviewer.api.GalleryInfo +import io.element.android.libraries.mediaviewer.api.GalleryItemData import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.textcomposer.mentions.LocalMentionSpanUpdater @@ -121,6 +131,7 @@ class MessagesFlowNode( private val knockRequestsListEntryPoint: KnockRequestsListEntryPoint, private val dateFormatter: DateFormatter, private val coroutineDispatchers: CoroutineDispatchers, + private val hasVulkanSupport: DeviceHasVulkanSupport, ) : BaseFlowNode( backstack = BackStack( initialElement = plugins.filterIsInstance().first().initialTarget.toNavTarget(), @@ -147,7 +158,16 @@ class MessagesFlowNode( ) : NavTarget @Parcelize - data class AttachmentPreview(val timelineMode: Timeline.Mode, val attachment: Attachment, val inReplyToEventId: EventId?) : NavTarget + data class GalleryViewer( + val fromPinnedMessages: Boolean, + val eventId: EventId?, + val galleryInfo: GalleryInfo, + val canUseOverlay: Boolean, + val galleryItems: List = emptyList(), + ) : NavTarget + + @Parcelize + data class AttachmentPreview(val timelineMode: Timeline.Mode, val attachments: ImmutableList, val inReplyToEventId: EventId?) : NavTarget @Parcelize data class LocationViewer(val mode: ShowLocationMode) : NavTarget @@ -184,10 +204,15 @@ class MessagesFlowNode( @Parcelize data object ThreadsList : NavTarget + + @Parcelize + data class AvatarPreview(val name: String, val avatarUrl: String) : NavTarget } private val callback: MessagesEntryPoint.Callback = callback() + private var displayVulkanNotSupportedError by mutableStateOf(false) + override fun onBuilt() { super.onBuilt() lifecycle.subscribe( @@ -228,7 +253,11 @@ class MessagesFlowNode( callback.navigateToRoomDetails() } - override fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean { + override fun handleEventClick( + timelineMode: Timeline.Mode, + event: TimelineItem.Event, + canUseOverlay: Boolean, + ): Boolean { return processEventClick( timelineMode = timelineMode, event = event, @@ -236,10 +265,24 @@ class MessagesFlowNode( ) } + override fun handleGalleryItemClick( + timelineMode: Timeline.Mode, + event: TimelineItem.Event, + galleryItemIndex: Int, + canUseOverlay: Boolean, + ): Boolean { + return processGalleryEventClick( + timelineMode = timelineMode, + event = event, + canUseOverlay = canUseOverlay, + galleryItemIndex = galleryItemIndex, + ) + } + override fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) { backstack.push( NavTarget.AttachmentPreview( - attachment = attachments.first(), + attachments = attachments, timelineMode = Timeline.Mode.Live, inReplyToEventId = inReplyToEventId, ) @@ -267,7 +310,11 @@ class MessagesFlowNode( } override fun navigateToSendLocation() { - backstack.push(NavTarget.SendLocation(Timeline.Mode.Live)) + if (hasVulkanSupport()) { + backstack.push(NavTarget.SendLocation(Timeline.Mode.Live)) + } else { + displayVulkanNotSupportedError = true + } } override fun navigateToCreatePoll() { @@ -279,7 +326,11 @@ class MessagesFlowNode( } override fun navigateToCurrentLiveLocation() { - backstack.push(NavTarget.LocationViewer(ShowLocationMode.Live(senderId = sessionId))) + if (hasVulkanSupport()) { + backstack.push(NavTarget.LocationViewer(ShowLocationMode.Live(senderId = sessionId))) + } else { + displayVulkanNotSupportedError = true + } } override fun navigateToRoomCall(roomId: RoomId, isAudioCall: Boolean) { @@ -311,18 +362,53 @@ class MessagesFlowNode( override fun navigateToDeveloperSettings() { callback.navigateToDeveloperSettings() } + + override fun navigateToAvatarPreview(username: String, avatarUrl: String) { + overlay.show(NavTarget.AvatarPreview(username, avatarUrl)) + } } val inputs = MessagesNode.Inputs(focusedEventId = navTarget.focusedEventId) createNode(buildContext, listOf(callback, inputs)) } is NavTarget.MediaViewer -> { - val params = MediaViewerEntryPoint.Params( + val params = MediaViewerEntryPoint.Params.RoomMedia( mode = navTarget.mode, eventId = navTarget.eventId, mediaInfo = navTarget.mediaInfo, mediaSource = navTarget.mediaSource, thumbnailSource = navTarget.thumbnailSource, - canShowInfo = true, + ) + val callback = object : MediaViewerEntryPoint.Callback { + override fun onDone() { + if (navTarget.canUseOverlay) { + overlay.hide() + } else { + backstack.pop() + } + } + + override fun viewInTimeline(eventId: EventId) { + this@MessagesFlowNode.viewInTimeline(eventId) + } + + override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) { + // Need to go to the parent because of the overlay + callback.forwardEvent(eventId, fromPinnedEvents) + } + } + mediaViewerEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + params = params, + callback = callback + ) + } + is NavTarget.GalleryViewer -> { + val params = MediaViewerEntryPoint.Params.EventGallery( + eventId = navTarget.eventId, + galleryInfo = navTarget.galleryInfo, + galleryItems = navTarget.galleryItems, + fromPinnedMessages = navTarget.fromPinnedMessages, ) val callback = object : MediaViewerEntryPoint.Callback { override fun onDone() { @@ -351,7 +437,7 @@ class MessagesFlowNode( } is NavTarget.AttachmentPreview -> { val inputs = AttachmentsPreviewNode.Inputs( - attachment = navTarget.attachment, + attachments = navTarget.attachments, timelineMode = navTarget.timelineMode, inReplyToEventId = navTarget.inReplyToEventId, ) @@ -432,6 +518,19 @@ class MessagesFlowNode( ) } + override fun handleGalleryItemClick( + event: TimelineItem.Event, + galleryItemIndex: Int, + canUseOverlay: Boolean, + ) { + processGalleryEventClick( + timelineMode = Timeline.Mode.PinnedEvents, + event = event, + galleryItemIndex = galleryItemIndex, + canUseOverlay = canUseOverlay, + ) + } + override fun navigateToRoomMemberDetails(userId: UserId) { callback.navigateToRoomMemberDetails(userId) } @@ -467,7 +566,11 @@ class MessagesFlowNode( focusedEventId = navTarget.focusedEventId, ) val callback = object : ThreadedMessagesNode.Callback { - override fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean { + override fun handleEventClick( + timelineMode: Timeline.Mode, + event: TimelineItem.Event, + canUseOverlay: Boolean, + ): Boolean { return processEventClick( timelineMode = timelineMode, event = event, @@ -475,10 +578,24 @@ class MessagesFlowNode( ) } + override fun handleGalleryItemClick( + timelineMode: Timeline.Mode, + event: TimelineItem.Event, + galleryItemIndex: Int, + canUseOverlay: Boolean, + ): Boolean { + return processGalleryEventClick( + timelineMode = timelineMode, + event = event, + canUseOverlay = canUseOverlay, + galleryItemIndex = galleryItemIndex, + ) + } + override fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) { backstack.push( NavTarget.AttachmentPreview( - attachment = attachments.first(), + attachments = attachments, timelineMode = Timeline.Mode.Thread(navTarget.threadRootId), inReplyToEventId = inReplyToEventId, ) @@ -506,7 +623,11 @@ class MessagesFlowNode( } override fun navigateToSendLocation() { - backstack.push(NavTarget.SendLocation(Timeline.Mode.Thread(navTarget.threadRootId))) + if (hasVulkanSupport()) { + backstack.push(NavTarget.SendLocation(Timeline.Mode.Thread(navTarget.threadRootId))) + } else { + displayVulkanNotSupportedError = true + } } override fun navigateToCreatePoll() { @@ -518,7 +639,11 @@ class MessagesFlowNode( } override fun navigateToCurrentLiveLocation() { - backstack.push(NavTarget.LocationViewer(ShowLocationMode.Live(senderId = sessionId))) + if (hasVulkanSupport()) { + backstack.push(NavTarget.LocationViewer(ShowLocationMode.Live(senderId = sessionId))) + } else { + displayVulkanNotSupportedError = true + } } override fun navigateToRoomCall(roomId: RoomId, isAudioCall: Boolean) { @@ -538,6 +663,10 @@ class MessagesFlowNode( override fun navigateToDeveloperSettings() { callback.navigateToDeveloperSettings() } + + override fun navigateToAvatarPreview(username: String, avatarUrl: String) { + overlay.show(NavTarget.AvatarPreview(username, avatarUrl)) + } } createNode(buildContext, listOf(inputs, callback)) } @@ -549,6 +678,31 @@ class MessagesFlowNode( } createNode(buildContext, listOf(callback)) } + is NavTarget.AvatarPreview -> { + val callback = object : MediaViewerEntryPoint.Callback { + override fun onDone() { + overlay.hide() + } + + override fun viewInTimeline(eventId: EventId) { + // Cannot happen + } + + override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) { + // Cannot happen + } + } + val params = mediaViewerEntryPoint.createParamsForAvatar( + filename = navTarget.name, + avatarUrl = navTarget.avatarUrl, + ) + mediaViewerEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + params = params, + callback = callback, + ) + } } } @@ -607,18 +761,23 @@ class MessagesFlowNode( ) } is TimelineItemLocationContent -> { - val mode = when (event.content.mode) { - is TimelineItemLocationContent.Mode.Live -> ShowLocationMode.Live(event.senderId) - is TimelineItemLocationContent.Mode.Static -> ShowLocationMode.Static( - location = event.content.mode.location, - senderName = event.safeSenderName, - senderId = event.senderId, - senderAvatarUrl = event.senderAvatar.url, - timestamp = event.sentTimeMillis, - assetType = event.content.assetType, - ) + if (hasVulkanSupport()) { + val mode = when (event.content.mode) { + is TimelineItemLocationContent.Mode.Live -> ShowLocationMode.Live(event.senderId) + is TimelineItemLocationContent.Mode.Static -> ShowLocationMode.Static( + location = event.content.mode.location, + senderName = event.safeSenderName, + senderId = event.senderId, + senderAvatarUrl = event.senderAvatar.url, + timestamp = event.sentTimeMillis, + assetType = event.content.assetType, + ) + } + NavTarget.LocationViewer(mode = mode).takeIf { locationService.isServiceAvailable() } + } else { + displayVulkanNotSupportedError = true + null } - NavTarget.LocationViewer(mode = mode).takeIf { locationService.isServiceAvailable() } } else -> null } @@ -639,6 +798,92 @@ class MessagesFlowNode( } } + private fun processGalleryEventClick( + timelineMode: Timeline.Mode, + event: TimelineItem.Event, + galleryItemIndex: Int, + canUseOverlay: Boolean, + ): Boolean { + val navTarget = when (event.content) { + is TimelineItemGalleryContent -> { + val galleryInfo = GalleryInfo( + caption = event.content.caption, + senderId = event.senderId, + senderName = event.safeSenderName, + senderAvatar = event.senderAvatar.url, + dateSent = dateFormatter.format( + event.sentTimeMillis, + mode = DateFormatterMode.Day, + ), + dateSentFull = dateFormatter.format( + timestamp = event.sentTimeMillis, + mode = DateFormatterMode.Full, + ), + initialIndex = galleryItemIndex, + ) + val galleryItems = event.content.items.map { galleryItem -> + GalleryItemData( + filename = galleryItem.filename, + mimeType = galleryItem.mimeType, + mediaSource = galleryItem.mediaSource, + thumbnailSource = galleryItem.thumbnailSource, + type = galleryItem.type.toMediaViewerType(), + ) + }.reversed() + NavTarget.GalleryViewer( + eventId = event.eventId, + galleryInfo = galleryInfo, + canUseOverlay = canUseOverlay, + galleryItems = galleryItems, + fromPinnedMessages = timelineMode is Timeline.Mode.PinnedEvents + ) + } + is TimelineItemAttachmentsContent -> { + val galleryInfo = GalleryInfo( + caption = event.content.caption, + senderId = event.senderId, + senderName = event.safeSenderName, + senderAvatar = event.senderAvatar.url, + dateSent = dateFormatter.format( + event.sentTimeMillis, + mode = DateFormatterMode.Day, + ), + dateSentFull = dateFormatter.format( + timestamp = event.sentTimeMillis, + mode = DateFormatterMode.Full, + ), + initialIndex = galleryItemIndex, + ) + val galleryItems = event.content.attachments.map { attachment -> + GalleryItemData( + filename = attachment.filename, + mimeType = attachment.mimeType, + mediaSource = attachment.mediaSource, + thumbnailSource = attachment.thumbnailSource, + type = GalleryItemData.Type.File, + ) + }.reversed() + NavTarget.GalleryViewer( + eventId = event.eventId, + galleryInfo = galleryInfo, + canUseOverlay = canUseOverlay, + galleryItems = galleryItems, + fromPinnedMessages = timelineMode is Timeline.Mode.PinnedEvents + ) + } + else -> null + } + if (navTarget != null) { + if (canUseOverlay) { + overlay.show(navTarget) + } else { + backstack.push(navTarget) + } + return true + } + return false + } + private fun buildMediaViewerNavTarget( mode: MediaViewerEntryPoint.MediaViewerMode, event: TimelineItem.Event, @@ -691,6 +936,11 @@ class MessagesFlowNode( @Composable override fun View(modifier: Modifier) { mentionSpanTheme.updateStyles() + + if (displayVulkanNotSupportedError) { + RenderingMapsNotSupportedDialog { displayVulkanNotSupportedError = false } + } + CompositionLocalProvider( LocalMentionSpanUpdater provides mentionSpanUpdater ) { @@ -698,3 +948,12 @@ class MessagesFlowNode( } } } + +private fun GalleryItem.Type.toMediaViewerType(): GalleryItemData.Type { + return when (this) { + GalleryItem.Type.Image -> GalleryItemData.Type.Image + GalleryItem.Type.Video -> GalleryItemData.Type.Video + GalleryItem.Type.Audio -> GalleryItemData.Type.Audio + GalleryItem.Type.File -> GalleryItemData.Type.File + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index a9ce2f5ba1..a7e8846047 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -66,6 +66,7 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.alias.matches import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo +import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.mediaplayer.api.MediaPlayer import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard @@ -107,7 +108,7 @@ class MessagesNode( private val timelineController = TimelineController(room, room.liveTimeline) private val presenter = presenterFactory.create( navigator = this, - composerPresenter = messageComposerPresenterFactory.create(timelineController, this, isInThread = false), + composerPresenter = messageComposerPresenterFactory.create(timelineController, this, threadRoot = null), timelinePresenter = timelinePresenterFactory.create(timelineController = timelineController, this), actionListPresenter = actionListPresenterFactory.create( postProcessor = TimelineItemActionPostProcessor.Default, @@ -118,6 +119,7 @@ class MessagesNode( interface Callback : Plugin { fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean + fun handleGalleryItemClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean): Boolean fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) fun navigateToRoomMemberDetails(userId: UserId) fun handlePermalinkClick(data: PermalinkData) @@ -136,6 +138,8 @@ class MessagesNode( fun navigateToDeveloperSettings() fun navigateToThreadsList() + + fun navigateToAvatarPreview(username: String, avatarUrl: String) } override fun onBuilt() { @@ -286,6 +290,18 @@ class MessagesNode( } } }, + onGalleryEventItemClick = { isLive, event, index -> + if (isLive) { + callback.handleGalleryItemClick(timelineController.mainTimelineMode(), event, index, canUseOverlay) + } else { + val detachedTimelineMode = timelineController.detachedTimelineMode() + if (detachedTimelineMode != null) { + callback.handleGalleryItemClick(detachedTimelineMode, event, index, canUseOverlay) + } else { + false + } + } + }, onUserDataClick = callback::navigateToRoomMemberDetails, onLinkClick = { url, customTab -> onLinkClick( @@ -319,6 +335,11 @@ class MessagesNode( else -> state.roomMemberModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target)) } }, + onAvatarClick = { user -> + user.avatarUrl?.let { url -> + callback.navigateToAvatarPreview(user.getBestName(), url) + } + }, modifier = Modifier, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index d3737f5fae..1109b2c70d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -47,10 +47,10 @@ import io.element.android.features.messages.impl.timeline.components.reactionsum import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetState import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo -import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent +import io.element.android.features.messages.impl.timeline.model.event.captionOrNull import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState import io.element.android.features.messages.impl.voicemessages.composer.DefaultVoiceMessageComposerPresenter import io.element.android.features.roomcall.api.RoomCallState @@ -533,7 +533,7 @@ class MessagesPresenter( ) { val composerMode = MessageComposerMode.EditCaption( eventOrTransactionId = targetEvent.eventOrTransactionId, - content = (targetEvent.content as? TimelineItemEventContentWithAttachment)?.caption.orEmpty(), + content = targetEvent.content.captionOrNull().orEmpty(), ) composerState.eventSink( MessageComposerEvent.SetMode(composerMode) @@ -606,7 +606,7 @@ class MessagesPresenter( } private fun handleCopyCaption(event: TimelineItem.Event) { - val content = (event.content as? TimelineItemEventContentWithAttachment)?.caption ?: return + val content = event.content.captionOrNull() ?: return clipboardHelper.copyPlainText(content) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_copied_to_clipboard)) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index b299ea42a9..8887424dc6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -136,6 +136,7 @@ fun MessagesView( onBackClick: () -> Unit, onRoomDetailsClick: () -> Unit, onEventContentClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean, + onGalleryEventItemClick: (isLive: Boolean, event: TimelineItem.Event, index: Int) -> Boolean, onUserDataClick: (UserId) -> Unit, onLinkClick: (String, Boolean) -> Unit, onSendLocationClick: () -> Unit, @@ -207,15 +208,15 @@ fun MessagesView( val expandableState = rememberExpandableBottomSheetLayoutState() ExpandableBottomSheetLayout( modifier = modifier - .fillMaxSize() - .imePadding() - .systemBarsPadding() - .onSizeChanged { size -> - // Let the composer takes at max half of the available height. - // The value will be different if the soft keyboard is displayed - // or not. - maxComposerHeightPx = (size.height * 0.5f).toInt() - }, + .fillMaxSize() + .imePadding() + .systemBarsPadding() + .onSizeChanged { size -> + // Let the composer takes at max half of the available height. + // The value will be different if the soft keyboard is displayed + // or not. + maxComposerHeightPx = (size.height * 0.5f).toInt() + }, content = { Scaffold( contentWindowInsets = WindowInsets.statusBars, @@ -252,12 +253,22 @@ fun MessagesView( content = { padding -> Box( modifier = Modifier - .padding(padding) - .consumeWindowInsets(padding) + .padding(padding) + .consumeWindowInsets(padding) ) { MessagesViewContent( state = state, onContentClick = ::onContentClick, + onGalleryItemClick = { event, index -> + val hideKeyboard = onGalleryEventItemClick( + state.timelineState.isLive, + event, + index, + ) + if (hideKeyboard) { + localView.hideKeyboard() + } + }, onMessageLongClick = ::onMessageLongClick, onUserDataClick = { hidingKeyboard { @@ -290,10 +301,10 @@ fun MessagesView( SuggestionsPickerView( modifier = Modifier - .shadow(10.dp) - .background(ElementTheme.colors.bgCanvasDefault) - .align(Alignment.BottomStart) - .heightIn(max = 230.dp), + .shadow(10.dp) + .background(ElementTheme.colors.bgCanvasDefault) + .align(Alignment.BottomStart) + .heightIn(max = 230.dp), roomId = state.roomId, roomName = state.roomName, roomAvatarData = state.roomAvatar, @@ -459,6 +470,7 @@ private fun MessagesViewContent( onMoreReactionsClick: (TimelineItem.Event) -> Unit, onReadReceiptClick: (TimelineItem.Event) -> Unit, onMessageLongClick: (TimelineItem.Event) -> Unit, + onGalleryItemClick: ((TimelineItem.Event, Int) -> Unit), onSendLocationClick: () -> Unit, onCreatePollClick: () -> Unit, onViewAllPinnedMessagesClick: () -> Unit, @@ -469,9 +481,9 @@ private fun MessagesViewContent( ) { Box( modifier = modifier - .fillMaxSize() - .navigationBarsPadding() - .imePadding(), + .fillMaxSize() + .navigationBarsPadding() + .imePadding(), ) { AttachmentsBottomSheet( state = state.composerState, @@ -502,7 +514,9 @@ private fun MessagesViewContent( pinnedMessagesCount = (state.pinnedMessagesBannerState as? PinnedMessagesBannerState.Visible)?.pinnedMessagesCount() ?: 0, ) val density = LocalDensity.current - var pinnedBannerHeightDp by remember { mutableStateOf(0.dp) } + // Combined height of the banners overlaid above the timeline. Drives the floating + // date badge offset so the badge sits below whichever banners are currently showing. + var topBannersHeightDp by remember { mutableStateOf(0.dp) } TimelineView( state = state.timelineState, @@ -510,6 +524,7 @@ private fun MessagesViewContent( onUserDataClick = onUserDataClick, onLinkClick = { link -> onLinkClick(link, false) }, onContentClick = onContentClick, + onGalleryItemClick = onGalleryItemClick, onMessageLongClick = onMessageLongClick, onSwipeToReply = onSwipeToReply, onReactionClick = onReactionClick, @@ -518,14 +533,15 @@ private fun MessagesViewContent( onReadReceiptClick = onReadReceiptClick, forceJumpToBottomVisibility = forceJumpToBottomVisibility, nestedScrollConnection = scrollBehavior.nestedScrollConnection, - floatingDateTopOffset = pinnedBannerHeightDp, + floatingDateTopOffset = topBannersHeightDp, ) if (state.timelineState.timelineMode !is Timeline.Mode.Thread) { - Column { + Column( + modifier = Modifier.onSizeChanged { topBannersHeightDp = with(density) { it.height.toDp() } }, + ) { AnimatedVisibility( visible = state.pinnedMessagesBannerState is PinnedMessagesBannerState.Visible && scrollBehavior.isVisible, - modifier = Modifier.onSizeChanged { pinnedBannerHeightDp = with(density) { it.height.toDp() } }, enter = expandVertically(), exit = shrinkVertically(), ) { @@ -598,9 +614,9 @@ private fun MessagesViewComposerBottomSheetContents( private fun CantSendMessageBanner() { Row( modifier = Modifier - .fillMaxWidth() - .background(ElementTheme.colors.bgSubtleSecondary) - .padding(16.dp), + .fillMaxWidth() + .background(ElementTheme.colors.bgSubtleSecondary) + .padding(16.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center ) { @@ -637,6 +653,7 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class) onBackClick = {}, onRoomDetailsClick = {}, onEventContentClick = { _, _ -> false }, + onGalleryEventItemClick = { _, _, _ -> false }, onUserDataClick = {}, onLinkClick = { _, _ -> }, onSendLocationClick = {}, @@ -692,6 +709,7 @@ internal fun MessagesViewA11yPreview() = ElementPreview { onBackClick = {}, onRoomDetailsClick = {}, onEventContentClick = { _, _ -> false }, + onGalleryEventItemClick = { _, _, _ -> false }, onUserDataClick = {}, onLinkClick = { _, _ -> }, onSendLocationClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index f9d97f6d9d..f17a841c52 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -27,8 +27,10 @@ import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUser import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent @@ -37,6 +39,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.canBeCopied import io.element.android.features.messages.impl.timeline.model.event.canBeForwarded import io.element.android.features.messages.impl.timeline.model.event.canReact +import io.element.android.features.messages.impl.timeline.model.event.captionOrNull import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatterMode @@ -198,9 +201,12 @@ class DefaultActionListPresenter( add(TimelineItemAction.Forward) } if (timelineItem.isEditable && usersEventPermissions.canSendMessage) { - if (timelineItem.content is TimelineItemEventContentWithAttachment) { + if (timelineItem.content is TimelineItemEventContentWithAttachment || + timelineItem.content is TimelineItemGalleryContent || + timelineItem.content is TimelineItemAttachmentsContent) { // Caption - if (timelineItem.content.caption == null) { + val caption = timelineItem.content.captionOrNull() + if (caption == null) { add(TimelineItemAction.AddCaption) } else { add(TimelineItemAction.EditCaption) @@ -225,7 +231,7 @@ class DefaultActionListPresenter( } if (timelineItem.content.canBeCopied()) { add(TimelineItemAction.CopyText) - } else if ((timelineItem.content as? TimelineItemEventContentWithAttachment)?.caption.isNullOrBlank().not()) { + } else if (timelineItem.content.captionOrNull().isNullOrBlank().not()) { add(TimelineItemAction.CopyCaption) } if (timelineItem.isRemote) { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt index e10dd2e1bc..b09c7e4ce7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt @@ -31,7 +31,8 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ListItemDefaults -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.material3.ripple import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable @@ -63,9 +64,11 @@ import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUser import io.element.android.features.messages.impl.timeline.a11y.a11yReactionAction import io.element.android.features.messages.impl.timeline.components.MessageShieldView import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent @@ -109,7 +112,9 @@ fun ActionListView( onVerifiedUserSendFailureClick: (TimelineItem.Event) -> Unit, modifier: Modifier = Modifier, ) { - val sheetState = rememberModalBottomSheetState() + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + ) val coroutineScope = rememberCoroutineScope() val targetItem = (state.target as? ActionListState.Target.Success)?.event @@ -249,7 +254,7 @@ private fun ActionListViewContent( leadingContent = ListItemContent.Icon(IconSource.Resource(action.icon)), style = when { action.destructive -> ListItemStyle.Destructive - else -> ListItemStyle.Primary + else -> ListItemStyle.Default } ) } @@ -299,6 +304,12 @@ private fun MessageSummary( is TimelineItemImageContent -> { content = { ContentForBody(event.content.bestDescription) } } + is TimelineItemGalleryContent -> { + content = { ContentForBody(event.content.body) } + } + is TimelineItemAttachmentsContent -> { + content = { ContentForBody(event.content.body) } + } is TimelineItemStickerContent -> { content = { ContentForBody(event.content.bestDescription) } } @@ -401,7 +412,9 @@ private fun EmojiReactionsRow( } Box( - modifier = Modifier.padding(end = 10.dp).requiredSize(48.dp), + modifier = Modifier + .padding(end = 10.dp) + .requiredSize(48.dp), contentAlignment = Alignment.CenterEnd, ) { Icon( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvent.kt index a7c64845d1..7ef14f26ff 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewEvent.kt @@ -17,8 +17,11 @@ sealed interface AttachmentsPreviewEvent { data object OpenImageEditor : AttachmentsPreviewEvent data object CloseImageEditor : AttachmentsPreviewEvent data object RotateImageToTheLeft : AttachmentsPreviewEvent + data object FlipImageHorizontally : AttachmentsPreviewEvent + data object FlipImageVertically : AttachmentsPreviewEvent data object ApplyImageEdits : AttachmentsPreviewEvent data object ResetImageEdits : AttachmentsPreviewEvent data class UpdateImageCropRect(val cropRect: NormalizedCropRect) : AttachmentsPreviewEvent data object ClearImageEditError : AttachmentsPreviewEvent + data class SetCurrentCarouselIndex(val index: Int) : AttachmentsPreviewEvent } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt index 451398d7d3..c3b8d7780f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer +import kotlinx.collections.immutable.ImmutableList @ContributesNode(RoomScope::class) @AssistedInject @@ -42,7 +43,7 @@ class AttachmentsPreviewNode( private val enterpriseService: EnterpriseService, ) : Node(buildContext, plugins = plugins) { data class Inputs( - val attachment: Attachment, + val attachments: ImmutableList, val timelineMode: Timeline.Mode, val inReplyToEventId: EventId?, ) : NodeInputs @@ -54,7 +55,7 @@ class AttachmentsPreviewNode( } private val presenter = presenterFactory.create( - attachment = inputs.attachment, + attachments = inputs.attachments, timelineMode = inputs.timelineMode, onDoneListener = onDoneListener, inReplyToEventId = inputs.inReplyToEventId, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index cab00d99c1..8ebb580a90 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -11,7 +11,9 @@ package io.element.android.features.messages.impl.attachments.preview import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -48,10 +50,11 @@ import io.element.android.libraries.mediaupload.api.allFiles import io.element.android.libraries.preferences.api.store.VideoCompressionPreset import io.element.android.libraries.textcomposer.model.TextEditorState import io.element.android.libraries.textcomposer.model.rememberMarkdownTextEditorState +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job -import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import timber.log.Timber @@ -59,7 +62,7 @@ import java.io.File @AssistedInject class AttachmentsPreviewPresenter( - @Assisted private val attachment: Attachment, + @Assisted private val attachments: ImmutableList, @Assisted private val onDoneListener: OnDoneListener, @Assisted private val timelineMode: Timeline.Mode, @Assisted private val inReplyToEventId: EventId?, @@ -76,13 +79,18 @@ class AttachmentsPreviewPresenter( @AssistedFactory interface Factory { fun create( - attachment: Attachment, + attachments: ImmutableList, timelineMode: Timeline.Mode, onDoneListener: OnDoneListener, inReplyToEventId: EventId?, ): AttachmentsPreviewPresenter } + data class AttachmentAndEdits( + val attachment: Attachment, + val edits: AttachmentImageEdits, + ) + private val mediaSender = mediaSenderFactory.create(timelineMode) @Composable @@ -92,14 +100,11 @@ class AttachmentsPreviewPresenter( val sendActionState = remember { mutableStateOf(SendActionState.Idle) } - val originalLocalMedia = remember { (attachment as Attachment.Media).localMedia } - var currentAttachment by remember { mutableStateOf(attachment) } - var canEditImage by remember { mutableStateOf(originalLocalMedia.info.canEditImage()) } + var canEditImage by remember { mutableStateOf(false) } var imageEditorState by remember { mutableStateOf(null) } - var appliedImageEdits by remember { mutableStateOf(AttachmentImageEdits()) } var isApplyingImageEdits by remember { mutableStateOf(false) } var displayImageEditError by remember { mutableStateOf(false) } - var editedTempFile by remember { mutableStateOf(null) } + var editedTempFiles by remember { mutableStateOf>(emptyMap()) } val markdownTextEditorState = rememberMarkdownTextEditorState(initialText = null, initialFocus = false) val textEditorState by rememberUpdatedState( @@ -108,76 +113,115 @@ class AttachmentsPreviewPresenter( val ongoingSendAttachmentJob = remember { mutableStateOf(null) } - var preprocessMediaJob by remember { mutableStateOf(null) } + var currentIndex by remember { mutableIntStateOf(0) } - val mediaAttachment = currentAttachment as Attachment.Media - val mediaOptimizationSelectorPresenter = remember { - mediaOptimizationSelectorPresenterFactory.create( - localMedia = mediaAttachment.localMedia, - sendAsFile = mediaAttachment.sendAsFile, + var attachmentsAndEdits by remember { + mutableStateOf( + attachments.map { + AttachmentAndEdits(it, AttachmentImageEdits()) + } ) } - val mediaOptimizationSelectorState by rememberUpdatedState(mediaOptimizationSelectorPresenter.present()) + + val editedAttachments by remember { + derivedStateOf { + attachmentsAndEdits.map { it.attachment }.toImmutableList() + } + } + + var preprocessMediaJob by remember { mutableStateOf(null) } + + val mediaOptimizationSelectorPresenters = remember { + attachments + .filterIsInstance() + .mapIndexed { index, attachment -> + mediaOptimizationSelectorPresenterFactory.create( + index = index, + localMedia = attachment.localMedia, + sendAsFile = attachment.sendAsFile, + ) + } + } + val mediaOptimizationSelectorStates by rememberUpdatedState( + mediaOptimizationSelectorPresenters.map { + it.present() + }.toImmutableList() + ) val observableSendState = snapshotFlow { sendActionState.value } var displayFileTooLargeError by remember { mutableStateOf(false) } LaunchedEffect( - mediaOptimizationSelectorState.displayMediaSelectorViews, - mediaOptimizationSelectorState.videoSizeEstimations, - currentAttachment, + mediaOptimizationSelectorStates, imageEditorState, isApplyingImageEdits, + editedAttachments, ) { + if (mediaOptimizationSelectorStates.any { it.displayMediaSelectorViews == true } || + imageEditorState != null || + isApplyingImageEdits + ) { + // If any of the media optimization selectors are displayed, we don't want to pre-process the media yet + return@LaunchedEffect + } // If the media optimization selector is not displayed, we can pre-process the media // to prepare it for sending. This is done to avoid blocking the UI thread when the // user clicks on the send button. - @Suppress("ComplexCondition") - if (mediaOptimizationSelectorState.displayMediaSelectorViews == false && - preprocessMediaJob == null && - imageEditorState == null && - !isApplyingImageEdits) { - if (mediaAttachment.localMedia.info.mimeType.isMimeTypeVideo() && mediaOptimizationSelectorState.videoSizeEstimations.dataOrNull() == null) { - Timber.d("Waiting for video size estimations to be able to select the best video compression preset before pre-processing the media") - return@LaunchedEffect - } - val config = getAutoPreprocessMediaOptimizationConfig( - mediaAttachment = mediaAttachment, + val configs = mediaOptimizationSelectorStates.mapIndexed { index, mediaOptimizationSelectorState -> + getAutoPreprocessMediaOptimizationConfig( + mediaAttachment = editedAttachments[index] as Attachment.Media, mediaOptimizationSelectorState = mediaOptimizationSelectorState, - ) ?: return@LaunchedEffect - preprocessMediaJob = coroutineScope.preProcessAttachment( - attachment = currentAttachment, - mediaOptimizationConfig = config, + ) + } + preprocessMediaJob?.cancel() + preprocessMediaJob = coroutineScope.launch(dispatchers.io) { + preProcessAttachments( + attachments = editedAttachments, + mediaOptimizationConfigs = configs, displayProgress = false, sendActionState = sendActionState, ) } } - LaunchedEffect(originalLocalMedia) { - canEditImage = originalLocalMedia.info.canEditImage() || attachmentImageEditor.canEdit(originalLocalMedia) + LaunchedEffect(currentIndex) { + val currentMedia = (attachments.getOrNull(currentIndex) as? Attachment.Media)?.localMedia + if (currentMedia != null) { + canEditImage = currentMedia.info.canEditImage() || attachmentImageEditor.canEdit(currentMedia) + } } - val maxUploadSize = mediaOptimizationSelectorState.maxUploadSize.dataOrNull() + val maxUploadSize = mediaOptimizationSelectorStates.firstNotNullOfOrNull { + it.maxUploadSize.dataOrNull() + } LaunchedEffect(maxUploadSize) { - // Check file upload size if the media won't be processed for upload - val isImageFile = mediaAttachment.localMedia.info.isImageAttachment() - val isVideoFile = mediaAttachment.localMedia.info.mimeType.isMimeTypeVideo() - if (maxUploadSize != null && !(isImageFile || isVideoFile)) { + if (maxUploadSize != null) { // If file size is not known, we're permissive and allow sending. The SDK will cancel the upload if needed. - val fileSize = mediaAttachment.localMedia.info.fileSize ?: 0L - if (maxUploadSize < fileSize) { - displayFileTooLargeError = true + displayFileTooLargeError = attachments.any { attachment -> + when (attachment) { + is Attachment.Media -> { + val isImageFile = attachment.localMedia.info.isImageAttachment() + val isVideoFile = attachment.localMedia.info.mimeType.isMimeTypeVideo() + if (isImageFile || isVideoFile) { + false + } else { + val fileSize = attachment.localMedia.info.fileSize ?: 0L + maxUploadSize < fileSize + } + } + } } } } - val videoSizeEstimations = mediaOptimizationSelectorState.videoSizeEstimations.dataOrNull() - LaunchedEffect(videoSizeEstimations) { - if (videoSizeEstimations != null) { - // Check if the video size estimations are too large for the max upload size - displayFileTooLargeError = videoSizeEstimations.none { it.canUpload } + mediaOptimizationSelectorStates.forEach { mediaOptimizationSelectorState -> + val videoSizeEstimations = mediaOptimizationSelectorState.videoSizeEstimations.dataOrNull() + LaunchedEffect(videoSizeEstimations) { + if (videoSizeEstimations != null) { + // Check if the video size estimations are too large for the max upload size + displayFileTooLargeError = videoSizeEstimations.none { it.canUpload } + } } } @@ -185,19 +229,23 @@ class AttachmentsPreviewPresenter( when (event) { is AttachmentsPreviewEvent.SendAttachment -> { ongoingSendAttachmentJob.value = coroutineScope.launch { - // If the media optimization selector is displayed, we need to wait for the user to select the options - // before we can pre-process the media. - if (mediaOptimizationSelectorState.displayMediaSelectorViews == true) { - val config = MediaOptimizationConfig( - compressImages = mediaOptimizationSelectorState.isImageOptimizationEnabled == true, - videoCompressionPreset = mediaOptimizationSelectorState.selectedVideoPreset ?: VideoCompressionPreset.STANDARD, - ) - preprocessMediaJob = preProcessAttachment( - attachment = currentAttachment, - mediaOptimizationConfig = config, - displayProgress = true, - sendActionState = sendActionState, - ) + if (preprocessMediaJob?.isActive != true && sendActionState.value !is SendActionState.Sending.ReadyToUpload) { + val configs = mediaOptimizationSelectorStates.map { + MediaOptimizationConfig( + compressImages = it.isImageOptimizationEnabled + ?: mediaOptimizationConfigProvider.get().compressImages, + videoCompressionPreset = it.selectedVideoPreset + ?: mediaOptimizationConfigProvider.get().videoCompressionPreset, + ) + } + preprocessMediaJob = coroutineScope.launch(dispatchers.io) { + preProcessAttachments( + attachments = editedAttachments, + mediaOptimizationConfigs = configs, + displayProgress = true, + sendActionState = sendActionState, + ) + } } // If the processing was hidden before, make it visible now @@ -206,35 +254,27 @@ class AttachmentsPreviewPresenter( } // Wait until the media is ready to be uploaded - val mediaUploadInfo = observableSendState.firstInstanceOf().mediaInfo + val allMediaUploadInfos = observableSendState.firstInstanceOf().mediaInfos // Pre-processing is done, send the attachment val caption = markdownTextEditorState.getMessageMarkdown(permalinkBuilder) .takeIf { it.isNotEmpty() } - val editedTempFileToDelete = editedTempFile - editedTempFile = null - - // If we're supposed to send the media as a background job, we can dismiss this screen already - if (coroutineContext.isActive) { - onDoneListener() - } + val editedTempFilesToDelete = editedTempFiles + editedTempFiles = emptyMap() // Send the media using the session coroutine scope so it doesn't matter if this screen or the chat one are closed sessionCoroutineScope.launch(dispatchers.io) { - try { - sendPreProcessedMedia( - mediaUploadInfo = mediaUploadInfo, - caption = caption, - sendActionState = sendActionState, - dismissAfterSend = false, - inReplyToEventId = inReplyToEventId, - ) - } finally { - editedTempFileToDelete?.safeDelete() - // Clean up the pre-processed media after it's been sent - mediaSender.cleanUp() - } + sendMedia( + mediaUploadInfos = allMediaUploadInfos, + caption = caption, + sendActionState = sendActionState, + inReplyToEventId = inReplyToEventId, + ) + + // Clean up the pre-processed media after it's been sent + mediaSender.cleanUp() + editedTempFilesToDelete.values.forEach { it.safeDelete() } } } } @@ -251,7 +291,11 @@ class AttachmentsPreviewPresenter( ongoingSendAttachmentJob.value?.cancel() // Dismiss the screen - dismiss(sendActionState, editedTempFile) + dismiss( + attachments = editedAttachments, + sendActionState = sendActionState, + editedTempFiles = editedTempFiles, + ) } AttachmentsPreviewEvent.CancelAndClearSendState -> { // Cancel media sending @@ -260,22 +304,23 @@ class AttachmentsPreviewPresenter( ongoingSendAttachmentJob.value = null } - val mediaUploadInfo = sendActionState.value.mediaUploadInfo() - sendActionState.value = if (mediaUploadInfo != null) { - SendActionState.Sending.ReadyToUpload(mediaUploadInfo) + val mediaUploadInfoList = sendActionState.value.mediaUploadInfoList() + sendActionState.value = if (mediaUploadInfoList != null) { + SendActionState.Sending.ReadyToUpload(mediaUploadInfoList) } else { SendActionState.Idle } } AttachmentsPreviewEvent.OpenImageEditor -> { - val resolvedCanEditImage = canEditImage || originalLocalMedia.info.canEditImage() + val currentLocalMedia = (attachments.getOrNull(currentIndex) as? Attachment.Media)?.localMedia ?: return + val resolvedCanEditImage = canEditImage || currentLocalMedia.info.canEditImage() if (resolvedCanEditImage) { preprocessMediaJob?.cancel() preprocessMediaJob = null resetPreparedMedia(sendActionState) imageEditorState = AttachmentImageEditorState( - localMedia = originalLocalMedia, - edits = appliedImageEdits, + localMedia = currentLocalMedia, + edits = attachmentsAndEdits.get(currentIndex).edits, previewDebug = false, ) } @@ -295,6 +340,18 @@ class AttachmentsPreviewPresenter( edits = pendingState.edits.rotateAntiClockwise() ) } + AttachmentsPreviewEvent.FlipImageHorizontally -> { + val pendingState = imageEditorState ?: return + imageEditorState = pendingState.copy( + edits = pendingState.edits.flipHorizontally() + ) + } + AttachmentsPreviewEvent.FlipImageVertically -> { + val pendingState = imageEditorState ?: return + imageEditorState = pendingState.copy( + edits = pendingState.edits.flipVertically() + ) + } AttachmentsPreviewEvent.ResetImageEdits -> { imageEditorState = imageEditorState?.copy( edits = AttachmentImageEdits() @@ -303,10 +360,15 @@ class AttachmentsPreviewPresenter( AttachmentsPreviewEvent.ApplyImageEdits -> { val pendingState = imageEditorState ?: return if (!pendingState.edits.hasChanges) { - editedTempFile?.safeDelete() - editedTempFile = null - appliedImageEdits = pendingState.edits - currentAttachment = Attachment.Media(originalLocalMedia) + editedTempFiles[currentIndex]?.safeDelete() + editedTempFiles = editedTempFiles - currentIndex + val currentAttachment = attachmentsAndEdits[currentIndex].attachment + attachmentsAndEdits = attachmentsAndEdits.toMutableList().also { + it[currentIndex] = AttachmentAndEdits( + currentAttachment, + pendingState.edits, + ) + }.toImmutableList() imageEditorState = null resetPreparedMedia(sendActionState) return @@ -316,16 +378,21 @@ class AttachmentsPreviewPresenter( coroutineScope.launch { val result = withContext(dispatchers.io) { attachmentImageEditor.exportEdits( - localMedia = originalLocalMedia, + localMedia = pendingState.localMedia, edits = pendingState.edits, ) } result.fold( onSuccess = { editedMedia -> - editedTempFile?.safeDelete() - editedTempFile = editedMedia.file - appliedImageEdits = pendingState.edits - currentAttachment = Attachment.Media(editedMedia.localMedia) + editedTempFiles[currentIndex]?.safeDelete() + editedTempFiles = editedTempFiles + (currentIndex to editedMedia.file) + val currentAttachment = Attachment.Media(editedMedia.localMedia) + attachmentsAndEdits = attachmentsAndEdits.toMutableList().also { + it[currentIndex] = AttachmentAndEdits( + currentAttachment, + pendingState.edits, + ) + }.toImmutableList() imageEditorState = null resetPreparedMedia(sendActionState) }, @@ -340,19 +407,23 @@ class AttachmentsPreviewPresenter( AttachmentsPreviewEvent.ClearImageEditError -> { displayImageEditError = false } + is AttachmentsPreviewEvent.SetCurrentCarouselIndex -> { + currentIndex = event.index + } } } return AttachmentsPreviewState( - attachment = currentAttachment, + attachments = editedAttachments, imageEditorState = imageEditorState, canEditImage = canEditImage, isApplyingImageEdits = isApplyingImageEdits, displayImageEditError = displayImageEditError, sendActionState = sendActionState.value, textEditorState = textEditorState, - mediaOptimizationSelectorState = mediaOptimizationSelectorState, + mediaOptimizationSelectorState = mediaOptimizationSelectorStates[currentIndex], displayFileTooLargeError = displayFileTooLargeError, + currentIndex = currentIndex, eventSink = ::handleEvent, ) } @@ -360,7 +431,7 @@ class AttachmentsPreviewPresenter( private suspend fun getAutoPreprocessMediaOptimizationConfig( mediaAttachment: Attachment.Media, mediaOptimizationSelectorState: MediaOptimizationSelectorState, - ): MediaOptimizationConfig? { + ): MediaOptimizationConfig { return if (mediaAttachment.sendAsFile) { // If we're sending the media as a file, we can skip image compression and we should select the highest video compression preset that still fits // the upload limit (if the estimations are available) @@ -374,71 +445,66 @@ class AttachmentsPreviewPresenter( videoCompressionPreset = videoCompressionPreset, ) } else { - // Otherwise, we just rely on the user preferences for media optimization - mediaOptimizationConfigProvider.get() + MediaOptimizationConfig( + compressImages = mediaOptimizationSelectorState.isImageOptimizationEnabled + ?: mediaOptimizationConfigProvider.get().compressImages, + videoCompressionPreset = mediaOptimizationSelectorState.selectedVideoPreset + ?: mediaOptimizationConfigProvider.get().videoCompressionPreset, + ) } } - private fun CoroutineScope.preProcessAttachment( - attachment: Attachment, - mediaOptimizationConfig: MediaOptimizationConfig, - displayProgress: Boolean, - sendActionState: MutableState, - ) = launch(dispatchers.io) { - when (attachment) { - is Attachment.Media -> { - preProcessMedia( - mediaAttachment = attachment, - mediaOptimizationConfig = mediaOptimizationConfig, - displayProgress = displayProgress, - sendActionState = sendActionState, - ) - } - } - } - - private suspend fun preProcessMedia( - mediaAttachment: Attachment.Media, - mediaOptimizationConfig: MediaOptimizationConfig, + private suspend fun preProcessAttachments( + attachments: List, + mediaOptimizationConfigs: List, displayProgress: Boolean, sendActionState: MutableState, ) { sendActionState.value = SendActionState.Sending.Processing(displayProgress = displayProgress) - mediaSender.preProcessMedia( - uri = mediaAttachment.localMedia.uri, - mimeType = mediaAttachment.localMedia.info.mimeType, - mediaOptimizationConfig = mediaOptimizationConfig, - ).fold( - onSuccess = { mediaUploadInfo -> - Timber.d("Media ${mediaUploadInfo.file.path.orEmpty().hash()} finished processing, it's now ready to upload") - sendActionState.value = SendActionState.Sending.ReadyToUpload(mediaUploadInfo) - }, - onFailure = { - Timber.e(it, "Failed to pre-process media") - if (it is CancellationException) { - throw it - } else { - sendActionState.value = SendActionState.Failure(it, null) - } - } - ) - } - - private fun dismiss( - sendActionState: MutableState, - editedTempFile: File?, - ) { - // Delete the temporary file - when (attachment) { - is Attachment.Media -> { - temporaryUriDeleter.delete(attachment.localMedia.uri) - sendActionState.value.mediaUploadInfo()?.let { data -> - cleanUp(data) + val mediaUploadInfos = mutableListOf() + attachments.forEachIndexed { index, attachment -> + when (attachment) { + is Attachment.Media -> { + mediaSender.preProcessMedia( + uri = attachment.localMedia.uri, + mimeType = attachment.localMedia.info.mimeType, + mediaOptimizationConfig = mediaOptimizationConfigs[index], + ).fold( + onSuccess = { mediaUploadInfo -> + Timber.d("Media ${mediaUploadInfo.file.path.orEmpty().hash()} finished processing") + mediaUploadInfos.add(mediaUploadInfo) + }, + onFailure = { + Timber.e(it, "Failed to pre-process media") + if (it is CancellationException) { + throw it + } else { + sendActionState.value = SendActionState.Failure(it, emptyList()) + return + } + } + ) } } } - editedTempFile?.safeDelete() - // Reset the sendActionState to ensure that dialog is closed before the screen + sendActionState.value = SendActionState.Sending.ReadyToUpload(mediaUploadInfos) + } + + private fun dismiss( + attachments: List, + sendActionState: MutableState, + editedTempFiles: Map = emptyMap(), + ) { + for (attachment in attachments) { + when (attachment) { + is Attachment.Media -> { + temporaryUriDeleter.delete(attachment.localMedia.uri) + } + } + } + val uploadInfos = (sendActionState.value as? SendActionState.Sending.ReadyToUpload)?.mediaInfos + uploadInfos?.forEach { cleanUp(it) } + editedTempFiles.values.forEach { it.safeDelete() } sendActionState.value = SendActionState.Done onDoneListener() } @@ -452,41 +518,45 @@ class AttachmentsPreviewPresenter( } private fun resetPreparedMedia(sendActionState: MutableState) { - sendActionState.value.mediaUploadInfo()?.let(::cleanUp) + sendActionState.value.mediaUploadInfoList()?.forEach(::cleanUp) mediaSender.cleanUp() sendActionState.value = SendActionState.Idle } - private suspend fun sendPreProcessedMedia( - mediaUploadInfo: MediaUploadInfo, + private suspend fun sendMedia( + mediaUploadInfos: List, caption: String?, sendActionState: MutableState, - dismissAfterSend: Boolean, inReplyToEventId: EventId?, ) = runCatchingExceptions { - sendActionState.value = SendActionState.Sending.Uploading(mediaUploadInfo) - mediaSender.sendPreProcessedMedia( - mediaUploadInfo = mediaUploadInfo, - caption = caption, - formattedCaption = null, - inReplyToEventId = inReplyToEventId, - ).getOrThrow() + if (mediaUploadInfos.size == 1) { + sendActionState.value = SendActionState.Sending.Uploading(mediaUploadInfos) + mediaSender.sendPreProcessedMedia( + mediaUploadInfo = mediaUploadInfos.first(), + caption = caption, + formattedCaption = null, + inReplyToEventId = inReplyToEventId, + ).getOrThrow() + } else { + mediaSender.sendGallery( + mediaUploadInfos = mediaUploadInfos, + caption = caption, + formattedCaption = null, + inReplyToEventId = inReplyToEventId, + ).getOrThrow() + } }.fold( onSuccess = { - cleanUp(mediaUploadInfo) - // Reset the sendActionState to ensure that dialog is closed before the screen + mediaUploadInfos.forEach { cleanUp(it) } sendActionState.value = SendActionState.Done - - if (dismissAfterSend) { - onDoneListener() - } + onDoneListener() }, onFailure = { error -> Timber.e(error, "Failed to send attachment") if (error is CancellationException) { throw error } else { - sendActionState.value = SendActionState.Failure(error, mediaUploadInfo) + sendActionState.value = SendActionState.Failure(error, mediaUploadInfos) } } ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt index 463479fe55..8d74844c80 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewState.kt @@ -14,9 +14,10 @@ import io.element.android.features.messages.impl.attachments.preview.imageeditor import io.element.android.features.messages.impl.attachments.video.MediaOptimizationSelectorState import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.textcomposer.model.TextEditorState +import kotlinx.collections.immutable.ImmutableList data class AttachmentsPreviewState( - val attachment: Attachment, + val attachments: ImmutableList, val imageEditorState: AttachmentImageEditorState?, val canEditImage: Boolean, val isApplyingImageEdits: Boolean, @@ -25,8 +26,12 @@ data class AttachmentsPreviewState( val textEditorState: TextEditorState, val mediaOptimizationSelectorState: MediaOptimizationSelectorState, val displayFileTooLargeError: Boolean, + val currentIndex: Int, val eventSink: (AttachmentsPreviewEvent) -> Unit, -) +) { + val isGallery: Boolean get() = attachments.size > 1 + val totalCount: Int get() = attachments.size +} @Immutable sealed interface SendActionState { @@ -35,17 +40,17 @@ sealed interface SendActionState { @Immutable sealed interface Sending : SendActionState { data class Processing(val displayProgress: Boolean) : Sending - data class ReadyToUpload(val mediaInfo: MediaUploadInfo) : Sending - data class Uploading(val mediaUploadInfo: MediaUploadInfo) : Sending + data class ReadyToUpload(val mediaInfos: List) : Sending + data class Uploading(val mediaInfos: List) : Sending } - data class Failure(val error: Throwable, val mediaUploadInfo: MediaUploadInfo?) : SendActionState + data class Failure(val error: Throwable, val mediaInfos: List) : SendActionState data object Done : SendActionState - fun mediaUploadInfo(): MediaUploadInfo? = when (this) { - is Sending.ReadyToUpload -> mediaInfo - is Sending.Uploading -> mediaUploadInfo - is Failure -> mediaUploadInfo + fun mediaUploadInfoList(): List? = when (this) { + is Sending.ReadyToUpload -> mediaInfos + is Sending.Uploading -> mediaInfos + is Failure -> mediaInfos else -> null } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt index a2df440a12..a7d4e14436 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewStateProvider.kt @@ -41,9 +41,9 @@ open class AttachmentsPreviewStateProvider : PreviewParameterProvider { - localMediaRenderer.Render(attachment.localMedia) + if (state.isGallery) { + val pagerState = rememberPagerState( + initialPage = state.currentIndex, + pageCount = { state.attachments.size }, + ) + var isPillVisible by remember { mutableStateOf(true) } + + HorizontalPager( + state = pagerState, + modifier = Modifier.fillMaxSize(), + beyondViewportPageCount = 1, + contentPadding = PaddingValues(horizontal = 20.dp), + pageSpacing = 10.dp, + ) { page -> + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + val attachment = state.attachments[page] + when (attachment) { + is Attachment.Media -> { + localMediaRenderer.Render(attachment.localMedia) + } + } + } + } + + LaunchedEffect(pagerState) { + snapshotFlow { pagerState.isScrollInProgress } + .collectLatest { isScrolling -> + if (isScrolling) { + isPillVisible = true + } else { + delay(2000.milliseconds) + isPillVisible = false + } + } + } + + androidx.compose.animation.AnimatedVisibility( + visible = isPillVisible, + enter = fadeIn(animationSpec = tween(150)), + exit = fadeOut(animationSpec = tween(300)), + modifier = Modifier + .align(Alignment.TopCenter) + .padding(top = 8.dp), + ) { + GalleryCarouselPill( + currentIndex = pagerState.currentPage + 1, + totalCount = state.totalCount, + ) + } + + LaunchedEffect(pagerState.currentPage) { + state.eventSink(AttachmentsPreviewEvent.SetCurrentCarouselIndex(pagerState.currentPage)) + } + } else { + val firstAttachment = state.attachments.first() + when (firstAttachment) { + is Attachment.Media -> { + localMediaRenderer.Render(firstAttachment.localMedia) + } } } } - val mediaInfo = (state.attachment as? Attachment.Media)?.localMedia?.info + val mediaInfo = (state.attachments[state.currentIndex] as? Attachment.Media)?.localMedia?.info if (mediaInfo?.isImageAttachment() == true) { ImageOptimizationSelector(state.mediaOptimizationSelectorState) } else if (mediaInfo?.mimeType?.isMimeTypeVideo() == true) { @@ -477,16 +556,16 @@ private fun AttachmentsPreviewBottomActions( internal fun AttachmentsPreviewViewPreview(@PreviewParameter(AttachmentsPreviewStateProvider::class) state: AttachmentsPreviewState) = ElementPreviewDark { AttachmentsPreviewView( state = state, - localMediaRenderer = object : LocalMediaRenderer { - @Composable - override fun Render(localMedia: LocalMedia) { - Image( - painter = painterResource(id = CommonDrawables.sample_background), - modifier = Modifier.fillMaxSize(), - contentDescription = null, - ) - } - } + localMediaRenderer = SampleMediaRenderer(), + ) +} + +@Preview +@Composable +internal fun AttachmentsPreviewGalleryViewPreview() = ElementPreviewDark { + AttachmentsPreviewView( + state = anAttachmentsPreviewGalleryState(), + localMediaRenderer = SampleMediaRenderer(), ) } @@ -529,3 +608,24 @@ fun VideoCompressionPreset.subtitle(): String { } ) } + +@Composable +internal fun GalleryCarouselPill( + currentIndex: Int, + totalCount: Int, + modifier: Modifier = Modifier, +) { + Surface( + modifier = modifier, + shape = RoundedCornerShape(16.dp), + color = ElementTheme.colors.floatingDateBadgeBackground, + shadowElevation = 4.dp, + ) { + Text( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + text = stringResource(R.string.screen_media_upload_preview_item_count, currentIndex, totalCount), + style = ElementTheme.typography.fontBodyMdMedium, + color = ElementTheme.colors.textPrimary, + ) + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/SampleMediaRenderer.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/SampleMediaRenderer.kt new file mode 100644 index 0000000000..df981a5d08 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/SampleMediaRenderer.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.attachments.preview + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import io.element.android.libraries.designsystem.utils.CommonDrawables +import io.element.android.libraries.mediaviewer.api.local.LocalMedia +import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer + +/** + * An implementation of [LocalMediaRenderer] that displays a sample background image. + * To be used for Previews only. + */ +internal class SampleMediaRenderer : LocalMediaRenderer { + @Composable + override fun Render(localMedia: LocalMedia) { + Image( + painter = painterResource(id = CommonDrawables.sample_background), + modifier = Modifier.fillMaxSize(), + contentDescription = null, + ) + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditor.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditor.kt index cb66802184..f8d199a74e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditor.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditor.kt @@ -87,30 +87,30 @@ class DefaultAttachmentImageEditor( decodedBitmap.recycle() } - val rotatedBitmap = normalizedBitmap.rotateQuarterTurns(edits.rotationQuarterTurns) - if (rotatedBitmap !== normalizedBitmap) { + val transformedBitmap = normalizedBitmap.applyEdits(edits) + if (transformedBitmap !== normalizedBitmap) { normalizedBitmap.recycle() } val cropRect = edits.cropRect.toPixelRect( - imageWidth = rotatedBitmap.width, - imageHeight = rotatedBitmap.height, + imageWidth = transformedBitmap.width, + imageHeight = transformedBitmap.height, ) val isCropUnchanged = cropRect.left == 0 && cropRect.top == 0 && - cropRect.width() == rotatedBitmap.width && cropRect.height() == rotatedBitmap.height + cropRect.width() == transformedBitmap.width && cropRect.height() == transformedBitmap.height val croppedBitmap = if (isCropUnchanged) { - rotatedBitmap + transformedBitmap } else { Bitmap.createBitmap( - rotatedBitmap, + transformedBitmap, cropRect.left, cropRect.top, cropRect.width(), cropRect.height(), ) } - if (croppedBitmap !== rotatedBitmap) { - rotatedBitmap.recycle() + if (croppedBitmap !== transformedBitmap) { + transformedBitmap.recycle() } val editedMediaDir = File(context.cacheDir, EDITED_MEDIA_DIR_NAME).apply { mkdirs() } @@ -141,11 +141,22 @@ internal fun exportedMimeTypeFor(sourceMimeType: String?): String { } } -private fun Bitmap.rotateQuarterTurns(quarterTurns: Int): Bitmap { - val normalizedTurns = (quarterTurns % 4 + 4) % 4 - if (normalizedTurns == 0) return this +private fun Bitmap.applyEdits(edits: AttachmentImageEdits): Bitmap { + val normalizedTurns = (edits.rotationQuarterTurns % 4 + 4) % 4 + if (normalizedTurns == 0 && !edits.isFlippedHorizontally && !edits.isFlippedVertically) { + return this + } + val centerX = width / 2f + val centerY = height / 2f val matrix = Matrix().apply { - postRotate(normalizedTurns * 90f) + val scaleX = if (edits.isFlippedHorizontally) -1f else 1f + val scaleY = if (edits.isFlippedVertically) -1f else 1f + if (scaleX < 0f || scaleY < 0f) { + postScale(scaleX, scaleY, centerX, centerY) + } + if (normalizedTurns != 0) { + postRotate(normalizedTurns * 90f, centerX, centerY) + } } return Bitmap.createBitmap(this, 0, 0, width, height, matrix, true) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorState.kt index 3c8af52ce8..b798df2747 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorState.kt @@ -26,6 +26,8 @@ data class AttachmentImageEditorState( data class AttachmentImageEdits( val cropRect: NormalizedCropRect = NormalizedCropRect.default(), val rotationQuarterTurns: Int = 0, + val isFlippedHorizontally: Boolean = false, + val isFlippedVertically: Boolean = false, ) { val normalizedRotationQuarterTurns: Int get() = rotationQuarterTurns % 4 @@ -34,18 +36,32 @@ data class AttachmentImageEdits( get() = normalizedRotationQuarterTurns * 90 val hasChanges: Boolean - get() = cropRect != NormalizedCropRect.default() || normalizedRotationQuarterTurns != 0 + get() = cropRect != NormalizedCropRect.default() || + normalizedRotationQuarterTurns != 0 || + isFlippedHorizontally || + isFlippedVertically fun rotateAntiClockwise(): AttachmentImageEdits { return copy( rotationQuarterTurns = (normalizedRotationQuarterTurns + 3) % 4, // Also update the crop rect to keep the same selected area - cropRect = NormalizedCropRect( - left = cropRect.top, - top = 1f - cropRect.right, - right = cropRect.bottom, - bottom = 1f - cropRect.left, - ) + cropRect = cropRect.rotateAntiClockwise() + ) + } + + fun flipHorizontally(): AttachmentImageEdits { + return copy( + isFlippedHorizontally = !isFlippedHorizontally, + // Also update the crop rect to keep the same selected area + cropRect = cropRect.flipHorizontally(), + ) + } + + fun flipVertically(): AttachmentImageEdits { + return copy( + isFlippedVertically = !isFlippedVertically, + // Also update the crop rect to keep the same selected area + cropRect = cropRect.flipVertically(), ) } } @@ -135,6 +151,23 @@ data class NormalizedCropRect( ) } + fun rotateAntiClockwise() = copy( + left = top, + top = 1f - right, + right = bottom, + bottom = 1f - left, + ) + + fun flipHorizontally() = copy( + left = 1f - right, + right = 1f - left, + ) + + fun flipVertically() = copy( + top = 1f - bottom, + bottom = 1f - top, + ) + companion object { fun default() = NormalizedCropRect( left = DEFAULT_CROP_MARGIN, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorStateProvider.kt index df4bb5257f..7c542fd1a8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditorStateProvider.kt @@ -75,6 +75,16 @@ open class AttachmentImageEditorStateProvider : PreviewParameterProvider Unit, onRotateClick: () -> Unit, + onFlipHorizontallyClick: () -> Unit, + onFlipVerticallyClick: () -> Unit, onResetClick: () -> Unit, onCancelClick: () -> Unit, onDoneClick: () -> Unit, @@ -101,8 +101,18 @@ fun AttachmentImageEditorView( state.edits.rotationDegrees, state.edits.rotationDegrees, ) - val rotateButtonBackground = ElementTheme.colors.bgCanvasDefault - + val flipHorizontalLabel = stringResource(R.string.screen_image_edition_a11y_flip_image_horizontally) + val flipHorizontalState = if (state.edits.isFlippedHorizontally) { + stringResource(R.string.screen_image_edition_a11y_flip_image_horizontally_state_flipped) + } else { + stringResource(R.string.screen_image_edition_a11y_flip_image_horizontally_state_original) + } + val flipVerticalLabel = stringResource(R.string.screen_image_edition_a11y_flip_image_vertically) + val flipVerticalState = if (state.edits.isFlippedVertically) { + stringResource(R.string.screen_image_edition_a11y_flip_image_vertically_state_flipped) + } else { + stringResource(R.string.screen_image_edition_a11y_flip_image_vertically_state_original) + } Scaffold( modifier = modifier.fillMaxSize(), topBar = { @@ -158,37 +168,57 @@ fun AttachmentImageEditorView( onClick = onResetClick, ) } - Box( - modifier = Modifier.weight(1f), - contentAlignment = Alignment.Center, + Row( + modifier = Modifier.weight(2f), + // Center the content horizontally + horizontalArrangement = Arrangement.Center, ) { + IconButton( + onClick = onFlipHorizontallyClick, + modifier = Modifier + .clearAndSetSemantics { + contentDescription = flipHorizontalLabel + stateDescription = flipHorizontalState + } + ) { + Icon( + imageVector = CompoundIcons.FlipHorizontal(), + contentDescription = null, + ) + } IconButton( onClick = onRotateClick, modifier = Modifier - .background( - color = rotateButtonBackground, - shape = CircleShape, - ) - .border(1.dp, ElementTheme.colors.borderInteractiveSecondary, CircleShape) .clearAndSetSemantics { contentDescription = rotateContentDescription stateDescription = rotationStateDescription } ) { Icon( - modifier = Modifier - .size(22.dp), imageVector = CompoundIcons.RotateLeft(), contentDescription = null, ) } + IconButton( + onClick = onFlipVerticallyClick, + modifier = Modifier + .clearAndSetSemantics { + contentDescription = flipVerticalLabel + stateDescription = flipVerticalState + } + ) { + Icon( + imageVector = CompoundIcons.FlipVertical(), + contentDescription = null, + ) + } } Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.CenterEnd, ) { TextButton( - text = stringResource(CommonStrings.action_done), + text = stringResource(CommonStrings.action_save), onClick = onDoneClick, ) } @@ -204,6 +234,8 @@ private fun BoxScope.CropEditorCanvas( ) { var imageSize by remember(state.localMedia.uri) { mutableStateOf(IntSize.Zero) } val rotationQuarterTurns = state.edits.normalizedRotationQuarterTurns + val flipScaleX = if (state.edits.isFlippedHorizontally) -1f else 1f + val flipScaleY = if (state.edits.isFlippedVertically) -1f else 1f var imageRect by remember { mutableStateOf(Rect.Zero) } @@ -257,6 +289,10 @@ private fun BoxScope.CropEditorCanvas( contentDescription = null, modifier = Modifier .requiredSize(imageLayoutWidthDp, imageLayoutHeightDp) + .graphicsLayer { + scaleX = flipScaleX + scaleY = flipScaleY + } .graphicsLayer { rotationZ = rotationQuarterTurns * 90f }, contentScale = ContentScale.Fit, ) @@ -266,6 +302,10 @@ private fun BoxScope.CropEditorCanvas( contentDescription = stringResource(CommonStrings.common_image), modifier = Modifier .requiredSize(imageLayoutWidthDp, imageLayoutHeightDp) + .graphicsLayer { + scaleX = flipScaleX + scaleY = flipScaleY + } .graphicsLayer { rotationZ = rotationQuarterTurns * 90f }, contentScale = ContentScale.Fit, onState = { painterState -> @@ -316,11 +356,13 @@ private fun BoxScope.CropEditorCanvas( ) { change, dragAmount -> val activeTarget = dragTarget ?: return@detectDragGestures change.consume() + val gestureAreaWidth = imageRect.width.takeIf { it > 0f } ?: size.width.toFloat() + val gestureAreaHeight = imageRect.height.takeIf { it > 0f } ?: size.height.toFloat() onCropRectChange( latestCropRect.applyChange( dragTarget = activeTarget, - deltaX = dragAmount.x / size.width.toFloat(), - deltaY = dragAmount.y / size.height.toFloat(), + deltaX = dragAmount.x / gestureAreaWidth, + deltaY = dragAmount.y / gestureAreaHeight, ) ) } @@ -640,6 +682,8 @@ internal fun AttachmentImageEditorViewPreview( state = state, onCropRectChange = {}, onRotateClick = {}, + onFlipHorizontallyClick = {}, + onFlipVerticallyClick = {}, onResetClick = {}, onCancelClick = {}, onDoneClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt index abc0264b2f..c194bda507 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt @@ -36,6 +36,7 @@ import kotlin.math.roundToLong @AssistedInject class DefaultMediaOptimizationSelectorPresenter( + @Assisted private val index: Int, @Assisted private val localMedia: LocalMedia, @Assisted private val sendAsFile: Boolean, private val maxUploadSizeProvider: MaxUploadSizeProvider, @@ -48,6 +49,7 @@ class DefaultMediaOptimizationSelectorPresenter( @AssistedFactory interface Factory : MediaOptimizationSelectorPresenter.Factory { override fun create( + index: Int, localMedia: LocalMedia, sendAsFile: Boolean, ): DefaultMediaOptimizationSelectorPresenter @@ -183,6 +185,7 @@ class DefaultMediaOptimizationSelectorPresenter( } return MediaOptimizationSelectorState( + index = index, maxUploadSize = maxUploadSize, videoSizeEstimations = videoSizeEstimations, isImageOptimizationEnabled = selectedImageOptimization.dataOrNull(), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorPresenter.kt index f1e17ef0a6..6c97557c37 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorPresenter.kt @@ -14,6 +14,7 @@ import io.element.android.libraries.mediaviewer.api.local.LocalMedia fun interface MediaOptimizationSelectorPresenter : Presenter { interface Factory { fun create( + index: Int, localMedia: LocalMedia, sendAsFile: Boolean, ): MediaOptimizationSelectorPresenter diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorState.kt index 29e51d39af..bc8bf90d55 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/MediaOptimizationSelectorState.kt @@ -13,6 +13,8 @@ import io.element.android.libraries.preferences.api.store.VideoCompressionPreset import kotlinx.collections.immutable.ImmutableList data class MediaOptimizationSelectorState( + // Adding an index helps to fix a Compose issue where the state of the wrong item is updated + val index: Int, val maxUploadSize: AsyncData, val videoSizeEstimations: AsyncData>, val isImageOptimizationEnabled: Boolean?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt index 2c1a1bbe23..d7dd95eb95 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt @@ -35,6 +35,7 @@ internal fun MessagesViewWithIdentityChangePreview( onBackClick = {}, onRoomDetailsClick = {}, onEventContentClick = { _, _ -> false }, + onGalleryEventItemClick = { _, _, _ -> false }, onUserDataClick = {}, onLinkClick = { _, _ -> }, onSendLocationClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt index c14dd03f1e..a430d4621f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt @@ -14,7 +14,8 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -43,7 +44,10 @@ fun ResolveVerifiedUserSendFailureView( state: ResolveVerifiedUserSendFailureState, modifier: Modifier = Modifier, ) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), + ) var showSheet by remember { mutableStateOf(false) } fun dismiss() { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt index 405e2b0be9..d5fb0a100b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt @@ -16,7 +16,8 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -34,7 +35,6 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.IconSource import io.element.android.libraries.designsystem.theme.components.ListItem -import io.element.android.libraries.designsystem.theme.components.ListItemStyle import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet import io.element.android.libraries.designsystem.theme.components.Text @@ -73,8 +73,9 @@ internal fun AttachmentsBottomSheet( if (isVisible) { ModalBottomSheet( modifier = modifier, - sheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true + sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), ), onDismissRequest = { isVisible = false }, scrollable = false, @@ -106,25 +107,21 @@ private fun AttachmentSourcePickerMenu( modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.PhotoFromCamera) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.TakePhoto())), headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_camera_photo)) }, - style = ListItemStyle.Primary, ) ListItem( modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.VideoFromCamera) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.VideoCall())), headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_camera_video)) }, - style = ListItemStyle.Primary, ) ListItem( modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.FromGallery) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Image())), headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_gallery)) }, - style = ListItemStyle.Primary, ) ListItem( modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.FromFiles) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Attachment())), headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_files)) }, - style = ListItemStyle.Primary, ) if (state.canShareLocation) { ListItem( @@ -134,7 +131,6 @@ private fun AttachmentSourcePickerMenu( }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.LocationPin())), headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_location)) }, - style = ListItemStyle.Primary, ) } ListItem( @@ -144,14 +140,12 @@ private fun AttachmentSourcePickerMenu( }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Polls())), headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_poll)) }, - style = ListItemStyle.Primary, ) if (enableTextFormatting) { ListItem( modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.ToggleTextFormatting(enabled = true)) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.TextFormatting())), headlineContent = { Text(stringResource(R.string.screen_room_attachment_text_formatting)) }, - style = ListItemStyle.Primary, ) } } @@ -159,10 +153,11 @@ private fun AttachmentSourcePickerMenu( @PreviewsDayNight @Composable -internal fun AttachmentSourcePickerMenuPreview() = ElementPreview { - AttachmentSourcePickerMenu( +internal fun AttachmentsBottomSheetPreview() = ElementPreview(fillMaxSize = true) { + AttachmentsBottomSheet( state = aMessageComposerState( canShareLocation = true, + showAttachmentSourcePicker = true, ), onSendLocationClick = {}, onCreatePollClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt index e226318345..858e872365 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt @@ -34,7 +34,6 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.location.api.LocationService import io.element.android.features.messages.impl.MessagesNavigator import io.element.android.features.messages.impl.attachments.Attachment -import io.element.android.features.messages.impl.attachments.Attachment.Media import io.element.android.features.messages.impl.attachments.preview.error.sendAttachmentError import io.element.android.features.messages.impl.draft.ComposerDraftService import io.element.android.features.messages.impl.messagecomposer.suggestions.RoomAliasSuggestionsDataSource @@ -48,7 +47,10 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.di.annotations.SessionCoroutineScope +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.matrix.api.permalink.PermalinkParser @@ -109,7 +111,7 @@ import io.element.android.libraries.core.mimetype.MimeTypes.Any as AnyMimeTypes class MessageComposerPresenter( @Assisted private val navigator: MessagesNavigator, @Assisted private val timelineController: TimelineController, - @Assisted private val isInThread: Boolean, + @Assisted private val threadRoot: ThreadId?, @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, private val room: JoinedRoom, private val mediaPickerProvider: PickerProvider, @@ -132,16 +134,18 @@ class MessageComposerPresenter( private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider, private val notificationConversationService: NotificationConversationService, private val slashCommandService: SlashCommandService, + private val featureFlagService: FeatureFlagService, ) : Presenter { @AssistedFactory interface Factory { fun create( timelineController: TimelineController, navigator: MessagesNavigator, - isInThread: Boolean, + threadRoot: ThreadId?, ): MessageComposerPresenter } + private val isInThread = threadRoot != null private val mediaSender = mediaSenderFactory.create(timelineMode = timelineController.mainTimelineMode()) private val cameraPermissionPresenter = permissionsPresenterFactory.create(Manifest.permission.CAMERA) @@ -175,10 +179,19 @@ class MessageComposerPresenter( canShareLocation.value = locationService.isServiceAvailable() } + val isSendGalleryMessagesEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.SendGalleryMessages) + .collectAsState(initial = false) + val galleryMediaPicker = mediaPickerProvider.registerGalleryPicker { uri, mimeType -> handlePickedMedia(uri, mimeType) } - val filesPicker = mediaPickerProvider.registerFilePicker(AnyMimeTypes) { uri, mimeType -> + val galleryMultiMediaPicker = mediaPickerProvider.registerGalleryMultiPicker { uris -> + handlePickedMediaList(uris) + } + val filesPicker = mediaPickerProvider.registerFileMultiPicker(AnyMimeTypes) { uris -> + handlePickedMediaList(uris, sendAsFile = true) + } + val fileSinglePicker = mediaPickerProvider.registerFilePicker(AnyMimeTypes) { uri, mimeType -> handlePickedMedia(uri, mimeType ?: MimeTypes.OctetStream, sendAsFile = true) } val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker { uri -> @@ -234,8 +247,7 @@ class MessageComposerPresenter( LaunchedEffect(Unit) { val draft = draftService.loadDraft( roomId = room.roomId, - // TODO support threads in composer - threadRoot = null, + threadRoot = threadRoot, isVolatile = false ) if (draft != null) { @@ -265,7 +277,7 @@ class MessageComposerPresenter( is MessageComposerEvent.SendUri -> { val inReplyToEventId = (messageComposerContext.composerMode as? MessageComposerMode.Reply)?.eventId sessionCoroutineScope.sendAttachment( - attachment = Media( + attachment = Attachment.Media( localMedia = localMediaFactory.createFromUri( uri = event.uri, mimeType = null, @@ -288,11 +300,19 @@ class MessageComposerPresenter( MessageComposerEvent.DismissAttachmentMenu -> showAttachmentSourcePicker = false MessageComposerEvent.PickAttachmentSource.FromGallery -> localCoroutineScope.launch { showAttachmentSourcePicker = false - galleryMediaPicker.launch() + if (isSendGalleryMessagesEnabled) { + galleryMultiMediaPicker.launch() + } else { + galleryMediaPicker.launch() + } } MessageComposerEvent.PickAttachmentSource.FromFiles -> localCoroutineScope.launch { showAttachmentSourcePicker = false - filesPicker.launch() + if (isSendGalleryMessagesEnabled) { + filesPicker.launch() + } else { + fileSinglePicker.launch() + } } MessageComposerEvent.PickAttachmentSource.PhotoFromCamera -> localCoroutineScope.launch { showAttachmentSourcePicker = false @@ -622,6 +642,30 @@ class MessageComposerPresenter( messageComposerContext.composerMode = MessageComposerMode.Normal } + private fun handlePickedMediaList( + uris: List, + sendAsFile: Boolean = false, + ) { + if (uris.isEmpty()) return + if (uris.size == 1) { + handlePickedMedia(uris.first(), sendAsFile = sendAsFile) + return + } + val attachments = uris.map { uri -> + val localMedia = localMediaFactory.createFromUri( + uri = uri, + mimeType = null, + name = null, + formattedFileSize = null, + ) + Attachment.Media(localMedia, sendAsFile = sendAsFile) + }.toImmutableList() + val inReplyToEventId = (messageComposerContext.composerMode as? MessageComposerMode.Reply)?.eventId + navigator.navigateToPreviewAttachments(attachments, inReplyToEventId) + + messageComposerContext.composerMode = MessageComposerMode.Normal + } + private suspend fun sendMedia( uri: Uri, mimeType: String, @@ -652,8 +696,7 @@ class MessageComposerPresenter( roomId = room.roomId, draft = draft, isVolatile = isVolatile, - // TODO support threads in composer - threadRoot = null, + threadRoot = threadRoot, ) } @@ -816,8 +859,7 @@ class MessageComposerPresenter( // Use the volatile draft only when coming from edit mode otherwise. val draft = draftService.loadDraft( roomId = room.roomId, - // TODO support threads in composer - threadRoot = null, + threadRoot = threadRoot, isVolatile = true ).takeIf { fromEdit } if (draft != null) { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt index a618117950..06d97f167c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt @@ -53,6 +53,7 @@ class PinnedMessagesListNode( ) : Node(buildContext, plugins = plugins), PinnedMessagesListNavigator { interface Callback : Plugin { fun handleEventClick(event: TimelineItem.Event, canUseOverlay: Boolean) + fun handleGalleryItemClick(event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean) fun navigateToRoomMemberDetails(userId: UserId) fun viewInTimeline(eventId: EventId) fun handlePermalinkClick(data: PermalinkData.RoomLink) @@ -119,6 +120,9 @@ class PinnedMessagesListNode( onEventClick = { callback.handleEventClick(it, canUseOverlay) }, + onGalleryItemClick = { event, index -> + callback.handleGalleryItemClick(event, index, canUseOverlay) + }, onUserDataClick = { callback.navigateToRoomMemberDetails(it.userId) }, onLinkClick = { link -> onLinkClick(context, link.url) }, onLinkLongClick = { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt index 9e5f5ba304..6e8974b871 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt @@ -208,7 +208,8 @@ class PinnedMessagesListPresenter( combine(timelineItemsFlow, room.membersStateFlow) { items, membersState -> timelineItemsFactory.replaceWith( timelineItems = items, - roomMembers = membersState.roomMembers().orEmpty() + roomMembers = membersState.roomMembers().orEmpty(), + renderReadReceipts = false, ) }.launchIn(this) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt index 9811b07c02..b4fe504ab1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt @@ -60,6 +60,7 @@ fun PinnedMessagesListView( state: PinnedMessagesListState, onBackClick: () -> Unit, onEventClick: (event: TimelineItem.Event) -> Unit, + onGalleryItemClick: (event: TimelineItem.Event, index: Int) -> Unit, onUserDataClick: (MatrixUser) -> Unit, onLinkClick: (Link) -> Unit, onLinkLongClick: (Link) -> Unit, @@ -81,6 +82,7 @@ fun PinnedMessagesListView( PinnedMessagesListContent( state = state, onEventClick = onEventClick, + onGalleryItemClick = onGalleryItemClick, onUserDataClick = onUserDataClick, onLinkClick = onLinkClick, onLinkLongClick = onLinkLongClick, @@ -111,6 +113,7 @@ private fun PinnedMessagesListTopBar( private fun PinnedMessagesListContent( state: PinnedMessagesListState, onEventClick: (event: TimelineItem.Event) -> Unit, + onGalleryItemClick: (event: TimelineItem.Event, index: Int) -> Unit, onUserDataClick: (MatrixUser) -> Unit, onLinkClick: (Link) -> Unit, onLinkLongClick: (Link) -> Unit, @@ -131,6 +134,7 @@ private fun PinnedMessagesListContent( state = state, displayThreadSummaries = state.displayThreadSummaries, onEventClick = onEventClick, + onGalleryItemClick = onGalleryItemClick, onUserDataClick = onUserDataClick, onLinkClick = onLinkClick, onLinkLongClick = onLinkLongClick, @@ -169,6 +173,7 @@ private fun PinnedMessagesListLoaded( state: PinnedMessagesListState.Filled, displayThreadSummaries: Boolean, onEventClick: (event: TimelineItem.Event) -> Unit, + onGalleryItemClick: (event: TimelineItem.Event, index: Int) -> Unit, onUserDataClick: (MatrixUser) -> Unit, onLinkClick: (Link) -> Unit, onLinkLongClick: (Link) -> Unit, @@ -217,7 +222,6 @@ private fun PinnedMessagesListLoaded( timelineItem = timelineItem, timelineMode = Timeline.Mode.PinnedEvents, timelineRoomInfo = state.timelineRoomInfo, - renderReadReceipts = false, timelineProtectionState = state.timelineProtectionState, isLastOutgoingMessage = false, focusedEventId = null, @@ -227,6 +231,7 @@ private fun PinnedMessagesListLoaded( }, onLinkLongClick = onLinkLongClick, onContentClick = onEventClick, + onGalleryItemClick = onGalleryItemClick, onLongClick = ::onMessageLongClick, displayThreadSummaries = displayThreadSummaries, inReplyToClick = {}, @@ -246,6 +251,7 @@ private fun PinnedMessagesListLoaded( event = event, timelineProtectionState = state.timelineProtectionState, onContentClick = { onEventClick(event) }, + onGalleryItemClick = { index -> onGalleryItemClick(event, index) }, onLongClick = { onMessageLongClick(event) }, onLinkClick = { link -> state.linkState.eventSink(LinkEvent.OnLinkClick(link)) @@ -269,6 +275,7 @@ private fun TimelineItemEventContentViewWrapper( event: TimelineItem.Event, timelineProtectionState: TimelineProtectionState, onContentClick: () -> Unit, + onGalleryItemClick: (index: Int) -> Unit, onLinkClick: (Link) -> Unit, onLinkLongClick: (Link) -> Unit, onLongClick: (() -> Unit)?, @@ -286,6 +293,7 @@ private fun TimelineItemEventContentViewWrapper( content = event.content, hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId, event.isMine), onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) }, + onGalleryItemClick = onGalleryItemClick, onLinkClick = onLinkClick, onLinkLongClick = onLinkLongClick, eventSink = { }, @@ -305,6 +313,7 @@ internal fun PinnedMessagesListViewPreview(@PreviewParameter(PinnedMessagesListS state = state, onBackClick = {}, onEventClick = { }, + onGalleryItemClick = { _, _ -> }, onUserDataClick = {}, onLinkClick = {}, onLinkLongClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt index be573fa92f..c3e06b880b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt @@ -67,6 +67,7 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.alias.matches import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo +import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.services.analytics.api.AnalyticsService @@ -112,7 +113,7 @@ class ThreadedMessagesNode( this.timelineController = timelineController return presenterFactory.create( navigator = this, - composerPresenter = messageComposerPresenterFactory.create(timelineController, this, isInThread = true), + composerPresenter = messageComposerPresenterFactory.create(timelineController, this, threadRoot = inputs.threadRootEventId), timelinePresenter = timelinePresenterFactory.create(timelineController = timelineController, this), // TODO add special processor for threaded timeline actionListPresenter = actionListPresenterFactory.create( @@ -125,6 +126,7 @@ class ThreadedMessagesNode( interface Callback : Plugin { fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean + fun handleGalleryItemClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean): Boolean fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) fun navigateToRoomMemberDetails(userId: UserId) fun handlePermalinkClick(data: PermalinkData) @@ -138,6 +140,8 @@ class ThreadedMessagesNode( fun navigateToRoomCall(roomId: RoomId, isAudioCall: Boolean) fun navigateToThread(threadRootId: ThreadId, focusedEventId: EventId?) fun navigateToDeveloperSettings() + + fun navigateToAvatarPreview(username: String, avatarUrl: String) } override fun onBuilt() { @@ -286,6 +290,20 @@ class ThreadedMessagesNode( } } == true }, + onGalleryEventItemClick = { isLive, event, index -> + timelineController?.let { controller -> + if (isLive) { + callback.handleGalleryItemClick(controller.mainTimelineMode(), event, index, canUseOverlay) + } else { + val detachedTimelineMode = controller.detachedTimelineMode() + if (detachedTimelineMode != null) { + callback.handleGalleryItemClick(detachedTimelineMode, event, index, canUseOverlay) + } else { + false + } + } + } == true + }, onUserDataClick = callback::navigateToRoomMemberDetails, onLinkClick = { url, customTab -> onLinkClick( @@ -315,6 +333,11 @@ class ThreadedMessagesNode( else -> state.roomMemberModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target)) } }, + onAvatarClick = { user -> + user.avatarUrl?.let { url -> + callback.navigateToAvatarPreview(user.getBestName(), url) + } + }, modifier = Modifier, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListPresenter.kt index 21946510d4..ba10df46f2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListPresenter.kt @@ -9,8 +9,10 @@ package io.element.android.features.messages.impl.threads.list import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import dev.zacsweers.metro.Inject import io.element.android.features.messages.impl.timeline.factories.event.TimelineItemContentFactory @@ -18,9 +20,12 @@ import io.element.android.features.messages.impl.utils.messagesummary.MessageSum import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatterMode +import io.element.android.libraries.designsystem.components.avatar.AvatarData +import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.threads.ThreadListPaginationStatus +import io.element.android.libraries.matrix.ui.model.getAvatarData import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -95,15 +100,20 @@ class ThreadsListPresenter( val roomInfo by room.roomInfoFlow.collectAsState() + val heroes by remember { + derivedStateOf { roomInfo.heroes.map { it.getAvatarData(AvatarSize.CurrentUserTopBar) }.toImmutableList() } + } + fun handleEvent(event: ThreadsListEvents) { when (event) { ThreadsListEvents.Paginate -> if ((paginationStatus as? ThreadListPaginationStatus.Idle)?.hasMoreToLoad == true) { coroutineScope.launch { Timber.d("Paginating thread list: $paginationStatus") threadsListService.paginate() + .onFailure { Timber.w(it, "Failed to paginate thread list") } } } else { - Timber.d("Not paginating since there is nothing else to load, current status: $paginationStatus") + Timber.d("Not paginating, current status: $paginationStatus") } } } @@ -114,6 +124,7 @@ class ThreadsListPresenter( roomName = roomInfo.name ?: room.roomId.value, roomAvatarUrl = roomInfo.avatarUrl, isRoomTombstoned = roomInfo.successorRoom != null, + heroes = heroes, eventSink = ::handleEvent, ) } @@ -124,6 +135,7 @@ data class ThreadsListState( val roomName: String, val roomAvatarUrl: String?, val isRoomTombstoned: Boolean, + val heroes: ImmutableList, val threads: ImmutableList, val eventSink: (ThreadsListEvents) -> Unit, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListView.kt index 7d741eb3ea..3bcb8ab67a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/list/ThreadsListView.kt @@ -67,6 +67,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay @@ -102,7 +103,10 @@ fun ThreadsListView( url = state.roomAvatarUrl, size = AvatarSize.CurrentUserTopBar, ), - avatarType = AvatarType.Room(isTombstoned = state.isRoomTombstoned), + avatarType = AvatarType.Room( + heroes = state.heroes, + isTombstoned = state.isRoomTombstoned, + ), contentDescription = null, ) Column { @@ -162,14 +166,14 @@ private fun ScrollHelper( val lastVisibleItemIndex by remember { derivedStateOf { listState.firstVisibleItemIndex + listState.layoutInfo.visibleItemsInfo.size - 1 } } - val needsPagination by remember { + val shouldPaginate by remember { derivedStateOf { - val canLoadNewItems = listState.isScrollInProgress || listState.firstVisibleItemScrollOffset == 0 - canLoadNewItems && lastVisibleItemIndex == listState.layoutInfo.totalItemsCount - 1 + val canLoadNewItems = listState.isScrollInProgress || listState.layoutInfo.totalItemsCount == 0 + canLoadNewItems && lastVisibleItemIndex >= listState.layoutInfo.totalItemsCount - 1 } } - LaunchedEffect(needsPagination, lastVisibleItemIndex) { - if (needsPagination) { + LaunchedEffect(shouldPaginate, lastVisibleItemIndex) { + if (shouldPaginate) { updatedOnPaginate() delay(400L) } @@ -323,6 +327,7 @@ internal fun ThreadsListViewPreview() { roomId = RoomId("!room-id:server"), roomName = ROOM_NAME, roomAvatarUrl = null, + heroes = persistentListOf(), threads = List(10) { aThreadListRowItem(threadId = ThreadId("\$thread-$it")) }.toImmutableList(), isRoomTombstoned = false, eventSink = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvent.kt index e9a6ce5549..5330fc00d3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineEvent.kt @@ -25,6 +25,8 @@ sealed interface TimelineEvent { data object HideShieldDialog : TimelineEvent + data object MarkAllAsRead : TimelineEvent + /** * Events coming from a timeline item. */ diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index 0681a0ff38..00039dc1af 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -33,6 +33,7 @@ import io.element.android.features.messages.impl.timeline.factories.TimelineItem import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig import io.element.android.features.messages.impl.timeline.model.NewEventState import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemTypingNotificationModel import io.element.android.features.messages.impl.typing.TypingNotificationState import io.element.android.features.messages.impl.userEventPermissions @@ -96,6 +97,7 @@ class TimelinePresenter( private val featureFlagService: FeatureFlagService, private val analyticsService: AnalyticsService, private val liveLocationShareManager: ActiveLiveLocationShareManager, + private val markAsFullyRead: MarkAsFullyRead, ) : Presenter { private val tag = "TimelinePresenter" @@ -134,13 +136,16 @@ class TimelinePresenter( val prevMostRecentItemId = rememberSaveable { mutableStateOf(null) } - val newEventState = remember { mutableStateOf(NewEventState.None) } + val newEventState = remember { mutableStateOf(NewEventState.None) } val messageShieldDialogData: MutableState = remember { mutableStateOf(null) } + // Forces [JumpToUnreadState.Hidden] until the next RoomInfo push. Set after a + // [TimelineEvent.MarkAllAsRead] await completes so the FAB hides without waiting for + // the SDK to push a refreshed fully-read marker; the after-await ordering means any + // RoomInfo update racing the mark-as-read call has already landed and can't undo this. + val suppressJumpToUnread = remember { mutableStateOf(false) } + val resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailurePresenter.present() - val renderReadReceipts by remember { - sessionPreferencesStore.isRenderReadReceiptsEnabled() - }.collectAsState(initial = true) val isLive by remember { timelineController.isLive() }.collectAsState(initial = true) @@ -148,8 +153,8 @@ class TimelinePresenter( val displayThreadSummaries by produceState(false) { value = featureFlagService.isFeatureEnabled(FeatureFlags.Threads) } - val displayFloatingDateBadge by produceState(false) { - value = featureFlagService.isFeatureEnabled(FeatureFlags.FloatingDateBadge) + val displayJumpToUnread by produceState(false) { + value = featureFlagService.isFeatureEnabled(FeatureFlags.JumpToUnread) } fun handleEvent(event: TimelineEvent) { @@ -224,6 +229,14 @@ class TimelinePresenter( timelineController.focusOnLive() } TimelineEvent.HideShieldDialog -> messageShieldDialogData.value = null + TimelineEvent.MarkAllAsRead -> sessionCoroutineScope.launch { + val latestEventId = room.liveTimeline.getLatestEventId().getOrElse { + Timber.tag(tag).w(it, "Failed to get latest event id to mark as fully read") + null + } ?: return@launch + markAsFullyRead(room.roomId, latestEventId) + suppressJumpToUnread.value = true + } is TimelineEvent.ShowShieldDialog -> messageShieldDialogData.value = event.messageShieldData is TimelineEvent.ComputeVerifiedUserSendFailure -> { resolveVerifiedUserSendFailureState.eventSink(ResolveVerifiedUserSendFailureEvent.ComputeForMessage(event.event)) @@ -255,13 +268,18 @@ class TimelinePresenter( } .launchIn(this) - combine(timelineController.timelineItems(), room.membersStateFlow) { items, membersState -> + combine( + timelineController.timelineItems(), + room.membersStateFlow, + sessionPreferencesStore.isRenderReadReceiptsEnabled(), + ) { items, membersState, renderReadReceipts -> val parent = analyticsService.getLongRunningTransaction(DisplayFirstTimelineItems) val transaction = parent?.startChild("timelineItemsFactory.replaceWith", "Processing timeline items") transaction?.putExtraData(AnalyticsUserData.TIMELINE_ITEM_COUNT, items.count().toString()) timelineItemsFactory.replaceWith( timelineItems = items, - roomMembers = membersState.roomMembers().orEmpty() + roomMembers = membersState.roomMembers().orEmpty(), + renderReadReceipts = renderReadReceipts, ) transaction?.finish() items @@ -275,7 +293,67 @@ class TimelinePresenter( computeNewItemState(timelineItems, prevMostRecentItemId, newEventState) } - LaunchedEffect(timelineItems.size, focusRequestState.value) { + // Keyed on the full [timelineItems] reference (not just .size) so we re-scan when the + // read marker advances in place — the SDK swaps the marker virtual item to a new position + // without changing the list length, e.g. when [markRoomAsFullyRead] is sent while at the + // bottom of the room. + // + // The state has three shapes: + // - InWindow: the SDK has materialised a virtual ReadMarker item in the loaded window; + // tapping the FAB smoothly scrolls to its index. + // - OutOfWindow: the marker event is older than the loaded window, so the SDK gives us + // only the event id via RoomInfo.fullyReadEventId; tapping triggers a focused-event + // load via the existing TimelineEvent.FocusOnEvent path. + // - Hidden: feature flag off, no marker, caught-up (marker loaded but no virtual item), + // or initial load (no items yet). + val jumpToUnread = remember { mutableStateOf(JumpToUnreadState.Hidden) } + // The SDK is authoritative again once it pushes a new fully-read marker, so drop the + // post-mark-as-read suppression and let the recompute below pick up the new value. + LaunchedEffect(roomInfo.fullyReadEventId) { + suppressJumpToUnread.value = false + } + LaunchedEffect( + timelineItems.map { it.identifier() }, + displayJumpToUnread, + roomInfo.fullyReadEventId, + roomInfo.numUnreadMessages, + suppressJumpToUnread.value, + ) { + if (!displayJumpToUnread || suppressJumpToUnread.value) { + jumpToUnread.value = JumpToUnreadState.Hidden + return@LaunchedEffect + } + val items = timelineItems + val fullyReadEventId = roomInfo.fullyReadEventId + val hasUnreadMessages = roomInfo.numUnreadMessages > 0 + val markerIndex = withContext(dispatchers.computation) { + items.indexOfFirst { + (it as? TimelineItem.Virtual)?.model is TimelineItemReadMarkerModel + } + } + jumpToUnread.value = when { + markerIndex >= 0 -> JumpToUnreadState.InWindow(markerIndex) + // Out-of-window only when there is genuinely unread *displayable* content + // (numUnreadMessages counts "interesting" messages, never state/hidden events) AND + // the marker event isn't merely an in-window item we don't render. isKnown is the + // cheap display-index check; isEventLoaded falls back to the SDK to tell + // "in window but not displayed" apart from "genuinely out of window". + fullyReadEventId != null && + hasUnreadMessages && + items.isNotEmpty() && + !timelineItemIndexer.isKnown(fullyReadEventId) && + !timelineController.activeTimelineFlow().value.isEventLoaded(fullyReadEventId) -> + JumpToUnreadState.OutOfWindow(fullyReadEventId) + else -> JumpToUnreadState.Hidden + } + } + + // Keyed on the full [timelineItems] reference (not just .size) so we re-resolve the index + // when a focused timeline loads with the same item count as the window it replaced — e.g. + // jumping to an out-of-window read marker in a busy room, where both windows fill to the + // same page size. With .size as the key the effect wouldn't re-run, the focused event's + // index would stay unresolved, and the scroll would never fire until a second tap. + LaunchedEffect(timelineItems.map { it.identifier() }, focusRequestState.value) { val currentFocusRequestState = focusRequestState.value if (currentFocusRequestState is FocusRequestState.Success && !currentFocusRequestState.rendered) { val eventId = currentFocusRequestState.eventId @@ -316,14 +394,14 @@ class TimelinePresenter( timelineItems = timelineItems, timelineMode = timelineMode, timelineRoomInfo = timelineRoomInfo, - renderReadReceipts = renderReadReceipts, newEventState = newEventState.value, isLive = isLive, focusRequestState = focusRequestState.value, messageShieldDialogData = messageShieldDialogData.value, resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState, displayThreadSummaries = displayThreadSummaries, - displayFloatingDateBadge = displayFloatingDateBadge, + displayJumpToUnread = displayJumpToUnread, + jumpToUnread = jumpToUnread.value, eventSink = ::handleEvent, ) } @@ -385,7 +463,7 @@ class TimelinePresenter( private suspend fun computeNewItemState( timelineItems: ImmutableList, prevMostRecentItemId: MutableState, - newEventState: MutableState + newEventState: MutableState, ) = withContext(dispatchers.computation) { // FromMe is prioritized over FromOther, so skip if we already have a FromMe if (newEventState.value == NewEventState.FromMe) { @@ -404,12 +482,7 @@ class TimelinePresenter( if (hasNewEvent) { // Scroll to bottom if the new event is from me, even if sent from another device - val fromMe = newMostRecentItem.isMine - newEventState.value = if (fromMe) { - NewEventState.FromMe - } else { - NewEventState.FromOther - } + newEventState.value = if (newMostRecentItem.isMine) NewEventState.FromMe else NewEventState.FromOther } prevMostRecentItemId.value = newMostRecentItemId } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt index 1869ad6906..7836c17563 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt @@ -26,7 +26,6 @@ data class TimelineState( val timelineItems: ImmutableList, val timelineRoomInfo: TimelineRoomInfo, val timelineMode: Timeline.Mode, - val renderReadReceipts: Boolean, val newEventState: NewEventState, val isLive: Boolean, val focusRequestState: FocusRequestState, @@ -34,7 +33,8 @@ data class TimelineState( val messageShieldDialogData: MessageShieldData?, val resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState, val displayThreadSummaries: Boolean, - val displayFloatingDateBadge: Boolean, + val displayJumpToUnread: Boolean, + val jumpToUnread: JumpToUnreadState, val eventSink: (TimelineEvent) -> Unit, ) { private val lastTimelineEvent = timelineItems.firstOrNull { it is TimelineItem.Event } as? TimelineItem.Event @@ -83,3 +83,18 @@ data class TimelineRoomInfo( val typingNotificationState: TypingNotificationState, val predecessorRoom: PredecessorRoom?, ) + +/** + * Whether the jump-to-unread FAB should be shown, and if so, how tapping it + * should bring the user to the read marker. + */ +@Immutable +sealed interface JumpToUnreadState { + data object Hidden : JumpToUnreadState + + /** The read marker is materialised at [index] in the loaded timeline — smooth scroll to it. */ + data class InWindow(val index: Int) : JumpToUnreadState + + /** The read marker event is older than the loaded window — load it via focused-event navigation. */ + data class OutOfWindow(val eventId: EventId) : JumpToUnreadState +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index 0bf293eca4..fc7cd844fa 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt @@ -51,14 +51,15 @@ import kotlin.random.Random fun aTimelineState( timelineItems: ImmutableList = persistentListOf(), timelineMode: Timeline.Mode = Timeline.Mode.Live, - renderReadReceipts: Boolean = false, timelineRoomInfo: TimelineRoomInfo = aTimelineRoomInfo(), focusedEventIndex: Int = -1, isLive: Boolean = true, messageShield: MessageShield? = null, resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState = aResolveVerifiedUserSendFailureState(), displayThreadSummaries: Boolean = false, - displayFloatingDateBadge: Boolean = false, + displayJumpToUnread: Boolean = false, + jumpToUnread: JumpToUnreadState = JumpToUnreadState.Hidden, + newEventState: NewEventState = NewEventState.None, eventSink: (TimelineEvent) -> Unit = {}, ): TimelineState { val focusedEventId = timelineItems.filterIsInstance().getOrNull(focusedEventIndex)?.eventId @@ -71,14 +72,14 @@ fun aTimelineState( timelineItems = timelineItems, timelineMode = timelineMode, timelineRoomInfo = timelineRoomInfo, - renderReadReceipts = renderReadReceipts, - newEventState = NewEventState.None, + newEventState = newEventState, isLive = isLive, focusRequestState = focusRequestState, messageShieldDialogData = messageShield?.let { MessageShieldData(it) }, resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState, displayThreadSummaries = displayThreadSummaries, - displayFloatingDateBadge = displayFloatingDateBadge, + displayJumpToUnread = displayJumpToUnread, + jumpToUnread = jumpToUnread, eventSink = eventSink, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt index 41a828abb4..6c0dce8cca 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt @@ -10,22 +10,34 @@ package io.element.android.features.messages.impl.timeline import android.view.HapticFeedbackConstants import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.FloatingActionButtonDefaults +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect @@ -39,16 +51,27 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.rotate +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.TransformOrigin +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntRect +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Popup +import androidx.compose.ui.window.PopupPositionProvider +import androidx.compose.ui.window.PopupProperties import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureView @@ -65,20 +88,23 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState import io.element.android.libraries.androidutils.system.copyToClipboard +import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom import io.element.android.libraries.designsystem.components.dialogs.AlertDialog import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.FloatingActionButton +import io.element.android.libraries.designsystem.text.roundToPx import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.animateScrollToItemCenter import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.testtags.TestTag import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.link.Link +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine @@ -97,6 +123,7 @@ fun TimelineView( onUserDataClick: (MatrixUser) -> Unit, onLinkClick: (Link) -> Unit, onContentClick: (TimelineItem.Event) -> Unit, + onGalleryItemClick: ((TimelineItem.Event, Int) -> Unit), onMessageLongClick: (TimelineItem.Event) -> Unit, onSwipeToReply: (TimelineItem.Event) -> Unit, onReactionClick: (emoji: String, TimelineItem.Event) -> Unit, @@ -106,6 +133,7 @@ fun TimelineView( modifier: Modifier = Modifier, lazyListState: LazyListState = rememberLazyListState(), forceJumpToBottomVisibility: Boolean = false, + forceJumpToReadMarkerVisibility: Boolean = false, nestedScrollConnection: NestedScrollConnection = rememberNestedScrollInteropConnection(), floatingDateTopOffset: Dp = 0.dp, ) { @@ -125,12 +153,17 @@ fun TimelineView( state.eventSink(TimelineEvent.JumpToLive) } + fun onMarkAllAsRead() { + state.eventSink(TimelineEvent.MarkAllAsRead) + } + + fun onFocusOnEvent(eventId: EventId) { + state.eventSink(TimelineEvent.FocusOnEvent(eventId)) + } + val context = LocalContext.current val toastMessage = stringResource(CommonStrings.common_copied_to_clipboard) val view = LocalView.current - // Disable reverse layout when TalkBack is enabled to avoid incorrect ordering issues seen in the current Compose UI version - val useReverseLayout = !isTalkbackActive() - fun inReplyToClick(eventId: EventId) { state.eventSink(TimelineEvent.FocusOnEvent(eventId)) } @@ -158,7 +191,7 @@ fun TimelineView( .nestedScroll(nestedScrollConnection) .testTag(TestTags.timeline), state = lazyListState, - reverseLayout = useReverseLayout, + reverseLayout = true, contentPadding = PaddingValues(top = 64.dp, bottom = 8.dp), ) { items( @@ -171,7 +204,6 @@ fun TimelineView( timelineMode = state.timelineMode, timelineRoomInfo = state.timelineRoomInfo, timelineProtectionState = timelineProtectionState, - renderReadReceipts = state.renderReadReceipts, isLastOutgoingMessage = state.isLastOutgoingMessage(timelineItem.identifier()), focusedEventId = state.focusedEventId, displayThreadSummaries = state.displayThreadSummaries, @@ -179,6 +211,7 @@ fun TimelineView( onLinkClick = onLinkClick, onLinkLongClick = ::onLinkLongClick, onContentClick = onContentClick, + onGalleryItemClick = onGalleryItemClick, onLongClick = onMessageLongClick, inReplyToClick = ::inReplyToClick, onReactionClick = onReactionClick, @@ -205,22 +238,25 @@ fun TimelineView( hasAnyEvent = state.hasAnyEvent, lazyListState = lazyListState, forceJumpToBottomVisibility = forceJumpToBottomVisibility, + forceJumpToReadMarkerVisibility = forceJumpToReadMarkerVisibility, newEventState = state.newEventState, isLive = state.isLive, focusRequestState = state.focusRequestState, + displayJumpToUnread = state.displayJumpToUnread, + jumpToUnread = state.jumpToUnread, onScrollFinishAt = ::onScrollFinishAt, onJumpToLive = ::onJumpToLive, onFocusEventRender = ::onFocusEventRender, + onMarkAllAsRead = ::onMarkAllAsRead, + onFocusOnEvent = ::onFocusOnEvent, ) - if (state.displayFloatingDateBadge && useReverseLayout) { - FloatingDateBadgeOverlay( - lazyListState = lazyListState, - timelineItems = state.timelineItems, - isLive = state.isLive, - topOffset = floatingDateTopOffset, - ) - } + FloatingDateBadgeOverlay( + lazyListState = lazyListState, + timelineItems = state.timelineItems, + isLive = state.isLive, + topOffset = floatingDateTopOffset, + ) } } @@ -289,10 +325,15 @@ private fun BoxScope.TimelineScrollHelper( newEventState: NewEventState, isLive: Boolean, forceJumpToBottomVisibility: Boolean, + forceJumpToReadMarkerVisibility: Boolean, focusRequestState: FocusRequestState, + displayJumpToUnread: Boolean, + jumpToUnread: JumpToUnreadState, onScrollFinishAt: (Int) -> Unit, onJumpToLive: () -> Unit, onFocusEventRender: () -> Unit, + onMarkAllAsRead: () -> Unit, + onFocusOnEvent: (EventId) -> Unit, ) { val coroutineScope = rememberCoroutineScope() val isScrollFinished by remember { derivedStateOf { !lazyListState.isScrollInProgress } } @@ -301,6 +342,22 @@ private fun BoxScope.TimelineScrollHelper( lazyListState.firstVisibleItemIndex < 3 && isLive } } + val isJumpToUnreadVisible by remember(jumpToUnread, forceJumpToReadMarkerVisibility) { + derivedStateOf { + if (forceJumpToReadMarkerVisibility) return@derivedStateOf true + when (val jtu = jumpToUnread) { + JumpToUnreadState.Hidden -> false + // Marker is outside the loaded window — we have no on-screen anchor, so just show. + is JumpToUnreadState.OutOfWindow -> true + // Marker is in the loaded window — hide once it's scrolled into the visible range. + is JumpToUnreadState.InWindow -> { + val lastVisibleIndex = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: return@derivedStateOf false + jtu.index > lastVisibleIndex + } + } + } + } + val isJumpToBottomVisible = !canAutoScroll || forceJumpToBottomVisibility || !isLive var jumpToLiveHandled by remember { mutableStateOf(true) } /** @@ -327,6 +384,16 @@ private fun BoxScope.TimelineScrollHelper( } } + fun jumpToReadMarker() { + when (val jtu = jumpToUnread) { + JumpToUnreadState.Hidden -> Unit + is JumpToUnreadState.InWindow -> coroutineScope.launch { + lazyListState.animateScrollToItemCenter(jtu.index) + } + is JumpToUnreadState.OutOfWindow -> onFocusOnEvent(jtu.eventId) + } + } + LaunchedEffect(jumpToLiveHandled, isLive) { if (!jumpToLiveHandled && isLive) { lazyListState.scrollToItem(0) @@ -343,8 +410,11 @@ private fun BoxScope.TimelineScrollHelper( } LaunchedEffect(canAutoScroll, newEventState) { - val shouldScrollToBottom = isScrollFinished && - (canAutoScroll && newEventState == NewEventState.FromOther || newEventState == NewEventState.FromMe) + val shouldScrollToBottom = isScrollFinished && when (newEventState) { + is NewEventState.FromOther -> canAutoScroll + NewEventState.FromMe -> true + NewEventState.None -> false + } if (shouldScrollToBottom) { scrollToBottom(force = true) } @@ -358,43 +428,145 @@ private fun BoxScope.TimelineScrollHelper( } } - JumpToBottomButton( - // Use inverse of canAutoScroll otherwise we might briefly see the before the scroll animation is triggered - isVisible = !canAutoScroll || forceJumpToBottomVisibility || !isLive, + Column( modifier = Modifier .align(Alignment.BottomEnd) - .padding(end = 24.dp, bottom = 12.dp), - onClick = { jumpToBottom() }, - ) + .padding(end = 24.dp, bottom = 16.dp) + ) { + JumpToPositionButton( + icon = CompoundIcons.ChevronUp(), + contentDescription = stringResource(id = CommonStrings.a11y_jump_to_unread_messages), + modifier = Modifier.padding(bottom = 12.dp), + isVisible = isJumpToUnreadVisible, + hasUnread = true, + onClick = ::jumpToReadMarker, + onMarkAsRead = onMarkAllAsRead, + testTag = TestTags.jumpToUnreadButton, + ) + // Reserves space for the jump to bottom button so the jump to unread button above + // stays in the same position regardless of whether the jump to bottom button is visible. + Box(modifier = Modifier.size(36.dp)) { + JumpToPositionButton( + icon = CompoundIcons.ChevronDown(), + contentDescription = stringResource(id = CommonStrings.a11y_jump_to_bottom), + isVisible = isJumpToBottomVisible, + hasUnread = displayJumpToUnread && newEventState is NewEventState.FromOther, + onClick = ::jumpToBottom, + onMarkAsRead = onMarkAllAsRead, + testTag = TestTags.jumpToBottomButton, + dotAlignment = Alignment.BottomCenter, + ) + } + } } @Composable -private fun JumpToBottomButton( +private fun JumpToPositionButton( + icon: ImageVector, + contentDescription: String, isVisible: Boolean, + hasUnread: Boolean, onClick: () -> Unit, + onMarkAsRead: () -> Unit, + testTag: TestTag, modifier: Modifier = Modifier, + dotAlignment: Alignment = Alignment.TopCenter, ) { AnimatedVisibility( modifier = modifier, visible = isVisible, - enter = scaleIn(animationSpec = tween(100)), - exit = scaleOut(animationSpec = tween(100)), + enter = scaleIn(animationSpec = tween(220), initialScale = 0.8f) + fadeIn(animationSpec = tween(220)), + exit = scaleOut(animationSpec = tween(180), targetScale = 0.8f) + fadeOut(animationSpec = tween(180)), ) { - FloatingActionButton( - onClick = onClick, - elevation = FloatingActionButtonDefaults.elevation(4.dp, 4.dp, 4.dp, 4.dp), - shape = CircleShape, - modifier = Modifier.size(36.dp), - containerColor = ElementTheme.colors.bgSubtleSecondary, - contentColor = ElementTheme.colors.iconSecondary, - ) { - Icon( + var menuExpanded by remember { mutableStateOf(false) } + Box { + Box( modifier = Modifier - .size(24.dp) - .rotate(90f), - imageVector = CompoundIcons.ArrowRight(), - contentDescription = stringResource(id = CommonStrings.a11y_jump_to_bottom) - ) + .size(36.dp) + .background(color = ElementTheme.colors.bgCanvasDefault, shape = CircleShape) + .clip(CircleShape) + .border(1.dp, ElementTheme.colors.borderDisabled, CircleShape) + .combinedClickable( + onClick = onClick, + onLongClick = { menuExpanded = true }, + onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), + ) + .testTag(testTag), + contentAlignment = Alignment.Center, + ) { + Icon( + modifier = Modifier.size(24.dp), + imageVector = icon, + contentDescription = contentDescription, + tint = ElementTheme.colors.iconSecondary, + ) + val menuTransitionState = remember { MutableTransitionState(false) } + .apply { targetState = menuExpanded } + if (menuTransitionState.currentState || menuTransitionState.targetState) { + val gapPx = with(LocalDensity.current) { 8.dp.roundToPx() } + val positionProvider = remember(gapPx) { CenterStartOfAnchorPositionProvider(gapPx) } + Popup( + popupPositionProvider = positionProvider, + onDismissRequest = { menuExpanded = false }, + properties = PopupProperties(focusable = true), + ) { + // Anchor the scale to the right-center edge so the menu visually grows + // outward from the FAB it's attached to. + val transformOrigin = TransformOrigin(pivotFractionX = 1f, pivotFractionY = 0.5f) + AnimatedVisibility( + visibleState = menuTransitionState, + enter = scaleIn( + animationSpec = tween(180), + initialScale = 0.9f, + transformOrigin = transformOrigin, + ) + fadeIn(animationSpec = tween(180)), + exit = scaleOut( + animationSpec = tween(140), + targetScale = 0.9f, + transformOrigin = transformOrigin, + ) + fadeOut(animationSpec = tween(140)), + ) { + // Hand-rolled instead of DropdownMenuItem: padding here is tighter + // than DropdownMenuItem's 12.dp default to match the Figma spec. + Row( + modifier = Modifier + .shadow(elevation = 1.dp, shape = RoundedCornerShape(8.dp)) + .clip(RoundedCornerShape(8.dp)) + .background(ElementTheme.colors.bgCanvasDefaultLevel1) + .border(1.dp, ElementTheme.colors.borderDisabled, RoundedCornerShape(8.dp)) + .clickable { + menuExpanded = false + onMarkAsRead() + } + .padding(horizontal = 12.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = CompoundIcons.MarkAsRead(), + contentDescription = null, + tint = ElementTheme.colors.iconTertiary, + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = stringResource(id = CommonStrings.action_mark_as_read), + color = ElementTheme.colors.textPrimary, + style = ElementTheme.typography.fontBodyLgRegular, + ) + } + } + } + } + } + val dotYOffset = if (dotAlignment == Alignment.BottomCenter) 4.dp else (-4).dp + if (hasUnread) { + UnreadIndicatorAtom( + modifier = Modifier + .align(dotAlignment) + .offset { IntOffset(x = 0, y = dotYOffset.roundToPx()) }, + color = ElementTheme.colors.iconSuccessPrimary, + border = BorderStroke(2.dp, ElementTheme.colors.bgCanvasDefault), + ) + } } } } @@ -429,7 +601,89 @@ internal fun TimelineViewPreview( onReactionLongClick = { _, _ -> }, onMoreReactionsClick = {}, onReadReceiptClick = {}, + onGalleryItemClick = { _, _ -> }, forceJumpToBottomVisibility = true, ) } } + +// The jump-to-unread FAB's indicator is always rendered when the FAB is visible — in +// production the FAB only appears when unread content exists above. So `hasUnreadAbove` +// here only varies the scroll-target state, not the upper indicator's visibility. +@Composable +private fun TimelineViewWithReadMarker( + hasUnreadAbove: Boolean, + hasUnreadBelow: Boolean, +) { + val timelineItems = persistentListOf( + aTimelineItemEvent(isMine = false), + aTimelineItemEvent(isMine = false), + aTimelineItemEvent(isMine = true), + aTimelineItemEvent(isMine = false), + aTimelineItemEvent(isMine = false), + aTimelineItemEvent(isMine = false), + ) + CompositionLocalProvider( + LocalTimelineItemPresenterFactories provides aFakeTimelineItemPresenterFactories(), + ) { + TimelineView( + state = aTimelineState( + timelineItems = timelineItems, + displayJumpToUnread = true, + // Index points past the loaded items, mirroring the real-world state the FAB + // represents: the user has scrolled past the read marker, so it's no longer in + // view. The actual scroll target doesn't matter for a static preview. + jumpToUnread = if (hasUnreadAbove) JumpToUnreadState.InWindow(timelineItems.size) else JumpToUnreadState.Hidden, + newEventState = if (hasUnreadBelow) NewEventState.FromOther else NewEventState.None, + ), + timelineProtectionState = aTimelineProtectionState(), + onUserDataClick = {}, + onLinkClick = {}, + onContentClick = {}, + onGalleryItemClick = { _, _ -> }, + onMessageLongClick = {}, + onSwipeToReply = {}, + onReactionClick = { _, _ -> }, + onReactionLongClick = { _, _ -> }, + onMoreReactionsClick = {}, + onReadReceiptClick = {}, + forceJumpToBottomVisibility = true, + forceJumpToReadMarkerVisibility = true, + ) + } +} + +@PreviewsDayNight +@Composable +internal fun TimelineViewWithReadMarkerJumpToUnreadIndicatorOnlyPreview() = ElementPreview { + TimelineViewWithReadMarker(hasUnreadAbove = false, hasUnreadBelow = false) +} + +@PreviewsDayNight +@Composable +internal fun TimelineViewWithReadMarkerBothIndicatorsPreview() = ElementPreview { + TimelineViewWithReadMarker(hasUnreadAbove = true, hasUnreadBelow = true) +} + +/** + * Anchors the popup so its right edge sits [gapPx] to the left of the anchor and its vertical + * center matches the anchor's. Adapts to localized menu widths and FAB size; coerced to stay + * on-screen. + */ +private class CenterStartOfAnchorPositionProvider( + private val gapPx: Int, +) : PopupPositionProvider { + override fun calculatePosition( + anchorBounds: IntRect, + windowSize: IntSize, + layoutDirection: LayoutDirection, + popupContentSize: IntSize, + ): IntOffset { + val x = anchorBounds.left - popupContentSize.width - gapPx + val y = anchorBounds.top + (anchorBounds.height - popupContentSize.height) / 2 + return IntOffset( + x = x.coerceIn(0, (windowSize.width - popupContentSize.width).coerceAtLeast(0)), + y = y.coerceIn(0, (windowSize.height - popupContentSize.height).coerceAtLeast(0)), + ) + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewMessageShieldPreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewMessageShieldPreview.kt index f0a11081e1..32d4aded2b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewMessageShieldPreview.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewMessageShieldPreview.kt @@ -49,6 +49,7 @@ internal fun TimelineViewMessageShieldPreview() = ElementPreview { onReactionLongClick = { _, _ -> }, onMoreReactionsClick = {}, onReadReceiptClick = {}, + onGalleryItemClick = { _, _ -> }, forceJumpToBottomVisibility = true, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt index 6be00fc14a..36deec0468 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ATimelineItemEventRow.kt @@ -22,7 +22,6 @@ internal fun ATimelineItemEventRow( event: TimelineItem.Event, timelineMode: Timeline.Mode = Timeline.Mode.Live, timelineRoomInfo: TimelineRoomInfo = aTimelineRoomInfo(), - renderReadReceipts: Boolean = false, isLastOutgoingMessage: Boolean = false, timelineProtectionState: TimelineProtectionState = aTimelineProtectionState(), displayThreadSummaries: Boolean = false, @@ -30,11 +29,11 @@ internal fun ATimelineItemEventRow( event = event, timelineMode = timelineMode, timelineRoomInfo = timelineRoomInfo, - renderReadReceipts = renderReadReceipts, timelineProtectionState = timelineProtectionState, isLastOutgoingMessage = isLastOutgoingMessage, displayThreadSummaries = displayThreadSummaries, onEventClick = {}, + onGalleryItemClick = {}, onLongClick = {}, onLinkClick = {}, onLinkLongClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/FloatingDateBadge.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/FloatingDateBadge.kt index 996bb07b81..5946798a76 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/FloatingDateBadge.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/FloatingDateBadge.kt @@ -27,6 +27,8 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.hideFromAccessibility import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme @@ -102,7 +104,10 @@ internal fun BoxScope.FloatingDateBadgeOverlay( visible = showBadge, modifier = Modifier .align(Alignment.TopCenter) - .padding(top = 8.dp + topOffset), + .padding(top = 8.dp + topOffset) + .clearAndSetSemantics { + hideFromAccessibility() + }, enter = fadeIn(animationSpec = tween(150)), exit = fadeOut(animationSpec = tween(300)), ) { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt index 25a53cec2d..b6af359269 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt @@ -43,6 +43,7 @@ fun TimelineEventTimestampView( event: TimelineItem.Event, eventSink: (TimelineEvent.TimelineItemEvent) -> Unit, modifier: Modifier = Modifier, + isLayoutDirectionMismatched: Boolean = false, ) { val formattedTime = event.sentTime val hasError = event.failedToSend @@ -77,9 +78,16 @@ fun TimelineEventTimestampView( else -> Modifier } } + + val padding = if (!isLayoutDirectionMismatched) { + PaddingValues(start = TimelineEventTimestampViewDefaults.spacing) + } else { + PaddingValues(end = TimelineEventTimestampViewDefaults.spacing) + } + Row( modifier = Modifier - .padding(PaddingValues(start = TimelineEventTimestampViewDefaults.spacing)) + .padding(padding) // For a better click target, make the corners rounded .clip(RoundedCornerShape(8.dp)) .then(clickableModifier) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt index fea4f92de5..a7ab44db54 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt @@ -52,7 +52,6 @@ internal fun TimelineItemCallNotifyView( timelineRoomInfo: TimelineRoomInfo, event: TimelineItem.Event, content: TimelineItemRtcNotificationContent, - renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, onLongClick: (TimelineItem.Event) -> Unit, onReadReceiptsClick: (TimelineItem.Event) -> Unit, @@ -106,7 +105,6 @@ internal fun TimelineItemCallNotifyView( isLastOutgoingMessage = isLastOutgoingMessage, receipts = event.readReceiptState.receipts, ), - renderReadReceipts = renderReadReceipts, onReadReceiptsClick = { onReadReceiptsClick(event) }, modifier = Modifier.padding(top = 4.dp), ) @@ -146,8 +144,10 @@ private fun getIcon( @PreviewsDayNight @Composable internal fun TimelineItemCallNotifyViewPreview() = ElementPreview { - val readReceiptState = aTimelineItemReadReceipts( - receipts = List(3) { aReadReceiptData(it) }, + val readReceiptState = mutableListOf( + aTimelineItemReadReceipts( + receipts = List(3) { aReadReceiptData(it) }, + ) ) Column(modifier = Modifier.padding(bottom = 16.dp)) { listOf(false, true).forEach { isDm -> @@ -162,13 +162,10 @@ internal fun TimelineItemCallNotifyViewPreview() = ElementPreview { timelineRoomInfo = aTimelineRoomInfo(isDm = isDm), event = aTimelineItemEvent( content = content, - readReceiptState = readReceiptState, + // Only display read receipts for the first item + readReceiptState = readReceiptState.removeFirstOrNull() ?: aTimelineItemReadReceipts(), ), content = content, - // Render read receipts for the first item only - renderReadReceipts = !isDm && - callIntent == CallIntent.AUDIO && - state == RtcNotificationState.Started, isLastOutgoingMessage = false, onLongClick = {}, onReadReceiptsClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventContentForGalleryViewProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventContentForGalleryViewProvider.kt new file mode 100644 index 0000000000..ed790da8a2 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventContentForGalleryViewProvider.kt @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.components + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.messages.impl.timeline.components.event.aGalleryItem +import io.element.android.features.messages.impl.timeline.components.event.aTimelineItemGalleryContent +import io.element.android.features.messages.impl.timeline.model.event.GalleryItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent +import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemAttachmentsContent +import io.element.android.features.messages.impl.timeline.model.event.anAttachmentItem +import kotlin.time.Duration + +class TimelineItemEventContentForGalleryViewProvider : + PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aTimelineItemGalleryContent( + caption = "My vacation photos", + items = listOf( + aGalleryItem(), + aGalleryItem(), + aGalleryItem(), + aGalleryItem(), + ), + ), + aTimelineItemGalleryContent( + items = listOf( + aGalleryItem(), + aGalleryItem(), + ), + ), + aTimelineItemGalleryContent( + caption = "Three photos", + items = listOf( + aGalleryItem(), + aGalleryItem(), + aGalleryItem(), + ), + ), + aTimelineItemGalleryContent( + caption = "Many photos", + items = (1..8).map { aGalleryItem() }, + ), + aTimelineItemGalleryContent( + caption = "Videos", + items = listOf( + aGalleryItem( + type = GalleryItem.Type.Video, + duration = Duration.parse("PT1M30S") + ), + aGalleryItem( + type = GalleryItem.Type.Video, + duration = Duration.parse("PT45S") + ), + aGalleryItem(), + ), + ), + aTimelineItemAttachmentsContent( + caption = "Documents", + attachments = listOf( + anAttachmentItem( + filename = "document.pdf", + fileExtension = "pdf", + ), + anAttachmentItem( + filename = "presentation.pdf", + fileExtension = "pdf", + ), + anAttachmentItem( + filename = "spreadsheet.xlsx", + fileExtension = "xlsx", + ), + ), + ), + aTimelineItemAttachmentsContent( + caption = "Photos", + attachments = listOf( + anAttachmentItem( + filename = "photo1.jpg", + fileExtension = "jpg", + hasThumbnail = true, + ), + anAttachmentItem( + filename = "photo2.jpg", + fileExtension = "jpg", + hasThumbnail = true, + ), + anAttachmentItem( + filename = "photo3.jpg", + fileExtension = "jpg", + hasThumbnail = true, + ), + ), + ), + aTimelineItemAttachmentsContent( + caption = "Videos", + attachments = listOf( + anAttachmentItem( + filename = "video1.mp4", + fileExtension = "mp4", + hasThumbnail = true, + fileSize = 150_000_000L, + formattedFileSize = "150MB", + ), + anAttachmentItem( + filename = "video2.mov", + fileExtension = "mov", + hasThumbnail = true, + fileSize = 85_000_000L, + formattedFileSize = "85MB", + ), + ), + ), + aTimelineItemAttachmentsContent( + caption = "Audio", + attachments = listOf( + anAttachmentItem( + filename = "recording.mp3", + fileExtension = "mp3", + fileSize = 4_500_000L, + formattedFileSize = "4.5MB", + ), + anAttachmentItem( + filename = "voice_message.m4a", + fileExtension = "m4a", + fileSize = 1_200_000L, + formattedFileSize = "1.2MB", + ), + ), + ), + ) +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 936028cbd6..c73248af53 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -39,7 +39,9 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.platform.ViewConfiguration import androidx.compose.ui.res.pluralStringResource @@ -49,9 +51,12 @@ import androidx.compose.ui.semantics.hideFromAccessibility import androidx.compose.ui.semantics.isTraversalGroup import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.traversalIndex +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import androidx.constraintlayout.compose.ConstrainScope @@ -68,12 +73,16 @@ import io.element.android.features.messages.impl.timeline.components.receipt.Rea import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition +import io.element.android.features.messages.impl.timeline.model.TimelineItemReactions import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo import io.element.android.features.messages.impl.timeline.model.bubble.BubbleState +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent @@ -91,6 +100,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarType import io.element.android.libraries.designsystem.modifiers.niceClickable import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewWithExtraLargeHeight import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.USER_NAME_ALICE import io.element.android.libraries.designsystem.swipe.SwipeableActionsState @@ -106,6 +116,7 @@ import io.element.android.libraries.matrix.api.timeline.item.EmbeddedEventInfo import io.element.android.libraries.matrix.api.timeline.item.ThreadSummary import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import io.element.android.libraries.matrix.api.timeline.item.event.ProfileDetails import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl @@ -122,7 +133,9 @@ import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonPlurals import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.utils.a11y.isTalkbackActive +import io.element.android.libraries.ui.utils.text.detect import io.element.android.wysiwyg.link.Link +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.launch import kotlin.math.abs import kotlin.math.roundToInt @@ -142,10 +155,10 @@ fun TimelineItemEventRow( timelineMode: Timeline.Mode, timelineRoomInfo: TimelineRoomInfo, timelineProtectionState: TimelineProtectionState, - renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, displayThreadSummaries: Boolean, onEventClick: () -> Unit, + onGalleryItemClick: ((Int) -> Unit), onLongClick: () -> Unit, onLinkClick: (Link) -> Unit, onLinkLongClick: (Link) -> Unit, @@ -166,13 +179,14 @@ fun TimelineItemEventRow( content = event.content, hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId), onContentClick = onContentClick, + onGalleryItemClick = onGalleryItemClick, onLongClick = onLongClick, onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) }, onLinkClick = onLinkClick, onLinkLongClick = onLinkLongClick, eventSink = eventSink, modifier = contentModifier, - onContentLayoutChange = onContentLayoutChange + onContentLayoutChange = onContentLayoutChange, ) }, ) { @@ -296,7 +310,6 @@ fun TimelineItemEventRow( isLastOutgoingMessage = isLastOutgoingMessage, receipts = event.readReceiptState.receipts, ), - renderReadReceipts = renderReadReceipts, onReadReceiptsClick = { onReadReceiptClick(event) }, modifier = Modifier.padding(top = 4.dp) ) @@ -651,23 +664,44 @@ private fun MessageEventBubbleContent( .padding(horizontal = 4.dp, vertical = 2.dp) ) } - TimestampPosition.Aligned -> - ContentAvoidingLayout( - modifier = modifier, - // The spacing is negative to make the content overlap the empty space at the start of the timestamp - spacing = (-4).dp, - overlayOffset = DpOffset(0.dp, -1.dp), - shrinkContent = canShrinkContent, - content = { content(this::onContentLayoutChange) }, - overlay = { - TimelineEventTimestampView( - event = event, - eventSink = eventSink, - modifier = Modifier - .padding(horizontal = 8.dp, vertical = 4.dp) - ) + TimestampPosition.Aligned -> @Composable { + val originalLayoutDirection = LocalLayoutDirection.current + // Detect if the direction of the text content (if any) does not match the layout direction, to place the content and timestamp correctly + val contentDirection = if (event.content is TimelineItemTextContent) { + remember(event.content.body) { + when (TextDirection.detect(event.content.body)) { + TextDirection.Ltr, TextDirection.ContentOrLtr -> LayoutDirection.Ltr + TextDirection.Rtl, TextDirection.ContentOrRtl -> LayoutDirection.Rtl + else -> originalLayoutDirection + } } - ) + } else { + originalLayoutDirection + } + + CompositionLocalProvider(LocalLayoutDirection provides contentDirection) { + ContentAvoidingLayout( + modifier = modifier, + // The spacing is negative to make the content overlap the empty space at the start of the timestamp + spacing = (-4).dp, + overlayOffset = DpOffset(0.dp, -1.dp), + shrinkContent = canShrinkContent, + content = { content(this::onContentLayoutChange) }, + overlay = { + // Use the original layout direction for the timestamp + CompositionLocalProvider(LocalLayoutDirection provides originalLayoutDirection) { + TimelineEventTimestampView( + event = event, + eventSink = eventSink, + isLayoutDirectionMismatched = originalLayoutDirection != contentDirection, + modifier = Modifier + .padding(horizontal = 8.dp, vertical = 4.dp) + ) + } + } + ) + } + } TimestampPosition.Below -> Column(modifier) { content {} @@ -778,6 +812,8 @@ private fun MessageEventBubbleContent( val timestampPosition = when (val content = event.content) { is TimelineItemImageContent -> if (content.showCaption) TimestampPosition.Aligned else TimestampPosition.Overlay is TimelineItemVideoContent -> if (content.showCaption) TimestampPosition.Aligned else TimestampPosition.Overlay + is TimelineItemGalleryContent -> if (content.showCaption) TimestampPosition.Aligned else TimestampPosition.Below + is TimelineItemAttachmentsContent -> TimestampPosition.Below is TimelineItemStickerContent -> TimestampPosition.Overlay is TimelineItemLocationContent -> { val content = content.ensureActiveLiveLocation() @@ -792,6 +828,8 @@ private fun MessageEventBubbleContent( val paddingBehaviour = when (event.content) { is TimelineItemImageContent -> if (event.content.showCaption) ContentPadding.CaptionedMedia else ContentPadding.Media is TimelineItemVideoContent -> if (event.content.showCaption) ContentPadding.CaptionedMedia else ContentPadding.Media + is TimelineItemGalleryContent -> ContentPadding.CaptionedMedia + is TimelineItemAttachmentsContent -> ContentPadding.CaptionedMedia is TimelineItemStickerContent, is TimelineItemLocationContent -> ContentPadding.Media else -> ContentPadding.Textual @@ -881,6 +919,149 @@ internal fun TimelineItemEventRowWithThreadSummaryPreview() = ElementPreview { } } +@PreviewWithExtraLargeHeight +@Composable +internal fun TimelineItemEventRowRtlContentPreview() = ElementPreview { + Column { + Text( + modifier = Modifier + .fillMaxWidth() + .background(Color.LightGray) + .padding(8.dp), + text = "LTR layout direction", + textAlign = TextAlign.Center, + style = ElementTheme.typography.fontHeadingMdBold, + ) + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + sequenceOf(false, true).forEach { isMine -> + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "ظَة وَدَاع يَسْتَغْرِب فِيهَ" + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.First, + ) + ) + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "ظَة وَدَاع يَسْتَغْرِب فِيهَ", + isEdited = true, + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.Middle, + messageShield = MessageShield.UnknownDevice(isCritical = true), + ) + ) + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "ظَة وَدَاع \nيَسْتَغْرِب فِيهَ" + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.Middle, + ) + ) + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "ظَة وَدَاع يَسْتَغْرِب فِيهَا اَلشَّاعِر أَنْ لَا يَبْكِي مِنْ أَلَم اَلْفِرَاق،" + + " وَيَصِف حَالَة اَلْمُودِعِينَ" + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.Last, + ) + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + modifier = Modifier + .fillMaxWidth() + .background(Color.LightGray) + .padding(8.dp), + text = "RTL layout direction", + textAlign = TextAlign.Center, + style = ElementTheme.typography.fontHeadingMdBold, + ) + + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { + sequenceOf(false, true).forEach { isMine -> + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "ظَة وَدَاع يَسْتَغْرِب فِيهَا اَلشَّاعِر أَنْ لَا يَبْكِي مِنْ أَلَم اَلْفِرَاق،" + + " وَيَصِف حَالَة اَلْمُودِعِينَ", + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.First, + ) + ) + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "Testing\nLTR Line\nBreaks.", + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.Middle, + ) + ) + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "Testing a very long LTR text in an RTL layout." + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.Middle, + ) + ) + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "Testing LTR in RTL layout.", + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.Last, + messageShield = MessageShield.UnknownDevice(isCritical = true), + ) + ) + ATimelineItemEventRow( + event = aTimelineItemEvent( + senderDisplayName = "Sender with a super long name that should ellipsize", + isMine = isMine, + content = aTimelineItemTextContent( + body = "Testing LTR in RTL layout.", + isEdited = true, + ), + timelineItemReactions = TimelineItemReactions(persistentListOf()), + groupPosition = TimelineItemGroupPosition.Last, + messageShield = MessageShield.UnknownDevice(isCritical = true), + ) + ) + } + } + } +} + @PreviewsDayNight @Composable internal fun ThreadSummaryViewPreview() { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowGalleryPreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowGalleryPreview.kt new file mode 100644 index 0000000000..22c3f354f2 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowGalleryPreview.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewParameter +import io.element.android.features.messages.impl.timeline.aTimelineItemEvent +import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight + +@PreviewsDayNight +@Composable +internal fun TimelineItemEventRowWithGalleryPreview( + @PreviewParameter(TimelineItemEventContentForGalleryViewProvider::class) content: TimelineItemEventContent, +) = ElementPreview { + Column { + sequenceOf(false, true).forEach { isMine -> + ATimelineItemEventRow( + event = aTimelineItemEvent( + isMine = isMine, + content = content, + groupPosition = TimelineItemGroupPosition.Last, + ), + ) + } + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt index f46ba780f3..6ea1161605 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithRRPreview.kt @@ -37,7 +37,6 @@ internal fun TimelineItemEventRowWithRRPreview( timelineItemReactions = aTimelineItemReactions(count = 0), readReceiptState = TimelineItemReadReceipts(state.receipts), ), - renderReadReceipts = true, isLastOutgoingMessage = false, ) // A message from current user @@ -49,7 +48,6 @@ internal fun TimelineItemEventRowWithRRPreview( timelineItemReactions = aTimelineItemReactions(count = 0), readReceiptState = TimelineItemReadReceipts(state.receipts), ), - renderReadReceipts = true, isLastOutgoingMessage = false, ) // Another message from current user @@ -61,7 +59,6 @@ internal fun TimelineItemEventRowWithRRPreview( timelineItemReactions = aTimelineItemReactions(count = 0), readReceiptState = TimelineItemReadReceipts(state.receipts), ), - renderReadReceipts = true, isLastOutgoingMessage = true, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt index 12f7a52f99..ed927956df 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt @@ -34,7 +34,6 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.link.Link @Composable @@ -43,7 +42,6 @@ fun TimelineItemGroupedEventsRow( timelineMode: Timeline.Mode, timelineRoomInfo: TimelineRoomInfo, timelineProtectionState: TimelineProtectionState, - renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, focusedEventId: EventId?, displayThreadSummaries: Boolean, @@ -70,6 +68,7 @@ fun TimelineItemGroupedEventsRow( eventSink = eventSink, modifier = contentModifier, onContentClick = null, + onGalleryItemClick = {}, onLongClick = null, onContentLayoutChange = onContentLayoutChange ) @@ -89,7 +88,6 @@ fun TimelineItemGroupedEventsRow( timelineRoomInfo = timelineRoomInfo, timelineProtectionState = timelineProtectionState, focusedEventId = focusedEventId, - renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, displayThreadSummaries = displayThreadSummaries, onClick = onClick, @@ -117,7 +115,6 @@ private fun TimelineItemGroupedEventsRowContent( timelineRoomInfo: TimelineRoomInfo, timelineProtectionState: TimelineProtectionState, focusedEventId: EventId?, - renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, displayThreadSummaries: Boolean, onClick: (TimelineItem.Event) -> Unit, @@ -143,6 +140,7 @@ private fun TimelineItemGroupedEventsRowContent( eventSink = eventSink, modifier = contentModifier, onContentClick = null, + onGalleryItemClick = {}, onLongClick = null, onContentLayoutChange = onContentLayoutChange ) @@ -161,19 +159,12 @@ private fun TimelineItemGroupedEventsRowContent( ) if (isExpanded) { Column { - timelineItem.events.let { - if (isTalkbackActive()) { - it.reversed() - } else { - it - } - }.forEach { subGroupEvent -> + timelineItem.events.forEach { subGroupEvent -> TimelineItemRow( timelineMode = timelineMode, timelineItem = subGroupEvent, timelineRoomInfo = timelineRoomInfo, timelineProtectionState = timelineProtectionState, - renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, focusedEventId = focusedEventId, displayThreadSummaries = displayThreadSummaries, @@ -181,6 +172,7 @@ private fun TimelineItemGroupedEventsRowContent( onLinkClick = onLinkClick, onLinkLongClick = onLinkLongClick, onContentClick = onClick, + onGalleryItemClick = { _, _ -> }, onLongClick = onLongClick, inReplyToClick = inReplyToClick, onReactionClick = onReactionClick, @@ -193,14 +185,13 @@ private fun TimelineItemGroupedEventsRowContent( ) } } - } else if (renderReadReceipts) { + } else if (timelineItem.aggregatedReadReceipts.isNotEmpty()) { TimelineItemReadReceiptView( state = ReadReceiptViewState( sendState = null, isLastOutgoingMessage = false, receipts = timelineItem.aggregatedReadReceipts, ), - renderReadReceipts = true, onReadReceiptsClick = onExpandGroupClick ) } @@ -219,7 +210,6 @@ internal fun TimelineItemGroupedEventsRowContentExpandedPreview() = ElementPrevi timelineRoomInfo = aTimelineRoomInfo(), timelineProtectionState = aTimelineProtectionState(), focusedEventId = events.events.first().eventId, - renderReadReceipts = true, isLastOutgoingMessage = false, displayThreadSummaries = false, onClick = {}, @@ -247,7 +237,6 @@ internal fun TimelineItemGroupedEventsRowContentCollapsePreview() = ElementPrevi timelineRoomInfo = aTimelineRoomInfo(), timelineProtectionState = aTimelineProtectionState(), focusedEventId = null, - renderReadReceipts = true, isLastOutgoingMessage = false, displayThreadSummaries = false, onClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt index 5dc69bba8b..6a5cbfd9dd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt @@ -56,7 +56,6 @@ internal fun TimelineItemRow( timelineItem: TimelineItem, timelineMode: Timeline.Mode, timelineRoomInfo: TimelineRoomInfo, - renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, timelineProtectionState: TimelineProtectionState, focusedEventId: EventId?, @@ -65,6 +64,7 @@ internal fun TimelineItemRow( onLinkClick: (Link) -> Unit, onLinkLongClick: (Link) -> Unit, onContentClick: (TimelineItem.Event) -> Unit, + onGalleryItemClick: (TimelineItem.Event, Int) -> Unit, onLongClick: (TimelineItem.Event) -> Unit, inReplyToClick: (EventId) -> Unit, onReactionClick: (key: String, TimelineItem.Event) -> Unit, @@ -81,12 +81,13 @@ internal fun TimelineItemRow( hideMediaContent = timelineProtectionState.hideMediaContent(event.eventId, event.isMine), onShowContentClick = { timelineProtectionState.eventSink(TimelineProtectionEvent.ShowContent(event.eventId)) }, onContentClick = { onContentClick(event) }, + onGalleryItemClick = { index -> onGalleryItemClick(event, index) }, onLongClick = { onLongClick(event) }, onLinkClick = onLinkClick, onLinkLongClick = onLinkLongClick, eventSink = eventSink, modifier = contentModifier, - onContentLayoutChange = onContentLayoutChange + onContentLayoutChange = onContentLayoutChange, ) }, ) { @@ -114,7 +115,6 @@ internal fun TimelineItemRow( is TimelineItemStateContent, is TimelineItemLegacyCallInviteContent -> { TimelineItemStateEventRow( event = timelineItem, - renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, onClick = { onContentClick(timelineItem) }, onReadReceiptsClick = onReadReceiptClick, @@ -127,7 +127,6 @@ internal fun TimelineItemRow( timelineRoomInfo = timelineRoomInfo, event = timelineItem, content = timelineItem.content, - renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, onLongClick = onLongClick, onReadReceiptsClick = onReadReceiptClick, @@ -167,7 +166,6 @@ internal fun TimelineItemRow( event = timelineItem, timelineMode = timelineMode, timelineRoomInfo = timelineRoomInfo, - renderReadReceipts = renderReadReceipts, timelineProtectionState = timelineProtectionState, isLastOutgoingMessage = isLastOutgoingMessage, displayThreadSummaries = displayThreadSummaries, @@ -182,6 +180,7 @@ internal fun TimelineItemRow( onMoreReactionsClick = onMoreReactionsClick, onReadReceiptClick = onReadReceiptClick, onSwipeToReply = { onSwipeToReply(timelineItem) }, + onGalleryItemClick = { index -> onGalleryItemClick(timelineItem, index) }, eventSink = eventSink, eventContentView = { contentModifier, onContentLayoutChange -> eventContentView(timelineItem, contentModifier, onContentLayoutChange) @@ -196,7 +195,6 @@ internal fun TimelineItemRow( timelineMode = timelineMode, timelineRoomInfo = timelineRoomInfo, timelineProtectionState = timelineProtectionState, - renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, focusedEventId = focusedEventId, displayThreadSummaries = displayThreadSummaries, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt index 6e409f2b8d..a6015758fc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt @@ -39,7 +39,6 @@ import kotlinx.collections.immutable.persistentListOf @Composable fun TimelineItemStateEventRow( event: TimelineItem.Event, - renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, onClick: () -> Unit, onLongClick: () -> Unit, @@ -75,6 +74,7 @@ fun TimelineItemStateEventRow( onShowContentClick = {}, eventSink = eventSink, onContentClick = null, + onGalleryItemClick = {}, onLongClick = null, modifier = Modifier.defaultTimelineContentPadding() ) @@ -86,7 +86,6 @@ fun TimelineItemStateEventRow( isLastOutgoingMessage = isLastOutgoingMessage, receipts = event.readReceiptState.receipts, ), - renderReadReceipts = renderReadReceipts, onReadReceiptsClick = { onReadReceiptsClick(event) }, ) } @@ -104,7 +103,6 @@ internal fun TimelineItemStateEventRowPreview() = ElementPreview { receipts = persistentListOf(aReadReceiptData(0)), ) ), - renderReadReceipts = true, isLastOutgoingMessage = false, onClick = {}, onLongClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt index 4ac83c520b..5b66a7a9ba 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt @@ -10,7 +10,8 @@ package io.element.android.features.messages.impl.timeline.components.customreac import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -30,7 +31,9 @@ fun CustomReactionBottomSheet( onSelectEmoji: (EventOrTransactionId, Emoji) -> Unit, modifier: Modifier = Modifier, ) { - val sheetState = rememberModalBottomSheetState() + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + ) val coroutineScope = rememberCoroutineScope() val target = state.target as? CustomReactionState.Target.Success diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemAttachmentsContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemAttachmentsContentProvider.kt new file mode 100644 index 0000000000..9bc554057f --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemAttachmentsContentProvider.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.components.event + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent +import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemAttachmentsContent +import io.element.android.features.messages.impl.timeline.model.event.anAttachmentItem +import io.element.android.libraries.matrix.api.media.MediaSource + +class TimelineItemAttachmentsContentProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aTimelineItemAttachmentsContent( + body = "Files", + caption = null, + attachments = listOf( + anAttachmentItem( + filename = "document.pdf", + mimeType = "application/pdf", + fileSize = null, + formattedFileSize = "2.5 MB", + fileExtension = "PDF", + ), + anAttachmentItem( + filename = "spreadsheet.xlsx", + mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + fileSize = null, + formattedFileSize = "450 KB", + fileExtension = "XLSX", + ), + ), + ), + aTimelineItemAttachmentsContent( + body = "Files", + caption = "Files mixed with media", + attachments = listOf( + anAttachmentItem( + filename = "report.pdf", + mimeType = "application/pdf", + fileSize = null, + formattedFileSize = "3.2 MB", + fileExtension = "PDF", + ), + anAttachmentItem( + filename = "notes.txt", + mimeType = "text/plain", + fileSize = null, + formattedFileSize = "12 KB", + fileExtension = "TXT", + ), + anAttachmentItem( + filename = "photo.jpg", + mimeType = "image/jpeg", + thumbnailSource = MediaSource(url = "thumb", json = ""), + fileSize = null, + formattedFileSize = "1.2 MB", + fileExtension = "JPG", + ), + anAttachmentItem( + filename = "video.mp4", + mimeType = "video/mp4", + thumbnailSource = MediaSource(url = "thumb", json = ""), + fileSize = null, + formattedFileSize = "15 MB", + fileExtension = "MP4", + ), + ), + ), + ) +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemAttachmentsListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemAttachmentsListView.kt new file mode 100644 index 0000000000..e21da90e94 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemAttachmentsListView.kt @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.components.event + +import android.text.SpannedString +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayout +import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData +import io.element.android.features.messages.impl.timeline.model.event.AttachmentItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent +import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio +import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeImage +import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.matrix.ui.media.MediaRequestData +import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle +import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.wysiwyg.compose.EditorStyledText +import io.element.android.wysiwyg.link.Link + +@Composable +fun TimelineItemAttachmentsListView( + content: TimelineItemAttachmentsContent, + onGalleryItemClick: (Int) -> Unit, + onLinkClick: (Link) -> Unit, + onLinkLongClick: (Link) -> Unit, + onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + Column( + modifier = Modifier.fillMaxWidth(), + ) { + content.attachments.forEachIndexed { index, attachment -> + Column { + if (index > 0) { + HorizontalDivider( + color = ElementTheme.colors.borderInteractiveSecondary, + ) + } + AttachmentListItem( + attachment = attachment, + onClick = { onGalleryItemClick(index) }, + ) + } + } + } + if (content.showCaption) { + HorizontalDivider( + color = ElementTheme.colors.borderInteractiveSecondary, + ) + Spacer(modifier = Modifier.height(8.dp)) + val caption = if (LocalInspectionMode.current) { + SpannedString(content.caption) + } else { + content.formattedCaption ?: SpannedString(content.caption) + } + CompositionLocalProvider( + LocalContentColor provides ElementTheme.colors.textPrimary, + LocalTextStyle provides ElementTheme.typography.fontBodyLgRegular + ) { + EditorStyledText( + modifier = Modifier + .padding(horizontal = 4.dp) + .widthIn(min = 120.dp), + text = caption, + style = ElementRichTextEditorStyle.textStyle(), + onLinkClickedListener = onLinkClick, + onLinkLongClickedListener = onLinkLongClick, + releaseOnDetach = false, + onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange), + ) + } + } + } +} + +@Composable +private fun AttachmentListItem( + attachment: AttachmentItem, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val iconSize = 36.dp + val thumbnailSize = 36L + val spacing = 8.dp + Row( + modifier = modifier + .clickable(onClick = onClick) + .padding(vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(spacing), + ) { + Box( + modifier = Modifier + .size(iconSize) + .clip(RoundedCornerShape(4.dp)) + .background(ElementTheme.colors.bgCanvasDefault), + contentAlignment = Alignment.Center, + ) { + if (attachment.thumbnailSource != null) { + val isVideo = attachment.mimeType.isMimeTypeVideo() + AsyncImage( + model = MediaRequestData( + source = attachment.thumbnailSource, + kind = MediaRequestData.Kind.Thumbnail(thumbnailSize), + ), + contentDescription = attachment.filename, + contentScale = ContentScale.Crop, + modifier = Modifier + .size(iconSize) + .clip(RoundedCornerShape(4.dp)), + ) + if (isVideo) { + Box( + modifier = Modifier + .size(iconSize) + .background( + color = Color.Black.copy(alpha = 0.3f), + shape = RoundedCornerShape(4.dp) + ), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = CompoundIcons.VideoCallSolid(), + contentDescription = stringResource(CommonStrings.common_video), + tint = Color.White, + modifier = Modifier.size(20.dp), + ) + } + } + } else { + val isImage = attachment.mimeType.isMimeTypeImage() + val isVideo = attachment.mimeType.isMimeTypeVideo() + val isAudio = attachment.mimeType.isMimeTypeAudio() + val icon = when { + isImage -> CompoundIcons.Image() + isVideo -> CompoundIcons.VideoCall() + isAudio -> CompoundIcons.Audio() + else -> CompoundIcons.Attachment() + } + Icon( + imageVector = icon, + contentDescription = null, + tint = ElementTheme.colors.iconPrimary, + modifier = Modifier.size(24.dp), + ) + } + } + + Column( + modifier = Modifier.weight(1f), + ) { + Text( + text = attachment.filename, + color = ElementTheme.colors.textPrimary, + style = ElementTheme.typography.fontBodyLgRegular, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) + Text( + text = "${attachment.fileExtension} • ${attachment.formattedFileSize}", + color = ElementTheme.colors.textSecondary, + style = ElementTheme.typography.fontBodySmRegular, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } +} + +@PreviewsDayNight +@Composable +internal fun TimelineItemAttachmentsListViewPreview( + @PreviewParameter(TimelineItemAttachmentsContentProvider::class) content: TimelineItemAttachmentsContent +) = ElementPreview { + TimelineItemAttachmentsListView( + content = content, + onGalleryItemClick = {}, + onLinkClick = {}, + onLinkLongClick = {}, + onContentLayoutChange = {}, + ) +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt index 2044796889..2951d13d65 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt @@ -14,10 +14,12 @@ import io.element.android.features.messages.impl.timeline.TimelineEvent import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories import io.element.android.features.messages.impl.timeline.di.rememberPresenter +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent @@ -40,6 +42,7 @@ fun TimelineItemEventContentView( content: TimelineItemEventContent, hideMediaContent: Boolean, onContentClick: (() -> Unit)?, + onGalleryItemClick: ((Int) -> Unit), onLongClick: (() -> Unit)?, onShowContentClick: () -> Unit, onLinkClick: (Link) -> Unit, @@ -90,6 +93,23 @@ fun TimelineItemEventContentView( onContentLayoutChange = onContentLayoutChange, modifier = modifier, ) + is TimelineItemGalleryContent -> TimelineItemGalleryView( + content = content, + onGalleryItemClick = { index -> onGalleryItemClick(index) }, + onLongClick = onLongClick, + onLinkClick = onLinkClick, + onLinkLongClick = onLinkLongClick, + onContentLayoutChange = onContentLayoutChange, + modifier = modifier, + ) + is TimelineItemAttachmentsContent -> TimelineItemAttachmentsListView( + content = content, + onGalleryItemClick = { index -> onGalleryItemClick(index) }, + onLinkClick = onLinkClick, + onLinkLongClick = onLinkLongClick, + onContentLayoutChange = {}, + modifier = modifier, + ) is TimelineItemStickerContent -> TimelineItemStickerView( content = content, hideMediaContent = hideMediaContent, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemGalleryContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemGalleryContentProvider.kt new file mode 100644 index 0000000000..fe7de6a7f6 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemGalleryContentProvider.kt @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.components.event + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.messages.impl.timeline.model.event.GalleryItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent +import io.element.android.libraries.matrix.api.media.MediaSource +import kotlinx.collections.immutable.toImmutableList +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +class TimelineItemGalleryContentProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aTimelineItemGalleryContent( + caption = "My vacation photos", + items = listOf( + aGalleryItem(), + aGalleryItem(type = GalleryItem.Type.Video, duration = 65.seconds), + aGalleryItem(), + aGalleryItem(), + ), + ), + aTimelineItemGalleryContent( + items = listOf( + aGalleryItem(), + ), + ), + aTimelineItemGalleryContent( + items = listOf( + aGalleryItem(width = 1920, height = 1080), + aGalleryItem(width = 1600, height = 900), + ), + ), + aTimelineItemGalleryContent( + items = listOf( + aGalleryItem(width = 1080, height = 1920), + aGalleryItem(width = 900, height = 1600), + ), + ), + aTimelineItemGalleryContent( + items = listOf( + aGalleryItem(width = 1920, height = 1080), + aGalleryItem(width = 1080, height = 1920), + ), + ), + aTimelineItemGalleryContent( + items = listOf( + aGalleryItem(type = GalleryItem.Type.Video, duration = 45.seconds), + aGalleryItem(), + aGalleryItem(), + ), + ), + aTimelineItemGalleryContent( + caption = "2 landscape + 1 portrait", + items = listOf( + aGalleryItem(width = 1920, height = 1080), + aGalleryItem(width = 1600, height = 900), + aGalleryItem(width = 1080, height = 1920), + ), + ), + aTimelineItemGalleryContent( + caption = "1 landscape + 2 portrait", + items = listOf( + aGalleryItem(width = 1920, height = 1080), + aGalleryItem(width = 1080, height = 1920), + aGalleryItem(width = 900, height = 1600), + ), + ), + aTimelineItemGalleryContent( + items = listOf( + aGalleryItem(), + aGalleryItem(), + aGalleryItem(type = GalleryItem.Type.Video, duration = 120.seconds), + aGalleryItem(), + aGalleryItem(), + ), + ), + aTimelineItemGalleryContent( + caption = "Many photos", + items = (1..12).map { + aGalleryItem( + type = if (it == 3) GalleryItem.Type.Video else GalleryItem.Type.Image, + ) + }, + ), + ) +} + +fun aTimelineItemGalleryContent( + body: String = "Gallery", + caption: String? = null, + items: List = listOf( + aGalleryItem(), + aGalleryItem(), + aGalleryItem(), + aGalleryItem(), + ), +) = TimelineItemGalleryContent( + body = body, + caption = caption, + formattedCaption = null, + isEdited = false, + items = items.toImmutableList(), +) + +fun aGalleryItem( + filename: String = "photo.jpg", + type: GalleryItem.Type = GalleryItem.Type.Image, + width: Int = 400, + height: Int = 300, + duration: Duration = Duration.ZERO, +): GalleryItem { + return GalleryItem( + filename = filename, + mimeType = when (type) { + GalleryItem.Type.Video -> "video/mp4" + GalleryItem.Type.Audio -> "audio/mpeg" + GalleryItem.Type.File -> "application/pdf" + GalleryItem.Type.Image -> "image/jpeg" + }, + mediaSource = MediaSource(url = "", json = ""), + thumbnailSource = null, + width = width, + height = height, + thumbnailWidth = width, + thumbnailHeight = height, + blurhash = null, + type = type, + duration = duration, + ) +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemGalleryView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemGalleryView.kt new file mode 100644 index 0000000000..c51055da92 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemGalleryView.kt @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.components.event + +import android.text.SpannedString +import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayout +import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData +import io.element.android.features.messages.impl.timeline.model.event.GalleryItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent +import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.bgSubtleTertiary +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle +import io.element.android.libraries.ui.utils.time.formatShort +import io.element.android.wysiwyg.compose.EditorStyledText +import io.element.android.wysiwyg.link.Link +import kotlinx.collections.immutable.ImmutableList + +private const val MAX_TILES = 5 +private val GALLERY_WIDTH = 264.dp +private val GRID_SPACING = 4.dp +private val GROUP_CORNER_RADIUS = 6.dp + +private val SINGLE_IMAGE_HEIGHT = 130.dp +private val TWO_IMAGE_ROW_HEIGHT = 130.dp +private val THREE_IMAGE_ROW_HEIGHT = 85.dp + +@Composable +fun TimelineItemGalleryView( + content: TimelineItemGalleryContent, + onGalleryItemClick: (Int) -> Unit, + onLongClick: (() -> Unit)?, + onLinkClick: (Link) -> Unit, + onLinkLongClick: (Link) -> Unit, + onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, + modifier: Modifier = Modifier, +) { + val totalItems = content.items.size + val showOverflow = totalItems > MAX_TILES + val overflowCount = totalItems - MAX_TILES + Column(modifier = modifier) { + val containerModifier = Modifier.clip(RoundedCornerShape(GROUP_CORNER_RADIUS)) + Column( + modifier = containerModifier.width(GALLERY_WIDTH), + verticalArrangement = Arrangement.spacedBy(GRID_SPACING), + ) { + when (totalItems) { + 0 -> Unit + 1 -> SingleItemLayout( + item = content.items[0], + onClick = { onGalleryItemClick(0) }, + onLongClick = onLongClick, + ) + 2 -> TwoItemLayout( + items = content.items, + onItemClick = onGalleryItemClick, + onLongClick = onLongClick, + ) + 3 -> ThreeItemLayout( + items = content.items, + onItemClick = onGalleryItemClick, + onLongClick = onLongClick, + ) + else -> FourPlusItemLayout( + items = content.items, + showOverflow = showOverflow, + overflowCount = overflowCount, + onItemClick = onGalleryItemClick, + onLongClick = onLongClick, + ) + } + } + if (content.showCaption) { + Spacer(modifier = Modifier.height(8.dp)) + val caption = if (LocalInspectionMode.current) { + SpannedString(content.caption) + } else { + content.formattedCaption ?: SpannedString(content.caption) + } + CompositionLocalProvider( + LocalContentColor provides ElementTheme.colors.textPrimary, + LocalTextStyle provides ElementTheme.typography.fontBodyLgRegular + ) { + EditorStyledText( + modifier = Modifier + .padding(horizontal = 4.dp) + .widthIn(min = 120.dp), + text = caption, + style = ElementRichTextEditorStyle.textStyle(), + onLinkClickedListener = onLinkClick, + onLinkLongClickedListener = onLinkLongClick, + releaseOnDetach = false, + onTextLayout = ContentAvoidingLayout.measureLegacyLastTextLine(onContentLayoutChange = onContentLayoutChange), + ) + } + } + } +} + +@Composable +private fun SingleItemLayout( + item: GalleryItem, + onClick: () -> Unit, + onLongClick: (() -> Unit)?, +) { + GalleryItemCell( + item = item, + isLast = false, + remainingCount = 0, + onClick = onClick, + onLongClick = onLongClick, + modifier = Modifier + .width(GALLERY_WIDTH) + .height(SINGLE_IMAGE_HEIGHT), + ) +} + +@Composable +private fun TwoItemLayout( + items: ImmutableList, + onItemClick: (Int) -> Unit, + onLongClick: (() -> Unit)?, +) { + Column( + modifier = Modifier.width(GALLERY_WIDTH), + verticalArrangement = Arrangement.spacedBy(GRID_SPACING), + ) { + items.forEachIndexed { index, item -> + GalleryItemCell( + item = item, + isLast = false, + remainingCount = 0, + onClick = { onItemClick(index) }, + onLongClick = onLongClick, + modifier = Modifier + .fillMaxWidth() + .height(TWO_IMAGE_ROW_HEIGHT), + ) + } + } +} + +@Composable +private fun ThreeItemLayout( + items: ImmutableList, + onItemClick: (Int) -> Unit, + onLongClick: (() -> Unit)?, +) { + Column( + modifier = Modifier.width(GALLERY_WIDTH), + verticalArrangement = Arrangement.spacedBy(GRID_SPACING), + ) { + GalleryItemCell( + item = items[0], + isLast = false, + remainingCount = 0, + onClick = { onItemClick(0) }, + onLongClick = onLongClick, + modifier = Modifier + .fillMaxWidth() + .height(SINGLE_IMAGE_HEIGHT), + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(GRID_SPACING), + ) { + for (it in 1..2) { + GalleryItemCell( + item = items[it], + isLast = false, + remainingCount = 0, + onClick = { onItemClick(it) }, + onLongClick = onLongClick, + modifier = Modifier + .weight(1f) + .height(TWO_IMAGE_ROW_HEIGHT), + ) + } + } + } +} + +@Composable +private fun FourPlusItemLayout( + items: ImmutableList, + showOverflow: Boolean, + overflowCount: Int, + onItemClick: (Int) -> Unit, + onLongClick: (() -> Unit)?, +) { + Column( + modifier = Modifier.width(GALLERY_WIDTH), + verticalArrangement = Arrangement.spacedBy(GRID_SPACING), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(GRID_SPACING), + ) { + for (it in 0..1) { + GalleryItemCell( + item = items[it], + isLast = false, + remainingCount = 0, + onClick = { onItemClick(it) }, + onLongClick = onLongClick, + modifier = Modifier + .weight(1f) + .height(TWO_IMAGE_ROW_HEIGHT), + ) + } + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(GRID_SPACING), + ) { + val bottomRowItems = if (showOverflow) 3 else minOf(items.size - 2, 3) + val bottomRowHeight = if (bottomRowItems == 3) THREE_IMAGE_ROW_HEIGHT else TWO_IMAGE_ROW_HEIGHT + for (i in 0 until bottomRowItems) { + val itemIndex = 2 + i + if (itemIndex < items.size) { + val isOverflowItem = showOverflow && i == bottomRowItems - 1 + GalleryItemCell( + item = items[itemIndex], + isLast = isOverflowItem, + remainingCount = if (isOverflowItem) overflowCount else 0, + onClick = { onItemClick(itemIndex) }, + onLongClick = onLongClick, + modifier = Modifier + .weight(1f) + .height(bottomRowHeight), + ) + } + } + } + } +} + +@Composable +private fun GalleryItemCell( + item: GalleryItem, + isLast: Boolean, + remainingCount: Int, + onClick: () -> Unit, + onLongClick: (() -> Unit)?, + modifier: Modifier = Modifier, +) { + Box( + modifier = modifier + .blurHashBackground(item.blurhash, alpha = 0.9f) + .combinedClickable( + onClick = onClick, + onLongClick = onLongClick, + ), + contentAlignment = Alignment.Center, + ) { + AsyncImage( + modifier = Modifier.fillMaxSize(), + model = item.thumbnailMediaRequestData, + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + contentDescription = item.filename, + ) + + if (item.type == GalleryItem.Type.Video) { + VideoOverlay(duration = item.duration) + } + + if (isLast && remainingCount > 0) { + RemainingCountOverlay(count = remainingCount) + } + } +} + +@Composable +private fun VideoOverlay(duration: kotlin.time.Duration) { + val gradientColor = ElementTheme.colors.bgCanvasDefault + + Box(modifier = Modifier.fillMaxSize()) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(80.dp) + .align(Alignment.BottomCenter) + .background( + brush = Brush.verticalGradient( + colors = listOf(gradientColor.copy(alpha = 0f), gradientColor.copy(alpha = 1f)) + ) + ) + ) + Row( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter) + .padding(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = CompoundIcons.VideoCallSolid(), + contentDescription = null, + tint = ElementTheme.colors.textPrimary, + modifier = Modifier.size(16.dp), + ) + Spacer(modifier = Modifier.weight(1f)) + Text( + text = duration.formatShort(), + color = ElementTheme.colors.textPrimary, + style = ElementTheme.typography.fontBodySmMedium, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } +} + +@Composable +private fun RemainingCountOverlay(count: Int) { + Box( + modifier = Modifier + .fillMaxSize() + .background(ElementTheme.colors.bgSubtleTertiary.copy(alpha = 0.7f)), + contentAlignment = Alignment.Center, + ) { + Text( + text = "+$count", + color = Color.White, + style = ElementTheme.typography.fontHeadingSmMedium, + ) + } +} + +@PreviewsDayNight +@Composable +internal fun TimelineItemGalleryViewPreview( + @PreviewParameter(TimelineItemGalleryContentProvider::class) content: TimelineItemGalleryContent, +) = ElementPreview { + TimelineItemGalleryView( + content = content, + onGalleryItemClick = {}, + onLongClick = {}, + onLinkClick = {}, + onLinkLongClick = {}, + onContentLayoutChange = {}, + ) +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt index 04974dfbc5..a299d2f1ce 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/layout/ContentAvoidingLayout.kt @@ -15,13 +15,13 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout -import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.style.ResolvedTextDirection import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpOffset -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.designsystem.text.roundToPx import io.element.android.wysiwyg.compose.EditorStyledText import kotlin.math.max @@ -149,13 +149,13 @@ object ContentAvoidingLayout { onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, extraWidth: Dp = 0.dp, ): ((TextLayoutResult) -> Unit) { - val layoutDirection = LocalLayoutDirection.current val extraWidthPx = extraWidth.roundToPx() return { textLayout: TextLayoutResult -> // We need to add the external extra width so it's not taken into account as 'free space' - val lastLineWidth = when (layoutDirection) { - LayoutDirection.Ltr -> textLayout.getLineRight(textLayout.lineCount - 1).roundToInt() - LayoutDirection.Rtl -> textLayout.getLineLeft(textLayout.lineCount - 1).roundToInt() + val textDirection = tryOrNull { textLayout.getParagraphDirection(0) } + val lastLineWidth = when (textDirection) { + ResolvedTextDirection.Rtl -> textLayout.getLineLeft(textLayout.lineCount - 1).roundToInt() + else -> textLayout.getLineRight(textLayout.lineCount - 1).roundToInt() } val lastLineHeight = textLayout.getLineBottom(textLayout.lineCount - 1).roundToInt() onContentLayoutChange( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt index b03aaf01c1..c9b712eba7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt @@ -25,9 +25,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.hideFromAccessibility +import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.testTag import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -53,27 +54,15 @@ import kotlinx.collections.immutable.ImmutableList @Composable fun TimelineItemReadReceiptView( state: ReadReceiptViewState, - renderReadReceipts: Boolean, onReadReceiptsClick: () -> Unit, modifier: Modifier = Modifier, ) { if (state.receipts.isNotEmpty()) { - if (renderReadReceipts) { - ReadReceiptsRow( - modifier = modifier.clearAndSetSemantics { - hideFromAccessibility() - } - ) { - ReadReceiptsAvatars( - receipts = state.receipts, - modifier = Modifier - .clip(RoundedCornerShape(4.dp)) - .clickable { - onReadReceiptsClick() - } - .padding(2.dp) - ) - } + ReadReceiptsRow(modifier = modifier) { + ReadReceiptsAvatars( + receipts = state.receipts, + onClick = onReadReceiptsClick, + ) } } else { when (state.sendState) { @@ -132,7 +121,8 @@ private fun ReadReceiptsRow( @Composable private fun ReadReceiptsAvatars( receipts: ImmutableList, - modifier: Modifier = Modifier + onClick: () -> Unit, + modifier: Modifier = Modifier, ) { val avatarSize = AvatarSize.TimelineReadReceipt.dp val avatarStrokeSize = 1.dp @@ -140,9 +130,16 @@ private fun ReadReceiptsAvatars( val receiptDescription = computeReceiptDescription(receipts) Row( modifier = modifier + .clip(RoundedCornerShape(4.dp)) + .clickable( + onClick = onClick, + onClickLabel = stringResource(id = CommonStrings.a11y_read_receipts_tap_to_show_all_android), + ) + .padding(2.dp) .clearAndSetSemantics { testTag = TestTags.messageReadReceipts.value contentDescription = receiptDescription + role = Role.Button }, horizontalArrangement = Arrangement.spacedBy(4.dp - avatarStrokeSize), verticalAlignment = Alignment.CenterVertically, @@ -209,7 +206,6 @@ internal fun TimelineItemReadReceiptViewPreview( ) = ElementPreview { TimelineItemReadReceiptView( state = state, - renderReadReceipts = true, onReadReceiptsClick = {}, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt index 9637298d58..007e809972 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt @@ -9,13 +9,13 @@ package io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -44,7 +44,9 @@ internal fun ReadReceiptBottomSheet( ) { val isVisible = state.selectedEvent != null - val sheetState = rememberModalBottomSheetState() + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + ) val coroutineScope = rememberCoroutineScope() if (isVisible) { ModalBottomSheet( @@ -115,9 +117,9 @@ private fun ReadReceiptBottomSheetContent( @PreviewsDayNight @Composable -internal fun ReadReceiptBottomSheetPreview(@PreviewParameter(ReadReceiptBottomSheetStateProvider::class) state: ReadReceiptBottomSheetState) = ElementPreview { - Column { - ReadReceiptBottomSheetContent( +internal fun ReadReceiptBottomSheetPreview(@PreviewParameter(ReadReceiptBottomSheetStateProvider::class) state: ReadReceiptBottomSheetState) { + ElementPreview(fillMaxSize = true) { + ReadReceiptBottomSheet( state = state, onUserDataClick = {}, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt index 7b369fe6b7..1679a6030a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt @@ -64,22 +64,24 @@ class TimelineItemsFactory( suspend fun replaceWith( timelineItems: List, roomMembers: List, + renderReadReceipts: Boolean, ) = withContext(dispatchers.computation) { lock.withLock { diffCacheUpdater.updateWith(timelineItems) - buildAndEmitTimelineItemStates(timelineItems, roomMembers) + buildAndEmitTimelineItemStates(timelineItems, roomMembers, renderReadReceipts) } } private suspend fun buildAndEmitTimelineItemStates( timelineItems: List, roomMembers: List, + renderReadReceipts: Boolean, ) { val newTimelineItemStates = ArrayList() for (index in diffCache.indices().reversed()) { val cacheItem = diffCache.get(index) if (cacheItem == null) { - buildAndCacheItem(timelineItems, index, roomMembers)?.also { timelineItemState -> + buildAndCacheItem(timelineItems, index, roomMembers, renderReadReceipts)?.also { timelineItemState -> newTimelineItemStates.add(timelineItemState) } } else { @@ -87,7 +89,8 @@ class TimelineItemsFactory( eventItemFactory.update( timelineItem = cacheItem, receivedMatrixTimelineItem = timelineItems[index] as MatrixTimelineItem.Event, - roomMembers = roomMembers + roomMembers = roomMembers, + renderReadReceipts = renderReadReceipts, ) } else { cacheItem @@ -103,10 +106,11 @@ class TimelineItemsFactory( timelineItems: List, index: Int, roomMembers: List, + renderReadReceipts: Boolean, ): TimelineItem? { val timelineItem = when (val currentTimelineItem = timelineItems[index]) { - is MatrixTimelineItem.Event -> eventItemFactory.create(currentTimelineItem, index, timelineItems, roomMembers) + is MatrixTimelineItem.Event -> eventItemFactory.create(currentTimelineItem, index, timelineItems, roomMembers, renderReadReceipts) is MatrixTimelineItem.Virtual -> virtualItemFactory.create(currentTimelineItem) MatrixTimelineItem.Other -> null } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt index e2e5d0c03e..040d0450ff 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt @@ -14,10 +14,14 @@ import androidx.core.text.toSpannable import dev.zacsweers.metro.Inject import io.element.android.features.location.api.Location import io.element.android.features.messages.api.timeline.HtmlConverterProvider +import io.element.android.features.messages.impl.timeline.model.event.AttachmentItem +import io.element.android.features.messages.impl.timeline.model.event.GalleryItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEmoteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent @@ -35,6 +39,8 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent @@ -263,6 +269,144 @@ class TimelineItemContentMessageFactory( isEdited = content.isEdited, ) } + is GalleryMessageType -> { + val dom = messageType.formatted?.toHtmlDocument(permalinkParser = permalinkParser) + val formattedCaption = dom?.let(::parseHtml) + ?: messageType.body.withLinks() + val galleryItems = messageType.items.mapNotNull { item -> + when (item) { + is GalleryItemType.Image -> { + GalleryItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + type = GalleryItem.Type.Image, + thumbnailSource = item.content.info?.thumbnailSource, + width = item.content.info?.width?.toInt(), + height = item.content.info?.height?.toInt(), + thumbnailWidth = item.content.info?.thumbnailInfo?.width?.toInt(), + thumbnailHeight = item.content.info?.thumbnailInfo?.height?.toInt(), + blurhash = item.content.info?.blurhash, + ) + } + is GalleryItemType.Video -> { + GalleryItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + type = GalleryItem.Type.Video, + thumbnailSource = item.content.info?.thumbnailSource, + width = item.content.info?.width?.toInt(), + height = item.content.info?.height?.toInt(), + thumbnailWidth = item.content.info?.thumbnailInfo?.width?.toInt(), + thumbnailHeight = item.content.info?.thumbnailInfo?.height?.toInt(), + blurhash = item.content.info?.blurhash, + duration = item.content.info?.duration ?: Duration.ZERO, + ) + } + is GalleryItemType.Audio -> { + GalleryItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + type = GalleryItem.Type.Audio, + thumbnailSource = null, + width = null, + height = null, + thumbnailWidth = null, + thumbnailHeight = null, + blurhash = null, + duration = item.content.info?.duration ?: Duration.ZERO, + ) + } + is GalleryItemType.File -> { + GalleryItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + type = GalleryItem.Type.File, + thumbnailSource = item.content.info?.thumbnailSource, + width = null, + height = null, + thumbnailWidth = null, + thumbnailHeight = null, + blurhash = null, + ) + } + is GalleryItemType.Other -> null + } + } + val hasPreviews = galleryItems.any { it.thumbnailSource != null } + val isOnlyVisualMedia = galleryItems.all { item -> + item.type.isVisualMedia() + } + if (isOnlyVisualMedia && hasPreviews) { + TimelineItemGalleryContent( + body = messageType.body, + caption = messageType.body.trimEnd().takeIf { it.isNotEmpty() }, + formattedCaption = formattedCaption, + isEdited = content.isEdited, + items = galleryItems.toImmutableList(), + ) + } else { + val attachments = messageType.items.mapNotNull { item -> + when (item) { + is GalleryItemType.File -> { + AttachmentItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + thumbnailSource = item.content.info?.thumbnailSource, + fileSize = item.content.info?.size, + formattedFileSize = fileSizeFormatter.format(item.content.info?.size ?: 0L), + fileExtension = fileExtensionExtractor.extractFromName(item.content.filename), + ) + } + is GalleryItemType.Image -> { + AttachmentItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + thumbnailSource = item.content.info?.thumbnailSource, + fileSize = item.content.info?.size, + formattedFileSize = fileSizeFormatter.format(item.content.info?.size ?: 0L), + fileExtension = fileExtensionExtractor.extractFromName(item.content.filename), + ) + } + is GalleryItemType.Video -> { + AttachmentItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + thumbnailSource = item.content.info?.thumbnailSource, + fileSize = item.content.info?.size, + formattedFileSize = fileSizeFormatter.format(item.content.info?.size ?: 0L), + fileExtension = fileExtensionExtractor.extractFromName(item.content.filename), + ) + } + is GalleryItemType.Audio -> { + AttachmentItem( + filename = item.content.filename, + mimeType = item.content.info?.mimetype ?: MimeTypes.OctetStream, + mediaSource = item.content.source, + thumbnailSource = null, + fileSize = item.content.info?.size, + formattedFileSize = fileSizeFormatter.format(item.content.info?.size ?: 0L), + fileExtension = fileExtensionExtractor.extractFromName(item.content.filename), + ) + } + is GalleryItemType.Other -> null + } + } + TimelineItemAttachmentsContent( + body = messageType.body, + caption = messageType.body.trimEnd().takeIf { it.isNotEmpty() }, + formattedCaption = formattedCaption, + isEdited = content.isEdited, + attachments = attachments.toImmutableList(), + ) + } + } is OtherMessageType -> { val body = messageType.body.trimEnd() TimelineItemTextContent( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index cf515a0b51..a36755dc09 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -57,6 +57,7 @@ class TimelineItemEventFactory( index: Int, timelineItems: List, roomMembers: List, + renderReadReceipts: Boolean, ): TimelineItem.Event { val currentSender = currentTimelineItem.event.sender val groupPosition = @@ -116,7 +117,7 @@ class TimelineItemEventFactory( sentDate = sentDate, groupPosition = groupPosition, reactionsState = currentTimelineItem.computeReactionsState(), - readReceiptState = currentTimelineItem.computeReadReceiptState(roomMembers), + readReceiptState = currentTimelineItem.computeReadReceiptState(roomMembers, renderReadReceipts), localSendState = currentTimelineItem.event.localSendState, inReplyTo = currentTimelineItem.event.inReplyTo()?.map(permalinkParser = permalinkParser), threadInfo = mappedThreadInfo, @@ -133,9 +134,10 @@ class TimelineItemEventFactory( timelineItem: TimelineItem.Event, receivedMatrixTimelineItem: MatrixTimelineItem.Event, roomMembers: List, + renderReadReceipts: Boolean, ): TimelineItem.Event { return timelineItem.copy( - readReceiptState = receivedMatrixTimelineItem.computeReadReceiptState(roomMembers) + readReceiptState = receivedMatrixTimelineItem.computeReadReceiptState(roomMembers, renderReadReceipts) ) } @@ -180,8 +182,9 @@ class TimelineItemEventFactory( private fun MatrixTimelineItem.Event.computeReadReceiptState( roomMembers: List, + renderReadReceipts: Boolean, ): TimelineItemReadReceipts { - if (!config.computeReadReceipts) { + if (!config.computeReadReceipts || !renderReadReceipts) { return TimelineItemReadReceipts(receipts = persistentListOf()) } return TimelineItemReadReceipts( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt index 837692ae6f..8ebfcfc9d2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/Groupability.kt @@ -9,9 +9,11 @@ package io.element.android.features.messages.impl.timeline.groups import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent @@ -52,6 +54,8 @@ internal fun TimelineItem.Event.canBeGrouped(): Boolean { is TimelineItemTextBasedContent, is TimelineItemEncryptedContent, is TimelineItemImageContent, + is TimelineItemGalleryContent, + is TimelineItemAttachmentsContent, is TimelineItemStickerContent, is TimelineItemFileContent, is TimelineItemVideoContent, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/NewEventState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/NewEventState.kt index cac2798fdd..f80640dd0f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/NewEventState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/NewEventState.kt @@ -8,12 +8,15 @@ package io.element.android.features.messages.impl.timeline.model +import androidx.compose.runtime.Immutable + /** * Model if there is a new event in the timeline and if it is from me or from other. * This can be used to scroll to the bottom of the list when a new event is added. */ -enum class NewEventState { - None, - FromMe, - FromOther +@Immutable +sealed interface NewEventState { + data object None : NewEventState + data object FromMe : NewEventState + data object FromOther : NewEventState } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt index c9adba21da..1cbc2ec29c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt @@ -10,7 +10,9 @@ package io.element.android.features.messages.impl.timeline.model import androidx.compose.runtime.Immutable import io.element.android.features.messages.impl.timeline.components.MessageShieldData +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent @@ -124,6 +126,8 @@ sealed interface TimelineItem { is TimelineItemStickerContent -> content.formattedCaption == null && content.caption == null is TimelineItemImageContent -> content.formattedCaption == null && content.caption == null is TimelineItemVideoContent -> content.formattedCaption == null && content.caption == null + is TimelineItemGalleryContent -> false + is TimelineItemAttachmentsContent -> false else -> true } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAttachmentsContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAttachmentsContent.kt new file mode 100644 index 0000000000..66d28598a1 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAttachmentsContent.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.model.event + +import io.element.android.libraries.matrix.api.media.MediaSource +import kotlinx.collections.immutable.ImmutableList + +data class TimelineItemAttachmentsContent( + val body: String, + val caption: String?, + val formattedCaption: CharSequence?, + override val isEdited: Boolean, + val attachments: ImmutableList, +) : TimelineItemEventContent, TimelineItemEventMutableContent { + override val type: String = "TimelineItemAttachmentsContent" + + val showCaption = caption != null + + val hasPreviews = attachments.any { it.thumbnailSource != null } +} + +data class AttachmentItem( + val filename: String, + val mimeType: String, + val mediaSource: MediaSource, + val thumbnailSource: MediaSource?, + val fileSize: Long?, + val formattedFileSize: String, + val fileExtension: String, +) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt index 9c4c48d11e..5aa99fd4eb 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContent.kt @@ -56,7 +56,9 @@ fun TimelineItemEventContent.canBeForwarded(): Boolean = is TimelineItemAudioContent, is TimelineItemVideoContent, is TimelineItemLocationContent, - is TimelineItemVoiceContent -> true + is TimelineItemVoiceContent, + is TimelineItemGalleryContent, + is TimelineItemAttachmentsContent -> true // Stickers can't be forwarded (yet) so we don't show the option // See https://github.com/element-hq/element-x-android/issues/2161 is TimelineItemStickerContent -> false @@ -78,7 +80,9 @@ fun TimelineItemEventContent.canReact(): Boolean = is TimelineItemLocationContent, is TimelineItemPollContent, is TimelineItemVoiceContent, - is TimelineItemVideoContent -> true + is TimelineItemVideoContent, + is TimelineItemGalleryContent, + is TimelineItemAttachmentsContent -> true is TimelineItemStateContent, is TimelineItemRedactedContent, is TimelineItemLegacyCallInviteContent, @@ -99,6 +103,18 @@ fun TimelineItemEventContent.isEdited(): Boolean = when (this) { */ fun TimelineItemEventContent.isRedacted(): Boolean = this is TimelineItemRedactedContent +/** + * Returns the caption text for content types that support captions. + * Gallery and attachments content types have captions but don't implement + * [TimelineItemEventContentWithAttachment]. + */ +fun TimelineItemEventContent.captionOrNull(): String? = when (this) { + is TimelineItemEventContentWithAttachment -> caption + is TimelineItemGalleryContent -> caption + is TimelineItemAttachmentsContent -> caption + else -> null +} + fun TimelineItemEventContentWithAttachment.duration(): Duration? { return when (this) { is TimelineItemAudioContent -> duration diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt index 52e008e121..76502b2975 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEventContentProvider.kt @@ -13,7 +13,9 @@ import android.text.style.StyleSpan import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.core.text.buildSpannedString import androidx.core.text.inSpans +import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent +import kotlinx.collections.immutable.toImmutableList import org.jsoup.nodes.Document class TimelineItemEventContentProvider : PreviewParameterProvider { @@ -111,3 +113,39 @@ fun aTimelineItemStateEventContent( ) = TimelineItemStateEventContent( body = body, ) + +fun aTimelineItemAttachmentsContent( + body: String = "Attachments", + caption: String? = null, + attachments: List = listOf( + anAttachmentItem(filename = "document.pdf", fileExtension = "pdf"), + anAttachmentItem(filename = "recording.mp3", fileExtension = "mp3", fileSize = 4_500_000L, formattedFileSize = "4.5MB"), + ), +) = TimelineItemAttachmentsContent( + body = body, + caption = caption, + formattedCaption = null, + isEdited = false, + attachments = attachments.toImmutableList(), +) + +fun anAttachmentItem( + filename: String = "file.pdf", + fileExtension: String = "pdf", + fileSize: Long? = 1_000_000L, + formattedFileSize: String = "1MB", + mimeType: String? = null, + thumbnailSource: MediaSource? = null, + hasThumbnail: Boolean = false, +) = AttachmentItem( + filename = filename, + mimeType = mimeType ?: when { + hasThumbnail -> "image/jpeg" + else -> "application/$fileExtension" + }, + mediaSource = MediaSource(url = "", json = ""), + thumbnailSource = thumbnailSource ?: if (hasThumbnail) MediaSource(url = "", json = "") else null, + fileSize = fileSize, + formattedFileSize = formattedFileSize, + fileExtension = fileExtension, +) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemGalleryContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemGalleryContent.kt new file mode 100644 index 0000000000..f376a2a00a --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemGalleryContent.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.messages.impl.timeline.model.event + +import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.ui.media.MediaRequestData +import kotlinx.collections.immutable.ImmutableList +import kotlin.time.Duration + +data class TimelineItemGalleryContent( + val body: String, + val caption: String?, + val formattedCaption: CharSequence?, + override val isEdited: Boolean, + val items: ImmutableList, +) : TimelineItemEventContent, TimelineItemEventMutableContent { + override val type: String = "TimelineItemGalleryContent" + + val showCaption = caption != null +} + +data class GalleryItem( + val filename: String, + val mimeType: String, + val mediaSource: MediaSource, + val type: Type, + val thumbnailSource: MediaSource?, + val width: Int?, + val height: Int?, + val thumbnailWidth: Int?, + val thumbnailHeight: Int?, + val blurhash: String?, + val duration: Duration = Duration.ZERO, +) { + enum class Type { + Image, + Video, + Audio, + File; + + fun isVisualMedia() = this in setOf(Image, Video) + } + + val thumbnailMediaRequestData: MediaRequestData by lazy { + MediaRequestData( + source = thumbnailSource ?: mediaSource, + kind = MediaRequestData.Kind.Thumbnail( + width = thumbnailWidth?.toLong() ?: io.element.android.libraries.matrix.ui.media.MAX_THUMBNAIL_WIDTH, + height = thumbnailHeight?.toLong() ?: io.element.android.libraries.matrix.ui.media.MAX_THUMBNAIL_HEIGHT, + ), + ) + } + + val aspectRatio: Float? by lazy { + if (width != null && height != null && height > 0) { + width.toFloat() / height.toFloat() + } else { + null + } + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt index fcaa28a108..1106c3809e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineItem.kt @@ -9,10 +9,12 @@ package io.element.android.features.messages.impl.timeline.protection import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEmoteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent @@ -40,6 +42,8 @@ fun TimelineItem.mustBeProtected(): Boolean { } else { when (content) { is TimelineItemImageContent, + is TimelineItemGalleryContent, + is TimelineItemAttachmentsContent, is TimelineItemVideoContent, is TimelineItemStickerContent -> true is TimelineItemAudioContent, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt index 210e123595..4ef8600043 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/messagesummary/DefaultMessageSummaryFormatter.kt @@ -11,10 +11,12 @@ package io.element.android.features.messages.impl.utils.messagesummary import android.content.Context import dev.zacsweers.metro.ContributesBinding import io.element.android.features.messages.impl.timeline.model.event.RtcNotificationState +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent @@ -56,6 +58,16 @@ class DefaultMessageSummaryFormatter( is TimelineItemVideoContent -> context.getString(CommonStrings.common_video) is TimelineItemFileContent -> context.getString(CommonStrings.common_file) is TimelineItemAudioContent -> context.getString(CommonStrings.common_audio) + is TimelineItemGalleryContent -> context.getString(CommonStrings.common_gallery) + is TimelineItemAttachmentsContent -> { + val count = content.attachments.size + val extensions = content.attachments.take(3).joinToString { it.fileExtension } + if (count <= 3) { + extensions + } else { + "$extensions +${count - 3}" + } + } is TimelineItemLegacyCallInviteContent -> context.getString(CommonStrings.common_unsupported_call) is TimelineItemRtcNotificationContent -> when (content.state) { is RtcNotificationState.Declined -> { diff --git a/features/messages/impl/src/main/res/values-be/translations.xml b/features/messages/impl/src/main/res/values-be/translations.xml index 80a5df8d6b..8b40c72040 100644 --- a/features/messages/impl/src/main/res/values-be/translations.xml +++ b/features/messages/impl/src/main/res/values-be/translations.xml @@ -16,6 +16,8 @@ "Сімвалы" "Не атрымалася апрацаваць медыяфайл для загрузкі, паспрабуйце яшчэ раз." "Не атрымалася загрузіць медыяфайлы, паспрабуйце яшчэ раз." + "Апрацоўка…" + "Дадаць медыя" "Заблакіраваць карыстальніка" "Адзначце, ці хочаце вы схаваць усе бягучыя і будучыя паведамленні ад гэтага карыстальніка" "Гэтае паведамленне будзе перададзена адміністратару вашага хатняга сервера. Яны не змогуць прачытаць зашыфраваныя паведамленні." @@ -25,7 +27,7 @@ "Запісаць відэа" "Далучэнне" "Бібліятэка фота & відэа" - "Месцазнаходжанне" + "Абагуліць месцазнаходжанне" "Апытанне" "Фармаціраванне тэксту" "Гісторыя паведамленняў зараз недаступна." diff --git a/features/messages/impl/src/main/res/values-et/translations.xml b/features/messages/impl/src/main/res/values-et/translations.xml index 506b5ce195..86b1995f32 100644 --- a/features/messages/impl/src/main/res/values-et/translations.xml +++ b/features/messages/impl/src/main/res/values-et/translations.xml @@ -16,6 +16,18 @@ "Reisimine ja kohad" "Hiljutised emojid" "Sümbolid" + "Pööra pilti ümber rõhttelje" + "Pilt on pööratud ümber rõhttelje" + "Pildi algne variant" + "Pööra pilti ümber püsttelje" + "Pilt on pööratud ümber püsttelje" + "Pildi algne variant" + "Pööra pilti vasakule" + + "%1$d kraad" + "%1$d kraadi" + + "Muuda fotot" "Selgitused ja alapealkirjad ei pruugi olla nähtavad vanemate rakenduste kasutajatele." "Klõpsa üleslaaditava video kvaliteedi muutmiseks" "Faili üleslaadimine ei õnnestunud." @@ -26,6 +38,7 @@ "Objekt %1$d/%2$d" "Optimeeri pildikvaliteeti" "Töötlen…" + "Lisa meediumi" "Blokeeri kasutaja" "Vali see eelistus, kui sa soovid peita selle kasutaja kõik senised ja tulevased sõnumid" "Teade selle sõnumi kohta edastatakse sinu koduserveri haldajale. Haldajal ei ole võimalik lugeda krüptitud sõnumite sisu." diff --git a/features/messages/impl/src/main/res/values-fi/translations.xml b/features/messages/impl/src/main/res/values-fi/translations.xml index 33e8f64d57..881a5386e7 100644 --- a/features/messages/impl/src/main/res/values-fi/translations.xml +++ b/features/messages/impl/src/main/res/values-fi/translations.xml @@ -16,6 +16,18 @@ "Matkustaminen ja paikat" "Viimeaikaiset emojit" "Symbolit" + "Käännä kuva vaakasuunnassa" + "Käännetty vaakasuunnassa" + "Alkuperäinen" + "Käännä kuva pystysuunnassa" + "Käännetty pystysuunnassa" + "Alkuperäinen" + "Kierrä kuvaa vasemmalle" + + "%1$d aste" + "%1$d astetta" + + "Muokkaa kuvaa" "Kuvatekstit eivät välttämättä näy ihmisille, jotka käyttävät vanhempia sovelluksia." "Napauta muuttaaksesi videon lähetyslaatua" "Tiedostoa ei voitu lähettää." @@ -26,6 +38,7 @@ "Kohde %1$d / %2$d" "Optimoi kuvanlaatu" "Käsitellään…" + "Lisää mediaa" "Estä käyttäjä" "Valitse tämä, jos haluat piilottaa kaikki nykyiset ja tulevat viestit tältä käyttäjältä" "Tämä viesti ilmoitetaan kotipalvelimesi ylläpitäjälle. Ylläpitäjä ei pysty lukemaan salattuja viestejä." diff --git a/features/messages/impl/src/main/res/values-fr/translations.xml b/features/messages/impl/src/main/res/values-fr/translations.xml index 0d8dab284f..3505fd520d 100644 --- a/features/messages/impl/src/main/res/values-fr/translations.xml +++ b/features/messages/impl/src/main/res/values-fr/translations.xml @@ -16,6 +16,18 @@ "Voyages & lieux" "Emojis récents" "Symboles" + "Retourner l’image horizontalement" + "Retournée horizontalement" + "Originale" + "Retourner l’image verticalement" + "Retournée verticalement" + "Originale" + "Pivoter l’image vers la gauche" + + "%1$d degré" + "%1$d degrés" + + "Modifier la photo" "Les légendes peuvent ne pas être visibles pour les utilisateurs d’anciennes applications." "Cliquez pour modifier la qualité d’envoi de la vidéo" "Le fichier n’a pas pu être envoyé." @@ -26,6 +38,7 @@ "Élément %1$d sur %2$d" "Optimiser la qualité de l’image" "Traitement en cours…" + "Ajouter un média" "Bloquer l’utilisateur" "Cochez si vous souhaitez masquer tous les messages actuels et futurs de cet utilisateur." "Ce message sera signalé à l’administrateur de votre serveur d’accueil. Il ne pourra lire aucun message chiffré." diff --git a/features/messages/impl/src/main/res/values-hu/translations.xml b/features/messages/impl/src/main/res/values-hu/translations.xml index 3cbd86e8d1..bb33520cb6 100644 --- a/features/messages/impl/src/main/res/values-hu/translations.xml +++ b/features/messages/impl/src/main/res/values-hu/translations.xml @@ -16,6 +16,18 @@ "Utazás és helyek" "Legutóbbi emodzsik" "Szimbólumok" + "Kép vízszintes tükrözése" + "Vízszintesen tükrözve" + "Eredeti" + "Kép függőleges tükrözése" + "Függőlegesen tükrözve" + "Eredeti" + "Kép elforgatása balra" + + "%1$d fok" + "%1$d fok" + + "Fotó szerkesztése" "Előfordulhat, hogy a feliratok nem láthatók a régebbi alkalmazásokat használók számára." "Koppintson a feltöltött videók minőségének módosításához" "A fájl nem tölthető fel." @@ -26,6 +38,7 @@ "%1$d. elem / %2$d" "Képminőség optimalizációja" "Feldolgozás…" + "Média hozzáadása" "Felhasználó letiltása" "Jelölje be, ha el akarja rejteni az összes jelenlegi és jövőbeli üzenetet ettől a felhasználótól" "Ez az üzenet jelentve lesz a Matrix-kiszolgáló adminisztrátorának. Nem fogja tudni elolvasni a titkosított üzeneteket." diff --git a/features/messages/impl/src/main/res/values-in/translations.xml b/features/messages/impl/src/main/res/values-in/translations.xml index 7a0994f65e..0e0ff67a57 100644 --- a/features/messages/impl/src/main/res/values-in/translations.xml +++ b/features/messages/impl/src/main/res/values-in/translations.xml @@ -23,6 +23,7 @@ "Gagal mengunggah media, silakan coba lagi." "Ukuran file maksimum yang diizinkan adalah%1$s ." "Ukuran file terlalu besar untuk diunggah." + "Item %1$d dari %2$d" "Optimalkan kualitas gambar" "Memproses…" "Blokir pengguna" diff --git a/features/messages/impl/src/main/res/values-ja/translations.xml b/features/messages/impl/src/main/res/values-ja/translations.xml index 93c10d13d8..455996fd1a 100644 --- a/features/messages/impl/src/main/res/values-ja/translations.xml +++ b/features/messages/impl/src/main/res/values-ja/translations.xml @@ -16,6 +16,11 @@ "旅・場所" "最近使用" "記号" + "画像を左に回転" + + "%1$d°" + + "写真を編集" "古いアプリケーションを使用しているユーザーはキャプションを見られない可能性があります。" "動画のアップロード画質を変更するにはタップしてください" "ファイルをアップロードに失敗しました。" @@ -34,7 +39,7 @@ "カメラ" "写真を撮影" "動画を撮影" - "添付ファイル" + "ファイルを添付" "アルバムの写真と動画" "場所を共有" "投票" diff --git a/features/messages/impl/src/main/res/values-ko/translations.xml b/features/messages/impl/src/main/res/values-ko/translations.xml index daede9ec1d..fbcb0cab52 100644 --- a/features/messages/impl/src/main/res/values-ko/translations.xml +++ b/features/messages/impl/src/main/res/values-ko/translations.xml @@ -16,6 +16,11 @@ "여행 & 장소" "최근 이모지" "상징" + "이미지를 왼쪽으로 회전" + + "%1$d도" + + "사진 편집" "캡션은 오래된 앱을 사용하는 사용자에게 표시되지 않을 수 있습니다." "비디오 업로드 품질을 변경하려면 탭하세요" "파일을 업로드할 수 없습니다." @@ -26,6 +31,7 @@ "전체 %2$d개 중 %1$d번째 파일" "이미지 품질 최적화" "처리 중…" + "미디어 추가" "사용자 차단하기" "이 사용자의 현재 및 향후 모든 메시지를 숨기려면 확인하세요." "이 메시지는 홈서버의 관리자에게 보고되었습니다. 암호화된 메시지는 읽을 수 없습니다." diff --git a/features/messages/impl/src/main/res/values-pl/translations.xml b/features/messages/impl/src/main/res/values-pl/translations.xml index a0b9c24af2..d8ffaac54c 100644 --- a/features/messages/impl/src/main/res/values-pl/translations.xml +++ b/features/messages/impl/src/main/res/values-pl/translations.xml @@ -16,6 +16,19 @@ "Podróż i miejsca" "Ostatnie emoji" "Symbole" + "Odwróć obraz w poziomie" + "Odwrócono w poziomie" + "Oryginalny" + "Odwróć obraz w pionie" + "Odwrócono w pionie" + "Oryginalny" + "Obróć obraz w lewo" + + "%1$d stopień" + "%1$d stopnie" + "%1$d stopni" + + "Edytuj zdjęcie" "Opis może być niedostępny dla osób korzystających ze starszej wersji aplikacji." "Dotknij, aby zmienić jakość przesyłania wideo." "Nie udało się przesłać pliku." diff --git a/features/messages/impl/src/main/res/values-pt-rBR/translations.xml b/features/messages/impl/src/main/res/values-pt-rBR/translations.xml index 3e3fcf08d1..f93f0d71ca 100644 --- a/features/messages/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/messages/impl/src/main/res/values-pt-rBR/translations.xml @@ -35,7 +35,7 @@ "Gravar vídeo" "Anexo" "Biblioteca de fotos e vídeos" - "Localização" + "Compartilhar localização" "Enquete" "Formatação de texto" "O histórico de mensagens não está disponível no momento." diff --git a/features/messages/impl/src/main/res/values-ru/translations.xml b/features/messages/impl/src/main/res/values-ru/translations.xml index a7d22b6542..3744beff8f 100644 --- a/features/messages/impl/src/main/res/values-ru/translations.xml +++ b/features/messages/impl/src/main/res/values-ru/translations.xml @@ -16,16 +16,30 @@ "Путешествия и места" "Недавние эмодзи" "Символы" + "Перевернуть изображение по горизонтали" + "Перевернуто по горизонтали" + "Оригинал" + "Перевернуть изображение по вертикали" + "Перевернуто по вертикали" + "Оригинал" + "Повернуть изображение влево." + + "%1$d градус" + "%1$d градуса" + "%1$d градусов" + + "Редактировать фото" "Подпись может быть не видна пользователям старых приложений." "Нажмите, чтобы изменить качество загружаемого видео." "Файл не может быть загружен." - "Не удалось обработать медиафайл для загрузки, попробуйте еще раз." - "Не удалось загрузить медиафайлы, попробуйте еще раз." + "Не удалось обработать медиафайл для загрузки, попробуйте ещё раз." + "Не удалось загрузить медиафайлы, попробуйте ещё раз." "Максимальный размер файла: %1$s." "Файл слишком большой для загрузки." "%1$d из %2$d" "Оптимизировать качество изображения" "Обработка…" + "Добавить медиа" "Заблокировать пользователя" "Отметьте, хотите ли вы скрыть все текущие и будущие сообщения от этого пользователя" "Это сообщение будет передано администратору вашего домашнего сервера. Они не смогут прочитать зашифрованные сообщения." diff --git a/features/messages/impl/src/main/res/values-uk/translations.xml b/features/messages/impl/src/main/res/values-uk/translations.xml index a3035e9e08..cae9560768 100644 --- a/features/messages/impl/src/main/res/values-uk/translations.xml +++ b/features/messages/impl/src/main/res/values-uk/translations.xml @@ -2,11 +2,11 @@ "Відправник події не збігається з власником пристрою, який його надіслав." "Автентичність цього зашифрованого повідомлення не може бути гарантована на цьому пристрої." - "Зашифровано попередньо перевіреним користувачем." + "Зашифровано звіреним раніше користувачем." "Не зашифровано." "Зашифровано невідомим або видаленим пристроєм." - "Зашифровано пристроєм, який не верифіковано його власником." - "Зашифровано неверифікованим користувачем." + "Зашифровано пристроєм, який не звірено його власником." + "Зашифровано не звіреним користувачем." "Дії" "Прапори" "Їжа та напої" @@ -16,6 +16,19 @@ "Подорожі та місця" "Нещодавні емодзі" "Символи" + "Повернути зображення по горизонталі" + "Перевернуто по горизонталі" + "Оригінал" + "Повернути зображення по вертикалі" + "Перевернуто по вертикалі" + "Оригінал" + "Повернути зображення вліво" + + "%1$d градус" + "%1$d градуси" + "%1$d градусів" + + "Редагувати фото" "Користувачі старих застосунків можуть не бачити підписи." "Натисніть, щоб змінити якість вивантажуваного відео" "Файл не може бути вивантажено." @@ -26,6 +39,7 @@ "Елемент %1$d з %2$d" "Оптимізувати якість зображення" "Обробка…" + "Додати медіа" "Заблокувати користувача" "Перевірте, чи хочете ви приховати всі поточні та майбутні повідомлення від цього користувача" "Це повідомлення буде надіслано адміністраторам вашого домашнього сервера. Вони не зможуть прочитати зашифровані повідомлення." @@ -39,7 +53,7 @@ "Опитування" "Форматування тексту" "Історія повідомлень наразі недоступна." - "Історія повідомлень недоступна в цій кімнаті. Перевірте цей пристрій, щоб побачити історію повідомлень." + "Історія повідомлень недоступна в цій кімнаті. Звірте цей пристрій, щоб побачити історію повідомлень." "Чи хотіли б ви запросити їх знову?" "Ви одні в цій бесіді" "Сповістити всю кімнату" diff --git a/features/messages/impl/src/main/res/values-zh/translations.xml b/features/messages/impl/src/main/res/values-zh/translations.xml index bdd898d26f..e2300912ae 100644 --- a/features/messages/impl/src/main/res/values-zh/translations.xml +++ b/features/messages/impl/src/main/res/values-zh/translations.xml @@ -16,6 +16,17 @@ "文旅景点" "最近的 Emoji" "符号" + "水平翻转图像" + "水平翻转" + "原始" + "垂直翻转图像" + "垂直翻转" + "原始" + "向左旋转图像" + + "%1$d 度" + + "编辑照片" "使用旧版应用程序的用户可能无法看到字幕。" "点按以更改视频上传质量" "无法上传该文件。" diff --git a/features/messages/impl/src/main/res/values/localazy.xml b/features/messages/impl/src/main/res/values/localazy.xml index 908646b048..173a4e78ad 100644 --- a/features/messages/impl/src/main/res/values/localazy.xml +++ b/features/messages/impl/src/main/res/values/localazy.xml @@ -16,6 +16,12 @@ "Travel & Places" "Recent emojis" "Symbols" + "Flip image horizontally" + "Flipped horizontally" + "Original" + "Flip image vertically" + "Flipped vertically" + "Original" "Rotate the image to the left" "%1$d degree" diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPointTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPointTest.kt index dc50fca2c3..9679e23a23 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPointTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/DefaultMessagesEntryPointTest.kt @@ -23,6 +23,7 @@ import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.messages.impl.pinned.banner.createPinnedEventsTimelineProvider import io.element.android.features.messages.impl.timeline.createTimelineController import io.element.android.features.poll.test.create.FakeCreatePollEntryPoint +import io.element.android.libraries.androidutils.system.DeviceHasVulkanSupport import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId @@ -42,6 +43,7 @@ import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode import io.element.android.tests.testutils.testCoroutineDispatchers +import io.mockk.mockk import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -85,6 +87,7 @@ class DefaultMessagesEntryPointTest { knockRequestsListEntryPoint = FakeKnockRequestsListEntryPoint(), dateFormatter = FakeDateFormatter(), coroutineDispatchers = testCoroutineDispatchers(), + hasVulkanSupport = DeviceHasVulkanSupport(mockk(relaxed = true)) ) } val callback = object : MessagesEntryPoint.Callback { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt index be44c64a5a..5d2dceaf31 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt @@ -29,7 +29,6 @@ import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipeRight import androidx.compose.ui.test.v2.runAndroidComposeUiTest import androidx.compose.ui.text.AnnotatedString -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.emojibasebindings.Emoji import io.element.android.emojibasebindings.EmojibaseCategory import io.element.android.emojibasebindings.EmojibaseStore @@ -69,6 +68,7 @@ import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureCalledOnceWithTwoParamsAndResult import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalledWithParam +import io.element.android.tests.testutils.EnsureNeverCalledWithThreeParamsAndResult import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParamsAndResult import io.element.android.tests.testutils.EventsRecorder @@ -78,16 +78,15 @@ import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import kotlin.time.Duration.Companion.milliseconds -@RunWith(AndroidJUnit4::class) -class MessagesViewTest { +class MessagesViewTest : RobolectricTest() { @Test fun `clicking on back invoke expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) @@ -238,7 +237,6 @@ class MessagesViewTest { val eventsRecorder = EventsRecorder() val state = aMessagesState( timelineState = aTimelineState( - renderReadReceipts = true, timelineItems = persistentListOf( aTimelineItemEvent( readReceiptState = aTimelineItemReadReceipts( @@ -688,6 +686,7 @@ private fun AndroidComposeUiTest.setMessagesView( onBackClick: () -> Unit = EnsureNeverCalled(), onRoomDetailsClick: () -> Unit = EnsureNeverCalled(), onEventClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean = EnsureNeverCalledWithTwoParamsAndResult(), + onGalleryEventItemClick: (isLive: Boolean, event: TimelineItem.Event, index: Int) -> Boolean = EnsureNeverCalledWithThreeParamsAndResult(), onUserDataClick: (UserId) -> Unit = EnsureNeverCalledWithParam(), onLinkClick: (String, Boolean) -> Unit = EnsureNeverCalledWithTwoParams(), onSendLocationClick: () -> Unit = EnsureNeverCalled(), @@ -704,6 +703,7 @@ private fun AndroidComposeUiTest.setMessagesView( onBackClick = onBackClick, onRoomDetailsClick = onRoomDetailsClick, onEventContentClick = onEventClick, + onGalleryEventItemClick = onGalleryEventItemClick, onUserDataClick = onUserDataClick, onLinkClick = onLinkClick, onSendLocationClick = onSendLocationClick, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index 140d4f8ea3..8370ec516f 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -33,6 +33,7 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo +import io.element.android.libraries.matrix.api.media.GalleryItemInfo import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder @@ -64,11 +65,13 @@ import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.test import io.element.android.tests.testutils.testCoroutineDispatchers import io.mockk.every import io.mockk.mockk import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -76,14 +79,11 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import java.io.File import kotlin.io.path.createTempFile @Suppress("LargeClass") -@RunWith(RobolectricTestRunner::class) -class AttachmentsPreviewPresenterTest { +class AttachmentsPreviewPresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() @@ -94,6 +94,7 @@ class AttachmentsPreviewPresenterTest { @Test fun `present - initial state`() = runTest { createAttachmentsPreviewPresenter().test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) } @@ -118,13 +119,14 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing(displayProgress = false)) initialState.eventSink(AttachmentsPreviewEvent.SendAttachment) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing(displayProgress = true)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(mediaUploadInfo)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(mediaUploadInfo)) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(listOf(mediaUploadInfo))) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(listOf(mediaUploadInfo))) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() @@ -152,6 +154,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) // Pre-processing finishes @@ -159,8 +162,8 @@ class AttachmentsPreviewPresenterTest { advanceUntilIdle() assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing(displayProgress = false)) initialState.eventSink(AttachmentsPreviewEvent.SendAttachment) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(mediaUploadInfo)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(mediaUploadInfo)) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(listOf(mediaUploadInfo))) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(listOf(mediaUploadInfo))) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() @@ -188,6 +191,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing(displayProgress = false)) @@ -195,8 +199,8 @@ class AttachmentsPreviewPresenterTest { // Pre-processing finishes processLatch.complete(Unit) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing(displayProgress = true)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(mediaUploadInfo)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(mediaUploadInfo)) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(listOf(mediaUploadInfo))) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(listOf(mediaUploadInfo))) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Done) sendFileResult.assertions().isCalledOnce() onDoneListener.assertions().isCalledOnce() @@ -217,6 +221,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvent.SendAttachment) @@ -240,6 +245,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) // Pre-processing finishes @@ -262,6 +268,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvent.CancelAndDismiss) @@ -293,6 +300,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.textEditorState.setMarkdown(A_CAPTION) @@ -334,6 +342,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.textEditorState.setMarkdown(A_CAPTION) @@ -375,6 +384,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = { onDoneListener() }, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.textEditorState.setMarkdown(A_CAPTION) @@ -409,22 +419,19 @@ class AttachmentsPreviewPresenterTest { ) val presenter = createAttachmentsPreviewPresenter(room = room, onDoneListener = onDoneListenerResult) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvent.SendAttachment) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing(displayProgress = false)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(mediaUploadInfo)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(mediaUploadInfo)) - - // Check that the onDoneListener is called so the screen would be dismissed - onDoneListenerResult.assertions().isCalledOnce() - + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(listOf(mediaUploadInfo))) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(listOf(mediaUploadInfo))) val failureState = awaitItem() - assertThat(failureState.sendActionState).isEqualTo(SendActionState.Failure(failure, mediaUploadInfo)) + assertThat(failureState.sendActionState).isEqualTo(SendActionState.Failure(failure, listOf(mediaUploadInfo))) sendFileResult.assertions().isCalledOnce() failureState.eventSink(AttachmentsPreviewEvent.CancelAndClearSendState) val clearedState = awaitLastSequentialItem() - assertThat(clearedState.sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(mediaUploadInfo)) + assertThat(clearedState.sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(listOf(mediaUploadInfo))) } } @@ -442,19 +449,17 @@ class AttachmentsPreviewPresenterTest { onDoneListener = onDoneListenerResult, ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.sendActionState).isEqualTo(SendActionState.Idle) initialState.eventSink(AttachmentsPreviewEvent.SendAttachment) assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Processing(displayProgress = false)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(mediaUploadInfo)) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(mediaUploadInfo)) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(listOf(mediaUploadInfo))) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.Uploading(listOf(mediaUploadInfo))) initialState.eventSink(AttachmentsPreviewEvent.CancelAndClearSendState) - assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(mediaUploadInfo)) + assertThat(awaitItem().sendActionState).isEqualTo(SendActionState.Sending.ReadyToUpload(listOf(mediaUploadInfo))) // The sending is cancelled and the state is kept at ReadyToUpload ensureAllEventsConsumed() - - // Check that the onDoneListener is called so the screen would be dismissed - onDoneListenerResult.assertions().isCalledOnce() } } @@ -466,7 +471,7 @@ class AttachmentsPreviewPresenterTest { val maxUploadSize = 999L // Set a max upload size smaller than the file size val presenter = createAttachmentsPreviewPresenter( - localMedia = localMedia, + attachments = listOf(Attachment.Media(localMedia)), room = FakeJoinedRoom( liveTimeline = FakeTimeline().apply { sendFileLambda = { _, _, _, _, _ -> @@ -477,6 +482,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = onDoneListenerResult, mediaOptimizationSelectorPresenterFactory = FakeMediaOptimizationSelectorPresenterFactory { MediaOptimizationSelectorState( + index = 0, // Set a max upload size smaller than the file size maxUploadSize = AsyncData.Success(maxUploadSize), videoSizeEstimations = AsyncData.Uninitialized, @@ -505,7 +511,7 @@ class AttachmentsPreviewPresenterTest { val localMedia = aLocalMedia(uri = Uri.EMPTY, mediaInfo = aVideoMediaInfo()) val presenter = createAttachmentsPreviewPresenter( - localMedia = localMedia, + attachments = listOf(Attachment.Media(localMedia)), room = FakeJoinedRoom( liveTimeline = FakeTimeline().apply { sendFileLambda = { _, _, _, _, _ -> @@ -516,6 +522,7 @@ class AttachmentsPreviewPresenterTest { onDoneListener = onDoneListenerResult, mediaOptimizationSelectorPresenterFactory = FakeMediaOptimizationSelectorPresenterFactory { MediaOptimizationSelectorState( + index = 0, // Set a max upload size smaller than the file size maxUploadSize = AsyncData.Success(Long.MAX_VALUE), videoSizeEstimations = AsyncData.Success( @@ -573,6 +580,7 @@ class AttachmentsPreviewPresenterTest { ) presenter.test { + skipItems(1) val initialState = awaitItem() initialState.eventSink(AttachmentsPreviewEvent.OpenImageEditor) val editorState = awaitItem() @@ -586,7 +594,7 @@ class AttachmentsPreviewPresenterTest { assertThat(awaitItem().isApplyingImageEdits).isTrue() val appliedState = awaitItem() - assertThat((appliedState.attachment as Attachment.Media).localMedia.uri).isEqualTo(editedUri) + assertThat((appliedState.attachments.first() as Attachment.Media).localMedia.uri).isEqualTo(editedUri) assertThat(appliedState.imageEditorState).isNull() assertThat(appliedState.isApplyingImageEdits).isFalse() } @@ -603,7 +611,7 @@ class AttachmentsPreviewPresenterTest { bottom = 0.9f, ) val presenter = createAttachmentsPreviewPresenter( - localMedia = originalLocalMedia, + attachments = listOf(Attachment.Media(originalLocalMedia)), displayMediaQualitySelectorViews = true, attachmentImageEditor = FakeAttachmentImageEditor { Result.success( @@ -624,10 +632,14 @@ class AttachmentsPreviewPresenterTest { val croppedState = awaitItem() croppedState.eventSink(AttachmentsPreviewEvent.RotateImageToTheLeft) val rotatedState = awaitItem() - rotatedState.eventSink(AttachmentsPreviewEvent.ApplyImageEdits) + rotatedState.eventSink(AttachmentsPreviewEvent.FlipImageHorizontally) + val flippedHorizontallyState = awaitItem() + flippedHorizontallyState.eventSink(AttachmentsPreviewEvent.FlipImageVertically) + val flippedState = awaitItem() + flippedState.eventSink(AttachmentsPreviewEvent.ApplyImageEdits) val appliedState = consumeItemsUntilPredicate { !it.isApplyingImageEdits && it.imageEditorState == null }.last() - assertThat((appliedState.attachment as Attachment.Media).localMedia.uri).isEqualTo(editedUri) + assertThat((appliedState.attachments.first() as Attachment.Media).localMedia.uri).isEqualTo(editedUri) appliedState.eventSink(AttachmentsPreviewEvent.OpenImageEditor) val reopenedState = consumeItemsUntilPredicate { it.imageEditorState != null }.last() @@ -638,27 +650,59 @@ class AttachmentsPreviewPresenterTest { right = cropRect.bottom, bottom = 1f - cropRect.left, ) - reopenedState.imageEditorState.edits.cropRect.assertIsSimilarTo(rotatedCropRect) + val flippedCropRect = NormalizedCropRect( + left = 1f - rotatedCropRect.right, + top = 1f - rotatedCropRect.bottom, + right = 1f - rotatedCropRect.left, + bottom = 1f - rotatedCropRect.top, + ) + reopenedState.imageEditorState.edits.cropRect.assertIsSimilarTo(flippedCropRect) assertThat(reopenedState.imageEditorState.edits.rotationQuarterTurns).isEqualTo(3) assertThat(reopenedState.imageEditorState.edits.rotationDegrees).isEqualTo(270) + assertThat(reopenedState.imageEditorState.edits.isFlippedHorizontally).isTrue() + assertThat(reopenedState.imageEditorState.edits.isFlippedVertically).isTrue() } } + @Test + fun `present - image editor flip events update edits`() = runTest { + val presenter = createAttachmentsPreviewPresenter(displayMediaQualitySelectorViews = true) + + presenter.test { + val initialState = awaitItem() + initialState.eventSink(AttachmentsPreviewEvent.OpenImageEditor) + val editorState = consumeItemsUntilPredicate { it.imageEditorState != null }.last() + + editorState.eventSink(AttachmentsPreviewEvent.FlipImageHorizontally) + val flippedHorizontallyState = awaitItem() + assertThat(flippedHorizontallyState.imageEditorState?.edits?.isFlippedHorizontally).isTrue() + + flippedHorizontallyState.eventSink(AttachmentsPreviewEvent.FlipImageVertically) + val flippedState = awaitItem() + assertThat(flippedState.imageEditorState?.edits?.isFlippedVertically).isTrue() + } + } + + @Test fun `present - sendAsFile attachment is pre-processed without image compression`() = runTest { // Even though the user has enabled "Optimize media quality" globally, picking the file // through the Files picker (sendAsFile = true) must skip compression. Regression test // for https://github.com/element-hq/element-x-android/issues/6365 val mediaPreProcessor = FakeMediaPreProcessor() val presenter = createAttachmentsPreviewPresenter( - localMedia = aLocalMedia(mockMediaUrl, anImageMediaInfo()), - sendAsFile = true, + attachments = listOf( + Attachment.Media( + localMedia = aLocalMedia(mockMediaUrl, anImageMediaInfo()), + sendAsFile = true, + ) + ), mediaPreProcessor = mediaPreProcessor, // Selector views are hidden in the sendAsFile flow, which triggers the auto pre-process path. displayMediaQualitySelectorViews = false, mediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider( config = MediaOptimizationConfig( - compressImages = true, - videoCompressionPreset = VideoCompressionPreset.STANDARD, + compressImages = false, + videoCompressionPreset = VideoCompressionPreset.HIGH, ) ), ) @@ -743,9 +787,11 @@ class AttachmentsPreviewPresenterTest { fileExtension = "png", ), ) - val presenter = createAttachmentsPreviewPresenter(localMedia = localMedia) - + val presenter = createAttachmentsPreviewPresenter( + attachments = listOf(Attachment.Media(localMedia)), + ) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState.canEditImage).isTrue() @@ -766,7 +812,7 @@ class AttachmentsPreviewPresenterTest { ), ) val presenter = createAttachmentsPreviewPresenter( - localMedia = localMedia, + attachments = listOf(Attachment.Media(localMedia)), attachmentImageEditor = FakeAttachmentImageEditor( canEditResult = true, ) { @@ -793,13 +839,18 @@ class AttachmentsPreviewPresenterTest { fun `present - sendAsFile video is pre-processed with best fitting preset`() = runTest { val mediaPreProcessor = FakeMediaPreProcessor() val presenter = createAttachmentsPreviewPresenter( - localMedia = aLocalMedia(mockMediaUrl, aVideoMediaInfo()), - sendAsFile = true, + attachments = listOf( + Attachment.Media( + localMedia = aLocalMedia(mockMediaUrl, aVideoMediaInfo()), + sendAsFile = true, + ) + ), mediaPreProcessor = mediaPreProcessor, // Selector views are hidden in the sendAsFile flow, which triggers the auto pre-process path. displayMediaQualitySelectorViews = false, mediaOptimizationSelectorPresenterFactory = FakeMediaOptimizationSelectorPresenterFactory { MediaOptimizationSelectorState( + index = 0, maxUploadSize = AsyncData.Success(250_000_000L), videoSizeEstimations = AsyncData.Success( persistentListOf( @@ -834,11 +885,62 @@ class AttachmentsPreviewPresenterTest { } } + @Test + fun `present - sending gallery after image edits restarts preprocessing`() = runTest { + val sendGalleryResult = + lambdaRecorder, String?, String?, EventId?, Result> { _, _, _, _ -> + Result.success(FakeMediaUploadHandler()) + } + val firstLocalMedia = aLocalMedia(uri = Uri.parse("file:///tmp/original-1.jpeg")) + val secondLocalMedia = aLocalMedia(uri = Uri.parse("file:///tmp/original-2.jpeg")) + val editedUri = Uri.parse("file:///tmp/edited-1.jpeg") + val onDoneListener = lambdaRecorder { } + val presenter = createAttachmentsPreviewPresenter( + room = FakeJoinedRoom( + liveTimeline = FakeTimeline().apply { + sendGalleryLambda = sendGalleryResult + }, + ), + attachments = persistentListOf( + aMediaAttachment(firstLocalMedia), + aMediaAttachment(secondLocalMedia), + ), + displayMediaQualitySelectorViews = false, + attachmentImageEditor = FakeAttachmentImageEditor { + Result.success( + EditedLocalMedia( + localMedia = firstLocalMedia.copy(uri = editedUri), + file = File("/tmp/edited-1.jpeg"), + ) + ) + }, + onDoneListener = OnDoneListener { onDoneListener() }, + ) + + presenter.test { + val initialState = awaitItem() + initialState.eventSink(AttachmentsPreviewEvent.OpenImageEditor) + val editorState = consumeItemsUntilPredicate { it.imageEditorState != null }.last() + + editorState.eventSink(AttachmentsPreviewEvent.ApplyImageEdits) + val appliedState = consumeItemsUntilPredicate { !it.isApplyingImageEdits && it.imageEditorState == null }.last() + + appliedState.eventSink(AttachmentsPreviewEvent.SendAttachment) + consumeItemsUntilPredicate { it.sendActionState == SendActionState.Done } + + sendGalleryResult.assertions().isCalledOnce() + onDoneListener.assertions().isCalledOnce() + } + } + private fun TestScope.createAttachmentsPreviewPresenter( - localMedia: LocalMedia = aLocalMedia( - uri = mockMediaUrl, + attachments: List = listOf( + aMediaAttachment( + aLocalMedia( + uri = mockMediaUrl, + ) + ), ), - sendAsFile: Boolean = false, room: JoinedRoom = FakeJoinedRoom(), timelineMode: Timeline.Mode = Timeline.Mode.Live, permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder(), @@ -849,6 +951,7 @@ class AttachmentsPreviewPresenterTest { mediaOptimizationSelectorPresenterFactory: FakeMediaOptimizationSelectorPresenterFactory = FakeMediaOptimizationSelectorPresenterFactory( fakePresenter = { MediaOptimizationSelectorState( + index = 0, maxUploadSize = AsyncData.Uninitialized, videoSizeEstimations = AsyncData.Uninitialized, isImageOptimizationEnabled = null, @@ -861,17 +964,22 @@ class AttachmentsPreviewPresenterTest { ), mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), attachmentImageEditor: AttachmentImageEditor = FakeAttachmentImageEditor { - Result.success( - EditedLocalMedia( - localMedia = localMedia.copy(uri = Uri.parse("file:///tmp/default-edited.jpeg")), - file = File("/tmp/default-edited.jpeg"), + val localMediaResult = (attachments.first() as? Attachment.Media)?.localMedia?.copy(uri = Uri.parse("file:///tmp/default-edited.jpeg")) + if (localMediaResult != null) { + Result.success( + EditedLocalMedia( + localMedia = localMediaResult, + file = File("/tmp/default-edited.jpeg"), + ) ) - ) + } else { + Result.failure(IllegalStateException("Check test values")) + } }, videoCompressionPresetSelector: VideoCompressionPresetSelector = VideoCompressionPresetSelector(), ): AttachmentsPreviewPresenter { return AttachmentsPreviewPresenter( - attachment = aMediaAttachment(localMedia, sendAsFile = sendAsFile), + attachments = attachments.toImmutableList(), onDoneListener = onDoneListener, mediaSenderFactory = MediaSenderFactory { timelineMode -> DefaultMediaSender( diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/SendActionStateTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/SendActionStateTest.kt index 208d9cc7c0..b0bc755af8 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/SendActionStateTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/SendActionStateTest.kt @@ -11,28 +11,27 @@ package io.element.android.features.messages.impl.attachments import com.google.common.truth.Truth.assertThat import io.element.android.features.messages.impl.attachments.preview.SendActionState import io.element.android.features.messages.impl.attachments.preview.aMediaUploadInfo -import io.element.android.libraries.mediaupload.api.MediaUploadInfo import org.junit.Test class SendActionStateTest { @Test - fun `mediaUploadInfo() should return the value from Uploading class`() { - val mediaUploadInfo: MediaUploadInfo = aMediaUploadInfo() - val state: SendActionState = SendActionState.Sending.Uploading(mediaUploadInfo = aMediaUploadInfo()) - assertThat(state.mediaUploadInfo()).isEqualTo(mediaUploadInfo) + fun `mediaUploadInfoList() should return the value from Uploading class`() { + val data = listOf(aMediaUploadInfo()) + val state: SendActionState = SendActionState.Sending.Uploading(mediaInfos = data) + assertThat(state.mediaUploadInfoList()).isEqualTo(data) } @Test - fun `mediaUploadInfo() should return the value from ReadyToUpload class`() { - val mediaUploadInfo: MediaUploadInfo = aMediaUploadInfo() - val state: SendActionState = SendActionState.Sending.ReadyToUpload(mediaInfo = aMediaUploadInfo()) - assertThat(state.mediaUploadInfo()).isEqualTo(mediaUploadInfo) + fun `mediaUploadInfoList() should return the value from ReadyToUpload class`() { + val data = listOf(aMediaUploadInfo()) + val state: SendActionState = SendActionState.Sending.ReadyToUpload(mediaInfos = data) + assertThat(state.mediaUploadInfoList()).isEqualTo(data) } @Test - fun `mediaUploadInfo() should return the value from Failure class`() { - val mediaUploadInfo: MediaUploadInfo = aMediaUploadInfo() - val state: SendActionState = SendActionState.Failure(error = IllegalStateException("An error"), mediaUploadInfo = aMediaUploadInfo()) - assertThat(state.mediaUploadInfo()).isEqualTo(mediaUploadInfo) + fun `mediaUploadInfoList() should return the value from Failure class`() { + val data = listOf(aMediaUploadInfo()) + val state: SendActionState = SendActionState.Failure(error = IllegalStateException("An error"), mediaInfos = data) + assertThat(state.mediaUploadInfoList()).isEqualTo(data) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditsTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditsTest.kt index 43c893dd05..eb989967ef 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditsTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/preview/imageeditor/AttachmentImageEditsTest.kt @@ -42,4 +42,37 @@ class AttachmentImageEditsTest { assertThat(result.cropRect.bottom).isWithin(0.0001f).of(0.8f) assertThat(result.hasChanges).isTrue() } + + @Test + fun `flip horizontally updates crop and change tracking`() { + val sut = AttachmentImageEdits( + cropRect = NormalizedCropRect( + left = 0.1f, + top = 0.3f, + right = 0.6f, + bottom = 0.9f, + ) + ) + val result = sut.flipHorizontally() + assertThat(result.isFlippedHorizontally).isTrue() + assertThat(result.cropRect.left).isWithin(0.0001f).of(0.4f) + assertThat(result.cropRect.right).isWithin(0.0001f).of(0.9f) + assertThat(result.cropRect.top).isWithin(0.0001f).of(0.3f) + assertThat(result.cropRect.bottom).isWithin(0.0001f).of(0.9f) + assertThat(result.hasChanges).isTrue() + } + + @Test + fun `flip vertical twice resets to default state`() { + val edits = AttachmentImageEdits().flipVertically().flipVertically() + assertThat(edits.isFlippedVertically).isFalse() + assertThat(edits.hasChanges).isFalse() + } + + @Test + fun `flip horizontally twice resets to default state`() { + val edits = AttachmentImageEdits().flipHorizontally().flipHorizontally() + assertThat(edits.isFlippedVertically).isFalse() + assertThat(edits.hasChanges).isFalse() + } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt index e06f4ad4cd..83c5c5f575 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt @@ -10,7 +10,6 @@ package io.element.android.features.messages.impl.attachments.video import android.net.Uri import android.util.Size -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.features.messages.test.attachments.video.FakeVideoMetadataExtractor import io.element.android.features.messages.test.attachments.video.FakeVideoMetadataExtractorFactory @@ -26,16 +25,15 @@ import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.test.viewer.aLocalMedia import io.element.android.libraries.preferences.api.store.VideoCompressionPreset import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.test import io.mockk.mockk import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith import kotlin.time.Duration.Companion.minutes -@RunWith(AndroidJUnit4::class) -class DefaultMediaOptimizationSelectorPresenterTest { +class DefaultMediaOptimizationSelectorPresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() @@ -276,6 +274,7 @@ class DefaultMediaOptimizationSelectorPresenterTest { } private fun createDefaultMediaOptimizationSelectorPresenter( + index: Int = 0, localMedia: LocalMedia = aLocalMedia(mockMediaUrl, aVideoMediaInfo()), maxUploadSizeProvider: MaxUploadSizeProvider = MaxUploadSizeProvider { Result.success(1_000L) }, featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SelectableMediaQuality.key to true)), @@ -285,6 +284,7 @@ class DefaultMediaOptimizationSelectorPresenterTest { sendAsFile: Boolean = false, ): DefaultMediaOptimizationSelectorPresenter { return DefaultMediaOptimizationSelectorPresenter( + index = index, localMedia = localMedia, sendAsFile = sendAsFile, maxUploadSizeProvider = maxUploadSizeProvider, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateViewTest.kt index 0ee342513a..4d29f10a57 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStateViewTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.designsystem.components.avatar.anAvatarData import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityState @@ -24,11 +23,10 @@ import io.element.android.libraries.matrix.ui.room.RoomMemberIdentityStateChange import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class IdentityChangeStateViewTest { +class IdentityChangeStateViewTest : RobolectricTest() { @Test fun `show and resolve pin violation`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureViewTest.kt index 07a0fd5f94..6fe01bb281 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureViewTest.kt @@ -14,16 +14,14 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ResolveVerifiedUserSendFailureViewTest { +class ResolveVerifiedUserSendFailureViewTest : RobolectricTest() { @Test fun `clicking on resolve and resend emit the expected event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/link/LinkViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/link/LinkViewTest.kt index b656430466..69093e948c 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/link/LinkViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/link/LinkViewTest.kt @@ -14,19 +14,17 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnceWithParam +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.wysiwyg.link.Link import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class LinkViewTest { +class LinkViewTest : RobolectricTest() { @Test fun `clicking on cancel emits the expected event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt index 116a1cfb5d..61b1fc8d26 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt @@ -24,6 +24,8 @@ import io.element.android.features.messages.impl.utils.FakeMentionSpanFormatter import io.element.android.features.messages.impl.utils.FakeTextPillificationHelper import io.element.android.features.messages.impl.utils.TextPillificationHelper import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.matrix.api.permalink.PermalinkParser @@ -271,12 +273,13 @@ class MessageComposerPresenterSlashCommandTest { isRichTextEditorEnabled: Boolean = true, draftService: ComposerDraftService = FakeComposerDraftService(), mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), - isInThread: Boolean = false, + threadRoot: ThreadId? = null, slashCommandService: SlashCommandService = FakeSlashCommandService(), + featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(), ) = MessageComposerPresenter( navigator = navigator, sessionCoroutineScope = this, - isInThread = isInThread, + threadRoot = threadRoot, room = room, mediaPickerProvider = pickerProvider, sessionPreferencesStore = sessionPreferencesStore, @@ -311,6 +314,7 @@ class MessageComposerPresenterSlashCommandTest { mediaOptimizationConfigProvider = mediaOptimizationConfigProvider, notificationConversationService = notificationConversationService, slashCommandService = slashCommandService, + featureFlagService = featureFlagService, ).apply { isTesting = true showTextFormatting = isRichTextEditorEnabled diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt index e8d106a80f..7c6f47058e 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt @@ -34,6 +34,7 @@ import io.element.android.features.messages.impl.utils.TextPillificationHelper import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.ThreadId @@ -107,6 +108,7 @@ import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.test import io.element.android.tests.testutils.waitForPredicate import io.mockk.mockk @@ -118,14 +120,11 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import uniffi.wysiwyg_composer.MentionsState import java.io.File @Suppress("LargeClass") -@RunWith(RobolectricTestRunner::class) -class MessageComposerPresenterTest { +class MessageComposerPresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() @@ -1534,12 +1533,13 @@ class MessageComposerPresenterTest { isRichTextEditorEnabled: Boolean = true, draftService: ComposerDraftService = FakeComposerDraftService(), mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), - isInThread: Boolean = false, + threadRoot: ThreadId? = null, slashCommandService: SlashCommandService = FakeSlashCommandService(), + featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(), ) = MessageComposerPresenter( navigator = navigator, sessionCoroutineScope = this, - isInThread = isInThread, + threadRoot = threadRoot, room = room, mediaPickerProvider = pickerProvider, sessionPreferencesStore = sessionPreferencesStore, @@ -1574,6 +1574,7 @@ class MessageComposerPresenterTest { mediaOptimizationConfigProvider = mediaOptimizationConfigProvider, notificationConversationService = notificationConversationService, slashCommandService = slashCommandService, + featureFlagService = featureFlagService, ).apply { isTesting = true showTextFormatting = isRichTextEditorEnabled diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerViewTest.kt index 546731ff87..cbe76d73f7 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -25,11 +24,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class PinnedMessagesBannerViewTest { +class PinnedMessagesBannerViewTest : RobolectricTest() { @Test fun `clicking on the banner invoke expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListViewTest.kt index 9c10abb631..35e60684a9 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListViewTest.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.test.onFirst import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.messages.impl.actionlist.ActionListEvent import io.element.android.features.messages.impl.actionlist.anActionListState import io.element.android.features.messages.impl.timeline.aTimelineItemList @@ -28,17 +27,17 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalledWithParam +import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import io.element.android.wysiwyg.link.Link import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class PinnedMessagesListViewTest { +class PinnedMessagesListViewTest : RobolectricTest() { @Test fun `clicking on back calls the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) @@ -98,6 +97,7 @@ private fun AndroidComposeUiTest.setPinnedMessagesListView( state: PinnedMessagesListState, onBackClick: () -> Unit = EnsureNeverCalled(), onEventClick: (event: TimelineItem.Event) -> Unit = EnsureNeverCalledWithParam(), + onGalleryItemClick: (event: TimelineItem.Event, index: Int) -> Unit = EnsureNeverCalledWithTwoParams(), onUserDataClick: (MatrixUser) -> Unit = EnsureNeverCalledWithParam(), onLinkClick: (Link) -> Unit = EnsureNeverCalledWithParam(), onLinkLongClick: (Link) -> Unit = EnsureNeverCalledWithParam(), @@ -107,6 +107,7 @@ private fun AndroidComposeUiTest.setPinnedMessagesListView( state = state, onBackClick = onBackClick, onEventClick = onEventClick, + onGalleryItemClick = onGalleryItemClick, onUserDataClick = onUserDataClick, onLinkClick = onLinkClick, onLinkLongClick = onLinkLongClick, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProviderTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProviderTest.kt index 9e98f0fa49..3c339aa04e 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProviderTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/DefaultHtmlConverterProviderTest.kt @@ -21,12 +21,10 @@ import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider import io.element.android.libraries.textcomposer.mentions.MentionSpanTheme +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultHtmlConverterProviderTest { +class DefaultHtmlConverterProviderTest : RobolectricTest() { private val provider = DefaultHtmlConverterProvider( mentionSpanProvider = MentionSpanProvider( permalinkParser = FakePermalinkParser(), diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index af37fb61ef..f8f23b35f1 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -28,6 +28,7 @@ import io.element.android.features.poll.api.actions.SendPollResponseAction import io.element.android.features.poll.test.actions.FakeEndPollAction import io.element.android.features.poll.test.actions.FakeSendPollResponseAction import io.element.android.features.roomcall.api.aStandByCallState +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId @@ -43,6 +44,7 @@ import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender import io.element.android.libraries.matrix.api.timeline.item.event.Receipt +import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 @@ -54,17 +56,20 @@ import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom +import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.consumeItemsUntilPredicate +import io.element.android.tests.testutils.consumeItemsUntilTimeout import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaError @@ -366,6 +371,500 @@ class TimelinePresenterTest { } } + @Test + fun `present - jumpToUnread is InWindow at the read marker virtual item index`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter( + timeline = timeline, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + // SDK delivers items oldest-first; the factory reverses so output index 0 is the newest. + // After processing: [msg-newest, membership, msg-2, read-marker, msg-old] + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("msg-old"), anEventTimelineItem(content = aMessageContent())), + MatrixTimelineItem.Virtual(UniqueId("read-marker"), VirtualTimelineItem.ReadMarker), + MatrixTimelineItem.Event(UniqueId("msg-2"), anEventTimelineItem(content = aMessageContent())), + MatrixTimelineItem.Event(UniqueId("membership"), anEventTimelineItem(content = aRoomMembershipContent())), + MatrixTimelineItem.Event(UniqueId("msg-newest"), anEventTimelineItem(content = aMessageContent())), + ) + ) + consumeItemsUntilPredicate { it.jumpToUnread is JumpToUnreadState.InWindow }.last().also { state -> + assertThat(state.jumpToUnread).isEqualTo(JumpToUnreadState.InWindow(index = 3)) + assertThat(state.displayJumpToUnread).isTrue() + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is Hidden when no read marker and no fullyReadEventId`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter( + timeline = timeline, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(content = aMessageContent())), + MatrixTimelineItem.Event(UniqueId("2"), anEventTimelineItem(content = aMessageContent())), + ) + ) + consumeItemsUntilPredicate { + it.timelineItems.size == 2 && it.jumpToUnread == JumpToUnreadState.Hidden + }.last().also { state -> + assertThat(state.jumpToUnread).isEqualTo(JumpToUnreadState.Hidden) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is Hidden when JumpToUnread feature flag is disabled`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter( + timeline = timeline, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to false)), + ) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("msg-old"), anEventTimelineItem(content = aMessageContent())), + MatrixTimelineItem.Virtual(UniqueId("read-marker"), VirtualTimelineItem.ReadMarker), + MatrixTimelineItem.Event(UniqueId("msg-newest"), anEventTimelineItem(content = aMessageContent())), + ) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 3 }.last().also { state -> + assertThat(state.displayJumpToUnread).isFalse() + assertThat(state.jumpToUnread).isEqualTo(JumpToUnreadState.Hidden) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - newEventState becomes FromOther when an event from another user arrives`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter(timeline) + presenter.test { + val initialState = awaitFirstItem() + assertThat(initialState.newEventState).isEqualTo(NewEventState.None) + // Seed prevMostRecentItemId so subsequent emissions count as new events. + timelineItems.emit( + listOf(MatrixTimelineItem.Event(UniqueId("seed"), anEventTimelineItem(content = aMessageContent()))) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 1 } + timelineItems.getAndUpdate { items -> + items + listOf(MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(content = aMessageContent()))) + } + consumeItemsUntilPredicate { it.newEventState == NewEventState.FromOther }.last().also { state -> + assertThat(state.newEventState).isEqualTo(NewEventState.FromOther) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - newEventState resets to None on OnScrollFinished firstIndex 0`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline( + timelineItems = timelineItems, + markAsReadResult = { Result.success(Unit) }, + ) + val presenter = createTimelinePresenter(timeline) + presenter.test { + val initialState = awaitFirstItem() + timelineItems.emit( + listOf(MatrixTimelineItem.Event(UniqueId("seed"), anEventTimelineItem(content = aMessageContent()))) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 1 } + timelineItems.getAndUpdate { items -> + items + listOf(MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(content = aMessageContent()))) + } + consumeItemsUntilPredicate { it.newEventState == NewEventState.FromOther } + initialState.eventSink.invoke(TimelineEvent.OnScrollFinished(0)) + consumeItemsUntilPredicate { it.newEventState == NewEventState.None }.last().also { state -> + assertThat(state.newEventState).isEqualTo(NewEventState.None) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - newEventState transitions to FromMe when latest event is from me`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter(timeline) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf(MatrixTimelineItem.Event(UniqueId("seed"), anEventTimelineItem(content = aMessageContent()))) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 1 } + // First, an event from another user moves us to FromOther. + timelineItems.getAndUpdate { items -> + items + listOf(MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(content = aMessageContent()))) + } + consumeItemsUntilPredicate { it.newEventState == NewEventState.FromOther } + // Then the local user sends a message: state moves to FromMe. + timelineItems.getAndUpdate { items -> + items + listOf( + MatrixTimelineItem.Event(UniqueId("2"), anEventTimelineItem(content = aMessageContent(), isOwn = true)), + ) + } + consumeItemsUntilPredicate { it.newEventState == NewEventState.FromMe }.last().also { state -> + assertThat(state.newEventState).isEqualTo(NewEventState.FromMe) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - newEventState does not reset on OnScrollFinished firstIndex other than 0`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter(timeline) + presenter.test { + val initialState = awaitFirstItem() + timelineItems.emit( + listOf(MatrixTimelineItem.Event(UniqueId("seed"), anEventTimelineItem(content = aMessageContent()))) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 1 } + timelineItems.getAndUpdate { items -> + items + listOf(MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(content = aMessageContent()))) + } + consumeItemsUntilPredicate { it.newEventState == NewEventState.FromOther } + // Scrolling stops above the bottom: state must NOT reset. + initialState.eventSink.invoke(TimelineEvent.OnScrollFinished(5)) + advanceUntilIdle() + val drained = consumeItemsUntilTimeout() + assertThat(drained.any { it.newEventState == NewEventState.None }).isFalse() + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - newEventState stays None for events with PAGINATION origin`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter(timeline) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf(MatrixTimelineItem.Event(UniqueId("seed"), anEventTimelineItem(content = aMessageContent()))) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 1 } + // A back-paginated event arrives. It should not flip newEventState. + timelineItems.getAndUpdate { items -> + items + listOf( + MatrixTimelineItem.Event( + UniqueId("paginated"), + anEventTimelineItem(content = aMessageContent()).copy(origin = TimelineItemEventOrigin.PAGINATION), + ) + ) + } + consumeItemsUntilPredicate { it.timelineItems.size == 2 }.last().also { state -> + assertThat(state.newEventState).isEqualTo(NewEventState.None) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is InWindow at index 0 when the read marker is the only item`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val presenter = createTimelinePresenter( + timeline = timeline, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf(MatrixTimelineItem.Virtual(UniqueId("read-marker"), VirtualTimelineItem.ReadMarker)) + ) + consumeItemsUntilPredicate { it.jumpToUnread is JumpToUnreadState.InWindow }.last().also { state -> + assertThat(state.jumpToUnread).isEqualTo(JumpToUnreadState.InWindow(index = 0)) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is OutOfWindow when fullyReadEventId is set but not in the loaded window`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val fullyReadEventId = EventId("\$older-than-loaded-window") + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + // There is genuinely unread *displayable* content, and the marker event isn't loaded + // (isEventLoaded defaults to false), so the FAB targets the out-of-window marker. + initialRoomInfo = aRoomInfo(fullyReadEventId = fullyReadEventId, numUnreadMessages = 1), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + // Loaded items don't include the fullyReadEventId and the SDK didn't materialise a ReadMarker. + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(eventId = AN_EVENT_ID, content = aMessageContent())), + MatrixTimelineItem.Event(UniqueId("2"), anEventTimelineItem(eventId = AN_EVENT_ID_2, content = aMessageContent())), + ) + ) + consumeItemsUntilPredicate { it.jumpToUnread is JumpToUnreadState.OutOfWindow }.last().also { state -> + assertThat(state.jumpToUnread).isEqualTo(JumpToUnreadState.OutOfWindow(eventId = fullyReadEventId)) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is Hidden when the marker event is loaded in the window but not displayed`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + // The marker event is in the loaded window (e.g. a state/filtered event) but never rendered. + val fullyReadEventId = EventId("\$loaded-but-not-displayed") + val timeline = FakeTimeline(timelineItems = timelineItems).apply { + isEventLoadedLambda = { it == fullyReadEventId } + } + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + initialRoomInfo = aRoomInfo(fullyReadEventId = fullyReadEventId, numUnreadMessages = 1), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + // Displayed items don't contain the marker event, but the SDK reports it as loaded. + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(eventId = AN_EVENT_ID, content = aMessageContent())), + MatrixTimelineItem.Event(UniqueId("2"), anEventTimelineItem(eventId = AN_EVENT_ID_2, content = aMessageContent())), + ) + ) + advanceUntilIdle() + // It must never be OutOfWindow — there is nothing displayable to jump to. + val drained = consumeItemsUntilTimeout() + assertThat(drained.any { it.jumpToUnread is JumpToUnreadState.OutOfWindow }).isFalse() + assertThat(drained.last().jumpToUnread).isEqualTo(JumpToUnreadState.Hidden) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is Hidden when out of window but there are no unread messages`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val fullyReadEventId = EventId("\$older-than-loaded-window") + // isEventLoaded defaults to false (genuinely out of window), but numUnreadMessages is 0. + val timeline = FakeTimeline(timelineItems = timelineItems) + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + initialRoomInfo = aRoomInfo(fullyReadEventId = fullyReadEventId, numUnreadMessages = 0), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(eventId = AN_EVENT_ID, content = aMessageContent())), + MatrixTimelineItem.Event(UniqueId("2"), anEventTimelineItem(eventId = AN_EVENT_ID_2, content = aMessageContent())), + ) + ) + advanceUntilIdle() + val drained = consumeItemsUntilTimeout() + assertThat(drained.any { it.jumpToUnread != JumpToUnreadState.Hidden }).isFalse() + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is Hidden when fullyReadEventId IS in the loaded window`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + // The user is caught up: the marker event is loaded, but the SDK didn't insert a + // virtual ReadMarker because there are no items newer than it. + initialRoomInfo = aRoomInfo(fullyReadEventId = AN_EVENT_ID), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + // A loaded item has eventId == AN_EVENT_ID (default of anEventTimelineItem). + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(content = aMessageContent())), + ) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 1 }.last().also { state -> + assertThat(state.jumpToUnread).isEqualTo(JumpToUnreadState.Hidden) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is Hidden when fullyReadEventId is set but the timeline is empty`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + initialRoomInfo = aRoomInfo(fullyReadEventId = AN_EVENT_ID), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + val initialState = awaitFirstItem() + // Without any timeline items, the FAB must stay hidden — the user is mid-load. + assertThat(initialState.jumpToUnread).isEqualTo(JumpToUnreadState.Hidden) + advanceUntilIdle() + val drained = consumeItemsUntilTimeout() + assertThat(drained.any { it.jumpToUnread != JumpToUnreadState.Hidden }).isFalse() + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread is Hidden when fullyReadEventId is set but the feature flag is off`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + initialRoomInfo = aRoomInfo(fullyReadEventId = AN_EVENT_ID), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to false)), + ) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(content = aMessageContent())), + ) + ) + consumeItemsUntilPredicate { it.timelineItems.size == 1 }.last().also { state -> + assertThat(state.jumpToUnread).isEqualTo(JumpToUnreadState.Hidden) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread prefers InWindow when both a virtual marker and fullyReadEventId are present`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline(timelineItems = timelineItems) + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + initialRoomInfo = aRoomInfo(fullyReadEventId = AN_EVENT_ID), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("msg-old"), anEventTimelineItem(content = aMessageContent())), + MatrixTimelineItem.Virtual(UniqueId("read-marker"), VirtualTimelineItem.ReadMarker), + MatrixTimelineItem.Event(UniqueId("msg-newest"), anEventTimelineItem(content = aMessageContent())), + ) + ) + consumeItemsUntilPredicate { it.jumpToUnread is JumpToUnreadState.InWindow }.last().also { state -> + assertThat(state.jumpToUnread).isInstanceOf(JumpToUnreadState.InWindow::class.java) + } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - jumpToUnread hides eagerly after MarkAllAsRead even before a new RoomInfo arrives`() = runTest { + val timelineItems = MutableStateFlow(emptyList()) + val timeline = FakeTimeline( + timelineItems = timelineItems, + getLatestEventIdResult = { Result.success(AN_EVENT_ID_2) }, + ) + val fullyReadEventId = EventId("\$older-than-loaded-window") + val room = FakeJoinedRoom( + liveTimeline = timeline, + baseRoom = FakeBaseRoom( + roomPermissions = roomPermissions(), + initialRoomInfo = aRoomInfo(fullyReadEventId = fullyReadEventId, numUnreadMessages = 1), + ), + ) + val presenter = createTimelinePresenter( + timeline = timeline, + room = room, + featureFlagService = FakeFeatureFlagService(initialState = mapOf(FeatureFlags.JumpToUnread.key to true)), + ) + presenter.test { + awaitFirstItem() + timelineItems.emit( + listOf( + MatrixTimelineItem.Event(UniqueId("1"), anEventTimelineItem(eventId = AN_EVENT_ID, content = aMessageContent())), + ) + ) + val outOfWindow = consumeItemsUntilPredicate { it.jumpToUnread is JumpToUnreadState.OutOfWindow }.last() + assertThat(outOfWindow.jumpToUnread).isEqualTo(JumpToUnreadState.OutOfWindow(eventId = fullyReadEventId)) + + outOfWindow.eventSink(TimelineEvent.MarkAllAsRead) + // RoomInfo is intentionally NOT updated — eager hide must fire on the await alone. + val afterMark = consumeItemsUntilPredicate { it.jumpToUnread == JumpToUnreadState.Hidden }.last() + assertThat(afterMark.jumpToUnread).isEqualTo(JumpToUnreadState.Hidden) + cancelAndIgnoreRemainingEvents() + } + } + @Test fun `present - reaction ordering`() = runTest { val timelineItems = MutableStateFlow(emptyList()) @@ -975,6 +1474,54 @@ class TimelinePresenterTest { } } + @Test + fun `present - MarkAllAsRead invokes markAsFullyRead with latest event id`() = runTest { + val markAsFullyReadRecorder = lambdaRecorder { _, _ -> } + val presenter = createTimelinePresenter( + timeline = FakeTimeline(getLatestEventIdResult = { Result.success(AN_EVENT_ID) }), + markAsFullyRead = FakeMarkAsFullyRead(markAsFullyReadRecorder), + ) + presenter.test { + val initialState = awaitFirstItem() + initialState.eventSink(TimelineEvent.MarkAllAsRead) + advanceUntilIdle() + markAsFullyReadRecorder.assertions().isCalledOnce().with(value(A_ROOM_ID), value(AN_EVENT_ID)) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - MarkAllAsRead does not invoke markAsFullyRead when latest event id lookup fails`() = runTest { + val markAsFullyReadRecorder = lambdaRecorder { _, _ -> } + val presenter = createTimelinePresenter( + timeline = FakeTimeline(getLatestEventIdResult = { Result.failure(RuntimeException("boom")) }), + markAsFullyRead = FakeMarkAsFullyRead(markAsFullyReadRecorder), + ) + presenter.test { + val initialState = awaitFirstItem() + initialState.eventSink(TimelineEvent.MarkAllAsRead) + advanceUntilIdle() + markAsFullyReadRecorder.assertions().isNeverCalled() + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - MarkAllAsRead does not invoke markAsFullyRead when there is no latest event`() = runTest { + val markAsFullyReadRecorder = lambdaRecorder { _, _ -> } + val presenter = createTimelinePresenter( + timeline = FakeTimeline(getLatestEventIdResult = { Result.success(null) }), + markAsFullyRead = FakeMarkAsFullyRead(markAsFullyReadRecorder), + ) + presenter.test { + val initialState = awaitFirstItem() + initialState.eventSink(TimelineEvent.MarkAllAsRead) + advanceUntilIdle() + markAsFullyReadRecorder.assertions().isNeverCalled() + cancelAndIgnoreRemainingEvents() + } + } + private suspend fun ReceiveTurbine.awaitFirstItem(): T { return awaitItem() } @@ -1014,6 +1561,7 @@ class TimelinePresenterTest { timelineItemIndexer: TimelineItemIndexer = TimelineItemIndexer(), featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(), liveLocationShareManager: FakeActiveLiveLocationShareManager = FakeActiveLiveLocationShareManager(), + markAsFullyRead: MarkAsFullyRead = FakeMarkAsFullyRead { _, _ -> }, ): TimelinePresenter { return TimelinePresenter( timelineItemsFactoryCreator = aTimelineItemsFactoryCreator(), @@ -1033,6 +1581,7 @@ class TimelinePresenterTest { featureFlagService = featureFlagService, analyticsService = FakeAnalyticsService(), liveLocationShareManager = liveLocationShareManager, + markAsFullyRead = markAsFullyRead, ) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt index 2138d4ced2..dc63817e99 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollToIndex import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.messages.impl.timeline.components.MessageShieldData import io.element.android.features.messages.impl.timeline.components.aCriticalShield import io.element.android.features.messages.impl.timeline.model.TimelineItem @@ -37,16 +36,15 @@ import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import io.element.android.wysiwyg.link.Link import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import org.junit.Ignore import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class TimelineViewTest { +class TimelineViewTest : RobolectricTest() { @Test fun `reaching the end of the timeline with more events to load emits a LoadMore event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() @@ -218,6 +216,7 @@ private fun AndroidComposeUiTest.setTimelineView( onReactionLongClick: (emoji: String, TimelineItem.Event) -> Unit = EnsureNeverCalledWithTwoParams(), onMoreReactionsClick: (TimelineItem.Event) -> Unit = EnsureNeverCalledWithParam(), onReadReceiptClick: (TimelineItem.Event) -> Unit = EnsureNeverCalledWithParam(), + onGalleryItemClick: (TimelineItem.Event, Int) -> Unit = EnsureNeverCalledWithTwoParams(), forceJumpToBottomVisibility: Boolean = false, ) { setSafeContent(clearAndroidUiDispatcher = true) { @@ -233,6 +232,7 @@ private fun AndroidComposeUiTest.setTimelineView( onReactionLongClick = onReactionLongClick, onMoreReactionsClick = onMoreReactionsClick, onReadReceiptClick = onReadReceiptClick, + onGalleryItemClick = onGalleryItemClick, forceJumpToBottomVisibility = forceJumpToBottomVisibility, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerPresenterTest.kt index 541b16b546..9ebbfd5a3a 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/picker/EmojiPickerPresenterTest.kt @@ -13,7 +13,6 @@ import androidx.compose.runtime.InternalComposeApi import androidx.compose.runtime.currentComposer import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow @@ -25,6 +24,7 @@ import io.element.android.emojibasebindings.EmojibaseCategory import io.element.android.emojibasebindings.EmojibaseStore import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -33,10 +33,8 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class EmojiPickerPresenterTest { +class EmojiPickerPresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollViewTest.kt index 40671e4bf8..1d3bb26a93 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollViewTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.hasText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.messages.impl.timeline.TimelineEvent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent import io.element.android.libraries.testtags.TestTags @@ -23,11 +22,10 @@ import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressTag +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class TimelineItemPollViewTest { +class TimelineItemPollViewTest : RobolectricTest() { @Test fun `answering a poll with first answer should emit a PollAnswerSelected event`() { testAnswer(answerIndex = 0) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineTextViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineTextViewTest.kt index 7b8597f05a..d0203d0329 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineTextViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineTextViewTest.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest import androidx.core.text.buildSpannedString import androidx.core.text.inSpans -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent @@ -39,13 +38,12 @@ import io.element.android.libraries.textcomposer.mentions.MentionType import io.element.android.libraries.textcomposer.mentions.getMentionSpans import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.wysiwyg.view.spans.CustomMentionSpan import kotlinx.coroutines.CompletableDeferred import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class TimelineTextViewTest { +class TimelineTextViewTest : RobolectricTest() { private val mentionSpanTheme = MentionSpanTheme(currentUserId = A_USER_ID) private val formatLambda = lambdaRecorder { mentionType -> mentionType.toString() } private val mentionSpanFormatter = FakeMentionSpanFormatter(formatLambda) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt index fa837f1492..fc01184764 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -19,9 +19,13 @@ import androidx.core.text.inSpans import androidx.core.text.toSpannable import com.google.common.truth.Truth.assertThat import io.element.android.features.location.api.Location +import io.element.android.features.messages.impl.timeline.model.event.AttachmentItem +import io.element.android.features.messages.impl.timeline.model.event.GalleryItem +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAttachmentsContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEmoteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemGalleryContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent @@ -47,6 +51,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageT import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType @@ -67,18 +73,18 @@ import io.element.android.libraries.matrix.test.timeline.aProfileDetails import io.element.android.libraries.matrix.test.timeline.aStickerContent import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.test.runTest import org.jsoup.nodes.Document import org.junit.Assert.fail import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes -@Suppress("LargeClass") @RunWith(RobolectricTestRunner::class) class TimelineItemContentMessageFactoryTest { +@Suppress("LargeClass") +class TimelineItemContentMessageFactoryTest : RobolectricTest() { @Test fun `test create OtherMessageType`() = runTest { val sut = createTimelineItemContentMessageFactory() @@ -343,10 +349,10 @@ import kotlin.time.Duration.Companion.minutes formattedCaption = null, source = MediaSource("url"), info = AudioInfo( - duration = 1.minutes, - size = 123L, - mimetype = MimeTypes.Mp3, - ) + duration = 1.minutes, + size = 123L, + mimetype = MimeTypes.Mp3, + ) ), isEdited = true, ), @@ -584,16 +590,16 @@ import kotlin.time.Duration.Companion.minutes formattedCaption = null, source = MediaSource("url"), info = FileInfo( - mimetype = MimeTypes.Pdf, - size = 123L, - thumbnailInfo = ThumbnailInfo( - height = 10L, - width = 5L, - mimetype = MimeTypes.Jpeg, - size = 111L, - ), - thumbnailSource = MediaSource("url_thumbnail"), - ) + mimetype = MimeTypes.Pdf, + size = 123L, + thumbnailInfo = ThumbnailInfo( + height = 10L, + width = 5L, + mimetype = MimeTypes.Jpeg, + size = 111L, + ), + thumbnailSource = MediaSource("url_thumbnail"), + ) ), isEdited = true, ), @@ -767,6 +773,428 @@ import kotlin.time.Duration.Companion.minutes (result as TimelineItemTextContent).formattedBody.assertSpannedEquals(expectedSpanned) } + @Test + fun `test create GalleryMessageType with image items returns TimelineItemGalleryContent`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource("image_url"), + info = ImageInfo( + height = 100L, + width = 200L, + mimetype = MimeTypes.Jpeg, + size = 888L, + thumbnailInfo = ThumbnailInfo(height = 10L, width = 20L, mimetype = MimeTypes.Jpeg, size = 111L), + thumbnailSource = MediaSource("thumbnail_url"), + blurhash = A_BLUR_HASH, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemGalleryContent( + body = "Gallery body", + caption = "Gallery body", + formattedCaption = null, + isEdited = false, + items = persistentListOf( + GalleryItem( + filename = "image.jpg", + mimeType = MimeTypes.Jpeg, + mediaSource = MediaSource("image_url"), + type = GalleryItem.Type.Image, + thumbnailSource = MediaSource("thumbnail_url"), + width = 200, + height = 100, + thumbnailWidth = 20, + thumbnailHeight = 10, + blurhash = A_BLUR_HASH, + ) + ) + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create GalleryMessageType with video items returns TimelineItemGalleryContent`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Video( + content = VideoMessageType( + filename = "video.mp4", + caption = null, + formattedCaption = null, + source = MediaSource("video_url"), + info = VideoInfo( + duration = 1.minutes, + height = 100L, + width = 200L, + mimetype = MimeTypes.Mp4, + size = 1234L, + thumbnailInfo = ThumbnailInfo(height = 10L, width = 20L, mimetype = MimeTypes.Jpeg, size = 111L), + thumbnailSource = MediaSource("thumbnail_url"), + blurhash = A_BLUR_HASH, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemGalleryContent( + body = "Gallery body", + caption = "Gallery body", + formattedCaption = null, + isEdited = false, + items = persistentListOf( + GalleryItem( + filename = "video.mp4", + mimeType = MimeTypes.Mp4, + mediaSource = MediaSource("video_url"), + type = GalleryItem.Type.Video, + thumbnailSource = MediaSource("thumbnail_url"), + width = 200, + height = 100, + thumbnailWidth = 20, + thumbnailHeight = 10, + blurhash = A_BLUR_HASH, + duration = 1.minutes, + ) + ) + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create GalleryMessageType with audio items returns TimelineItemAttachmentsContent`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Audio( + content = AudioMessageType( + filename = "audio.mp3", + caption = null, + formattedCaption = null, + source = MediaSource("audio_url"), + info = AudioInfo( + duration = 1.minutes, + size = 123L, + mimetype = MimeTypes.Mp3, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemAttachmentsContent( + body = "Gallery body", + caption = "Gallery body", + formattedCaption = null, + isEdited = false, + attachments = persistentListOf( + AttachmentItem( + filename = "audio.mp3", + mimeType = MimeTypes.Mp3, + mediaSource = MediaSource("audio_url"), + thumbnailSource = null, + fileSize = 123L, + formattedFileSize = "123 Bytes", + fileExtension = "mp3", + ) + ) + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create GalleryMessageType with file items returns TimelineItemAttachmentsContent`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.File( + content = FileMessageType( + filename = "document.pdf", + caption = null, + formattedCaption = null, + source = MediaSource("file_url"), + info = FileInfo( + mimetype = MimeTypes.Pdf, + size = 456L, + thumbnailInfo = null, + thumbnailSource = null, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemAttachmentsContent( + body = "Gallery body", + caption = "Gallery body", + formattedCaption = null, + isEdited = false, + attachments = persistentListOf( + AttachmentItem( + filename = "document.pdf", + mimeType = MimeTypes.Pdf, + mediaSource = MediaSource("file_url"), + thumbnailSource = null, + fileSize = 456L, + formattedFileSize = "456 Bytes", + fileExtension = "pdf", + ) + ) + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create GalleryMessageType with image items without thumbnails returns TimelineItemAttachmentsContent`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource("image_url"), + info = ImageInfo( + height = 100L, + width = 200L, + mimetype = MimeTypes.Jpeg, + size = 888L, + thumbnailInfo = null, + thumbnailSource = null, + blurhash = null, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemAttachmentsContent( + body = "Gallery body", + caption = "Gallery body", + formattedCaption = null, + isEdited = false, + attachments = persistentListOf( + AttachmentItem( + filename = "image.jpg", + mimeType = MimeTypes.Jpeg, + mediaSource = MediaSource("image_url"), + thumbnailSource = null, + fileSize = 888L, + formattedFileSize = "888 Bytes", + fileExtension = "jpg", + ) + ) + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create GalleryMessageType with only Other items returns TimelineItemAttachmentsContent with empty attachments`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Other(itemType = "unknown_type", body = "Some body") + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemAttachmentsContent( + body = "Gallery body", + caption = "Gallery body", + formattedCaption = null, + isEdited = false, + attachments = persistentListOf(), + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create GalleryMessageType with mixed image and file items returns TimelineItemAttachmentsContent`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource("image_url"), + info = ImageInfo( + height = 100L, + width = 200L, + mimetype = MimeTypes.Jpeg, + size = 888L, + thumbnailInfo = ThumbnailInfo(height = 10L, width = 20L, mimetype = MimeTypes.Jpeg, size = 111L), + thumbnailSource = MediaSource("thumbnail_url"), + blurhash = null, + ) + ) + ), + GalleryItemType.File( + content = FileMessageType( + filename = "document.pdf", + caption = null, + formattedCaption = null, + source = MediaSource("file_url"), + info = FileInfo( + mimetype = MimeTypes.Pdf, + size = 456L, + thumbnailInfo = null, + thumbnailSource = null, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + assertThat(result).isInstanceOf(TimelineItemAttachmentsContent::class.java) + val attachmentsContent = result as TimelineItemAttachmentsContent + assertThat(attachmentsContent.attachments).hasSize(2) + } + + @Test + fun `test create GalleryMessageType with formatted caption returns TimelineItemGalleryContent with formatted caption`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "Gallery body", + formatted = FormattedBody(MessageFormat.HTML, "formatted"), + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource("image_url"), + info = ImageInfo( + height = 100L, + width = 200L, + mimetype = MimeTypes.Jpeg, + size = 888L, + thumbnailInfo = ThumbnailInfo(height = 10L, width = 20L, mimetype = MimeTypes.Jpeg, size = 111L), + thumbnailSource = MediaSource("thumbnail_url"), + blurhash = null, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + assertThat(result).isInstanceOf(TimelineItemGalleryContent::class.java) + val galleryContent = result as TimelineItemGalleryContent + galleryContent.formattedCaption.assertSpannedEquals(SpannedString("formatted")) + } + + @Test + fun `test create GalleryMessageType with empty body has no caption`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = GalleryMessageType( + body = "", + formatted = null, + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource("image_url"), + info = ImageInfo( + height = 100L, + width = 200L, + mimetype = MimeTypes.Jpeg, + size = 888L, + thumbnailInfo = ThumbnailInfo(height = 10L, width = 20L, mimetype = MimeTypes.Jpeg, size = 111L), + thumbnailSource = MediaSource("thumbnail_url"), + blurhash = null, + ) + ) + ) + ) + ) + ), + senderId = A_USER_ID, + senderProfile = aProfileDetails(), + eventId = AN_EVENT_ID, + ) + assertThat(result).isInstanceOf(TimelineItemGalleryContent::class.java) + val galleryContent = result as TimelineItemGalleryContent + assertThat(galleryContent.caption).isNull() + assertThat(galleryContent.formattedCaption).isNull() + } + private fun createMessageContent( body: String = "Body", inReplyTo: InReplyTo? = null, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/ProtectedViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/ProtectedViewTest.kt index 8050278fb2..aef12deeca 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/ProtectedViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/ProtectedViewTest.kt @@ -16,17 +16,15 @@ import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.lambda.lambdaError +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ProtectedViewTest { +class ProtectedViewTest : RobolectricTest() { @Test fun `when hideContent is false, the content is rendered`() = runAndroidComposeUiTest { setProtectedView( diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultMessageSummaryFormatterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultMessageSummaryFormatterTest.kt index 664d21ed64..06e436d64c 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultMessageSummaryFormatterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultMessageSummaryFormatterTest.kt @@ -18,14 +18,12 @@ import io.element.android.features.messages.impl.utils.messagesummary.DefaultMes import io.element.android.libraries.matrix.api.notification.CallIntent import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.timeline.aProfileDetails +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -@RunWith(RobolectricTestRunner::class) -class DefaultMessageSummaryFormatterTest { +class DefaultMessageSummaryFormatterTest : RobolectricTest() { private val formatter = DefaultMessageSummaryFormatter( RuntimeEnvironment.getApplication() as Context ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultTextPillificationHelperTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultTextPillificationHelperTest.kt index 16c8c922ca..6390c2ba48 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultTextPillificationHelperTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/DefaultTextPillificationHelperTest.kt @@ -9,7 +9,6 @@ package io.element.android.features.messages.impl.utils import android.net.Uri -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomAlias @@ -27,11 +26,10 @@ import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider import io.element.android.libraries.textcomposer.mentions.MentionSpanTheme import io.element.android.libraries.textcomposer.mentions.MentionType import io.element.android.libraries.textcomposer.mentions.getMentionSpans +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultTextPillificationHelperTest { +class DefaultTextPillificationHelperTest : RobolectricTest() { @Test fun `pillify - adds pills for user ids`() { val text = "A @user:server.com" diff --git a/features/messages/test/src/main/kotlin/io/element/android/features/messages/test/attachments/video/FakeMediaOptimizationSelectorPresenterFactory.kt b/features/messages/test/src/main/kotlin/io/element/android/features/messages/test/attachments/video/FakeMediaOptimizationSelectorPresenterFactory.kt index fff3ede5d3..af068a14c2 100644 --- a/features/messages/test/src/main/kotlin/io/element/android/features/messages/test/attachments/video/FakeMediaOptimizationSelectorPresenterFactory.kt +++ b/features/messages/test/src/main/kotlin/io/element/android/features/messages/test/attachments/video/FakeMediaOptimizationSelectorPresenterFactory.kt @@ -16,6 +16,7 @@ import io.element.android.libraries.mediaviewer.api.local.LocalMedia class FakeMediaOptimizationSelectorPresenterFactory( private val fakePresenter: MediaOptimizationSelectorPresenter = MediaOptimizationSelectorPresenter { MediaOptimizationSelectorState( + index = 0, maxUploadSize = AsyncData.Uninitialized, videoSizeEstimations = AsyncData.Uninitialized, isImageOptimizationEnabled = null, @@ -26,7 +27,7 @@ class FakeMediaOptimizationSelectorPresenterFactory( ) } ) : MediaOptimizationSelectorPresenter.Factory { - override fun create(localMedia: LocalMedia, sendAsFile: Boolean): MediaOptimizationSelectorPresenter { + override fun create(index: Int, localMedia: LocalMedia, sendAsFile: Boolean): MediaOptimizationSelectorPresenter { return fakePresenter } } diff --git a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt index 7b954abf86..591c31c7da 100644 --- a/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt +++ b/features/migration/impl/src/test/kotlin/io/element/android/features/migration/impl/migrations/AppMigration04Test.kt @@ -10,13 +10,11 @@ package io.element.android.features.migration.impl.migrations import androidx.test.platform.app.InstrumentationRegistry import com.google.common.truth.Truth.assertThat +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class AppMigration04Test { +class AppMigration04Test : RobolectricTest() { @Test fun `test migration`() = runTest { val context = InstrumentationRegistry.getInstrumentation().context diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryViewTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryViewTest.kt index a6b97c554c..ee6ad69ba6 100644 --- a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryViewTest.kt +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.poll.api.pollcontent.aPollContentState import io.element.android.features.poll.impl.R import io.element.android.features.poll.impl.history.model.PollHistoryFilter @@ -29,12 +28,11 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class PollHistoryViewTest { +class PollHistoryViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt index 12de2be746..2d6c2b0904 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvents.kt @@ -15,4 +15,6 @@ sealed interface DeveloperSettingsEvents { data class ChangeBrandColor(val color: Color?) : DeveloperSettingsEvents data object ClearCache : DeveloperSettingsEvents data object VacuumStores : DeveloperSettingsEvents + data class MarkAllRoomsAsRead(val needsConfirmation: Boolean) : DeveloperSettingsEvents + data object DismissMarkAllRoomsAsReadConfirmation : DeveloperSettingsEvents } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt index 1598c2ef27..02d2573ed6 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt @@ -22,6 +22,7 @@ import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.preferences.impl.developer.appsettings.AppDeveloperSettingsState import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase +import io.element.android.features.preferences.impl.tasks.MarkAllRoomsAsRead import io.element.android.features.preferences.impl.tasks.VacuumStoresUseCase import io.element.android.libraries.androidutils.filesize.FileSizeFormatter import io.element.android.libraries.architecture.AsyncAction @@ -46,6 +47,7 @@ class DeveloperSettingsPresenter( private val vacuumStoresUseCase: VacuumStoresUseCase, private val databaseSizesUseCase: GetDatabaseSizesUseCase, private val fileSizeFormatter: FileSizeFormatter, + private val markAllRoomsAsRead: MarkAllRoomsAsRead, ) : Presenter { @Composable override fun present(): DeveloperSettingsState { @@ -58,6 +60,9 @@ class DeveloperSettingsPresenter( val clearCacheAction = remember { mutableStateOf>(AsyncAction.Uninitialized) } + val markAllRoomsAsReadAction = remember { + mutableStateOf>(AsyncAction.Uninitialized) + } var showColorPicker by remember { mutableStateOf(false) } @@ -88,6 +93,18 @@ class DeveloperSettingsPresenter( DeveloperSettingsEvents.VacuumStores -> coroutineScope.launch { vacuumStoresUseCase() } + is DeveloperSettingsEvents.MarkAllRoomsAsRead -> { + if (event.needsConfirmation) { + markAllRoomsAsReadAction.value = AsyncAction.ConfirmingNoParams + } else { + coroutineScope.markAllRoomsAsRead( + markAllRoomsAsReadAction = markAllRoomsAsReadAction, + ) + } + } + DeveloperSettingsEvents.DismissMarkAllRoomsAsReadConfirmation -> { + markAllRoomsAsReadAction.value = AsyncAction.Uninitialized + } } } @@ -97,6 +114,7 @@ class DeveloperSettingsPresenter( cacheSize = cacheSize.value, databaseSizes = databaseSizes.value, clearCacheAction = clearCacheAction.value, + markAllRoomsAsReadAction = markAllRoomsAsReadAction.value, isEnterpriseBuild = enterpriseService.isEnterpriseBuild, showColorPicker = showColorPicker, eventSink = ::handleEvent, @@ -131,8 +149,14 @@ class DeveloperSettingsPresenter( } private fun CoroutineScope.clearCache(clearCacheAction: MutableState>) = launch { + suspend { clearCacheUseCase() }.runCatchingUpdatingState(state = clearCacheAction) + } + + private fun CoroutineScope.markAllRoomsAsRead( + markAllRoomsAsReadAction: MutableState>, + ) = launch { suspend { - clearCacheUseCase() - }.runCatchingUpdatingState(clearCacheAction) + markAllRoomsAsRead().getOrThrow() + }.runCatchingUpdatingState(state = markAllRoomsAsReadAction) } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt index fa5859a028..fe48e8c446 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt @@ -18,9 +18,10 @@ data class DeveloperSettingsState( val cacheSize: AsyncData, val databaseSizes: AsyncData>, val clearCacheAction: AsyncAction, + val markAllRoomsAsReadAction: AsyncAction, val isEnterpriseBuild: Boolean, val showColorPicker: Boolean, val eventSink: (DeveloperSettingsEvents) -> Unit ) { - val showLoader = clearCacheAction is AsyncAction.Loading + val showLoader = clearCacheAction is AsyncAction.Loading || markAllRoomsAsReadAction is AsyncAction.Loading } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt index 28aefd3ad1..fd285b1bb9 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStateProvider.kt @@ -37,6 +37,7 @@ open class DeveloperSettingsStateProvider : PreviewParameterProvider = AsyncAction.Uninitialized, + markAllRoomsAsReadAction: AsyncAction = AsyncAction.Uninitialized, isEnterpriseBuild: Boolean = false, showColorPicker: Boolean = false, eventSink: (DeveloperSettingsEvents) -> Unit = {}, @@ -45,6 +46,7 @@ fun aDeveloperSettingsState( cacheSize = AsyncData.Success("1.2 MB"), databaseSizes = AsyncData.Success(persistentMapOf("state_store" to "1.2MB")), clearCacheAction = clearCacheAction, + markAllRoomsAsReadAction = markAllRoomsAsReadAction, isEnterpriseBuild = isEnterpriseBuild, showColorPicker = showColorPicker, eventSink = eventSink, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt index 3adf9a13de..45009d1f71 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt @@ -18,9 +18,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme import io.element.android.features.preferences.impl.R import io.element.android.features.preferences.impl.developer.appsettings.AppDeveloperSettingsView import io.element.android.libraries.designsystem.components.ProgressDialog +import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory import io.element.android.libraries.designsystem.components.preferences.PreferencePage @@ -45,6 +47,15 @@ fun DeveloperSettingsView( if (state.showLoader) { ProgressDialog() } + if (state.markAllRoomsAsReadAction.isConfirming()) { + ConfirmationDialog( + title = "Are you sure you want to mark all the rooms as read?", + content = "", + submitText = stringResource(CommonStrings.action_yes), + onSubmitClick = { state.eventSink(DeveloperSettingsEvents.MarkAllRoomsAsRead(needsConfirmation = false)) }, + onDismiss = { state.eventSink(DeveloperSettingsEvents.DismissMarkAllRoomsAsReadConfirmation) }, + ) + } BackHandler( enabled = !state.showLoader, onBack = onBackClick, @@ -64,6 +75,7 @@ fun DeveloperSettingsView( onOpenShowkase = onOpenShowkase, ) NotificationCategory(onPushHistoryClick) + MarkAllRoomsAsReadCategory(state) if (state.isEnterpriseBuild) { PreferenceCategory(title = "Theme") { @@ -152,6 +164,32 @@ fun DeveloperSettingsView( ) } +@Composable +private fun MarkAllRoomsAsReadCategory(state: DeveloperSettingsState) { + PreferenceCategory(title = "Room list") { + ListItem( + headlineContent = { + Text("Mark all rooms as read") + }, + supportingContent = { + Text( + text = """ + This will send a private read receipt and a read marker in every room you are part of. + It's a long running operation that might get rate limited. + It will run in the background but the app must be alive for it to finish. + """.trimIndent(), + style = ElementTheme.typography.fontBodySmRegular, + color = ElementTheme.colors.textSecondary, + ) + }, + enabled = !state.showLoader, + onClick = { + state.eventSink(DeveloperSettingsEvents.MarkAllRoomsAsRead(needsConfirmation = true)) + }, + ) + } +} + @Composable private fun NotificationCategory(onPushHistoryClick: () -> Unit) { PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_title)) { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/MarkAllRoomsAsRead.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/MarkAllRoomsAsRead.kt new file mode 100644 index 0000000000..d09ac11dd5 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/MarkAllRoomsAsRead.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.tasks + +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.push.api.notifications.NotificationCleaner +import kotlinx.coroutines.withContext + +interface MarkAllRoomsAsRead { + suspend operator fun invoke(): Result +} + +@ContributesBinding(SessionScope::class) +class DefaultMarkAllRoomsAsRead( + private val client: MatrixClient, + private val notificationCleaner: NotificationCleaner, + private val coroutineDispatchers: CoroutineDispatchers, +) : MarkAllRoomsAsRead { + override suspend fun invoke(): Result = withContext(coroutineDispatchers.io) { + client.markAllRoomsAsRead() + .onSuccess { + notificationCleaner.clearAllMessagesEvents(client.sessionId) + } + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/MarkRoomAsRead.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/MarkRoomAsRead.kt new file mode 100644 index 0000000000..072fa1ea87 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/MarkRoomAsRead.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.tasks + +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.timeline.ReceiptType +import io.element.android.libraries.preferences.api.store.SessionPreferencesStore +import io.element.android.libraries.push.api.notifications.NotificationCleaner +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.withContext + +interface MarkRoomAsRead { + suspend operator fun invoke(roomId: RoomId): Result +} + +@ContributesBinding(SessionScope::class) +class DefaultMarkRoomAsRead( + private val client: MatrixClient, + private val notificationCleaner: NotificationCleaner, + private val sessionPreferencesStore: SessionPreferencesStore, + private val coroutineDispatchers: CoroutineDispatchers, +) : MarkRoomAsRead { + override suspend fun invoke(roomId: RoomId): Result = withContext(coroutineDispatchers.io) { + notificationCleaner.clearMessagesForRoom(client.sessionId, roomId) + val room = client.getRoom(roomId) ?: return@withContext Result.failure(IllegalStateException("Room not found")) + room.use { + it.setUnreadFlag(isUnread = false) + val receiptType = if (sessionPreferencesStore.isSendPublicReadReceiptsEnabled().first()) { + ReceiptType.READ + } else { + ReceiptType.READ_PRIVATE + } + it.markAsRead(receiptType) + } + } +} diff --git a/features/preferences/impl/src/main/res/values-et/translations.xml b/features/preferences/impl/src/main/res/values-et/translations.xml index d1e2b91d58..3d5102fa9f 100644 --- a/features/preferences/impl/src/main/res/values-et/translations.xml +++ b/features/preferences/impl/src/main/res/values-et/translations.xml @@ -58,6 +58,7 @@ "Kas tahad katsetada?" "Katsed" "Täiendavad seadistused" + "Kõne helin" "Hääl- ja videokõned" "Eelistused ei sobi omavahel" "Et eelistusi oleks kergem leida, me oleme lihtsustanud teavituste seadistusi. Kuigi mõned varem valitud eelistused pole siin näha, siis nad kehtivad jätkuvalt. @@ -76,10 +77,26 @@ Kui sa jätkad muutmist, siis võivad muutuda ka need peidetud eelistused.""Kutsed" "Sinu koduserver ei toeta seda funktsionaalsust krüptitud jututubades ja seega ei pruugi kõik teavitused sinuni jõuda." "Mainimiste alusel" + "Vali muu ​​helin…" + "Hetkel on kasutusel %1$s" + "Sõnumi heli" + "Sõnumi heli" "Kõik" "Mainimiste alusel" "Teavita mind" "Teavita mind @jututoa puhul" + "Kohandatud" + "Sinu valitud helin…" + "Viga faili kustutamisel" + "Elementi vaikimisi väärtus" + "Elemendi hajumine" + "Viga faili importimisel" + "Viga helina eelvaate esitamisel" + "Helin" + "Sulge helinavea viga" + "Viga helina seadistamisel" + "Vaikne" + "Süsteemi vaikimisi väärtus" "Teavituste saamiseks palun muuda oma %1$s." "süsteemi seadistusi" "Süsteemi teavitused on välja lülitatud" diff --git a/features/preferences/impl/src/main/res/values-fi/translations.xml b/features/preferences/impl/src/main/res/values-fi/translations.xml index 99f900bcc1..f37673427f 100644 --- a/features/preferences/impl/src/main/res/values-fi/translations.xml +++ b/features/preferences/impl/src/main/res/values-fi/translations.xml @@ -58,6 +58,7 @@ "Kokeilunhaluinen olo?" "Labrat" "Lisäasetukset" + "Puhelun soittoääni" "Ääni- ja videopuheluista" "Konfiguraatio ei täsmää" "Olemme yksinkertaistaneet ilmoitusasetuksia, jotta vaihtoehdot olisi helpompi löytää. Joitakin aiemmin valitsemiasi asetuksia ei näytetä tässä, mutta ne ovat edelleen voimassa. @@ -76,17 +77,26 @@ Jos jatkat, jotkin asetukset saattavat muuttua." "Kutsut" "Kotipalvelimesi ei tue tätä vaihtoehtoa salatuissa huoneissa, joten et ehkä saa ilmoitusta joissakin huoneissa." "Maininnat" + "Valitse toinen ääni…" + "Käytössä tällä hetkellä %1$s" + "Viestin ääni" + "Viestin ääni" "Kaikki" "Maininnat" "Ilmoita minulle" "Ilmoita minulle @room-maininnoista" + "Mukautettu" "Mukautettu ääni…" "Virhe tiedoston poistamisessa" "Elementin oletus" + "Element Fade" "Virhe tiedoston tuonnissa" "Ongelma ilmoitusäänen esikatselussa" "Ääni" + "Hylkää hälytysäänen virhe" "Ongelma ilmoitusäänen asettamisessa" + "Hiljainen" + "Järjestelmän oletus" "Jos haluat saada ilmoituksia, vaihda %1$s." "järjestelmäsi asetuksia" "Järjestelmän ilmoitukset on poissa päältä" diff --git a/features/preferences/impl/src/main/res/values-fr/translations.xml b/features/preferences/impl/src/main/res/values-fr/translations.xml index d7f17e4ffe..fc57491f4a 100644 --- a/features/preferences/impl/src/main/res/values-fr/translations.xml +++ b/features/preferences/impl/src/main/res/values-fr/translations.xml @@ -58,6 +58,7 @@ "Envie d’expérimenter?" "Expérimental" "Réglages supplémentaires" + "Sonnerie d’appel" "Appels audio et vidéo" "Incompatibilité de configuration" "Nous avons simplifié les paramètres des notifications pour que les options soient plus faciles à trouver. Certains paramètres personnalisés que vous avez choisis par le passé ne sont pas affichés ici, mais ils sont toujours actifs. @@ -76,15 +77,31 @@ Si vous continuez, il est possible que certains de vos paramètres soient modifi "Invitations" "Votre serveur d’accueil ne supporte pas cette option pour les salons chiffrés, vous pourriez ne pas être notifié(e) dans certains salons." "Mentions" + "Choisir un autre son…" + "Vous utilisez actuellement %1$s" + "Son des messages" + "Son des messages" "Tous" "Mentions" "Prévenez-moi pour" "Prévenez-moi si un message contient \"@room\"" + "Personnalisé" "Son personnalisé…" + "Erreur lors de la suppression du fichier" + "Element - défaut" + "Element - doux" + "Erreur lors de l’importation du fichier" + "Problème lors de l’écoute préalable du son d’alerte" + "Son" + "Ignorer l’erreur des sons d’alerte" + "Problème de configuration du son d’alerte" + "Silencieux" + "Paramètres par défaut du système" "Pour recevoir des notifications, veuillez modifier votre %1$s." "paramètres du système" "Les notifications du système sont désactivées" "Notifications" + "Noir" "Sombre" "Clair" "Système" diff --git a/features/preferences/impl/src/main/res/values-hu/translations.xml b/features/preferences/impl/src/main/res/values-hu/translations.xml index 4c1b988696..f4a9616321 100644 --- a/features/preferences/impl/src/main/res/values-hu/translations.xml +++ b/features/preferences/impl/src/main/res/values-hu/translations.xml @@ -58,6 +58,7 @@ "Kísérletezni szeretne?" "Kísérletek" "További beállítások" + "Csengőhang" "Hang- és videóhívások" "Konfigurációs eltérés" "Egyszerűsítettük az értesítési beállításokat, hogy könnyebben megtalálhatók legyenek a lehetőségek. A korábban kiválasztott egyéni beállítások némelyike nem jelenik meg itt, de továbbra is aktív. @@ -76,10 +77,26 @@ Ha folytatja, egyes beállítások megváltozhatnak." "Meghívók" "A Matrix-kiszolgálója nem támogatja ezt a beállítást a titkosított szobákban, előfordulhat, hogy egyes szobákban nem kap értesítést." "Említések" + "Válasszon egy másik hangot…" + "Jelenleg használt: %1$s" + "Üzenet hang" + "Üzenet hang" "Összes" "Említések" "Értesítés ezekről:" "Értesítés a @room említésekor" + "Egyedi" + "Egyedi hang…" + "Hiba a fájl törlésekor" + "Element alapértelmezett" + "Element Fade" + "Hiba a fájl importálásakor" + "Probléma a riasztási hang előnézetekor" + "Hang" + "Figyelmeztető hang hiba kikapcsolása" + "Probléma a riasztási hang beállításánál" + "Néma" + "Rendszer alapértelmezett" "Az értesítések fogadásához kérjük, módosítsa a %1$s." "rendszerbeállításokat" "A rendszerértesítések ki vannak kapcsolva" diff --git a/features/preferences/impl/src/main/res/values-ja/translations.xml b/features/preferences/impl/src/main/res/values-ja/translations.xml index 5cab6bdcf8..8e97d03c54 100644 --- a/features/preferences/impl/src/main/res/values-ja/translations.xml +++ b/features/preferences/impl/src/main/res/values-ja/translations.xml @@ -54,9 +54,10 @@ "スレッドへの返信を有効化" "変更を適用するためにアプリケーションは再起動します。" "開発段階の最新機能を試すことができます。未完成のため、変更や不安定な挙動が生じる可能性があります。" - "探究したいですか?" + "探究的な気分ですか?" "ラボ" "追加設定" + "発信音" "音声・ビデオ通話" "設定の不一致" "通知設定を簡素化し、見つけやすくしました。以前のカスタム設定の一部はここに表示されませんが、引き続き有効です。 @@ -75,10 +76,15 @@ "招待" "暗号化されたルームでは、この機能にホームサーバーが対応しないため、一部のルームから通知が届かない可能性があります。" "メンション" + "他の音を選択…" + "%1$s を使用中" + "メッセージの音" + "メッセージの音" "すべて" "メンション" "以下を通知" @ルームで通知を受け取る + "カスタム" "カスタム着信音" "ファイルの削除に失敗" "Element の既定" @@ -86,33 +92,10 @@ "ファイルの取り込みに失敗" "通知音のプレビューで問題が発生しました" "音" + "通知音のエラーを無視" "通知音の設定に問題が発生しました" - "アラート" - "予感" - "ベル" - "開花" - "カリプソ" - "チャイム" - "汽車ポッポ" - "下降" - "エレクトロニック" - "ファンファーレ" - "ガラス" - "ホーン" - "はしご" - "メヌエット" - "速報" - "ノワール" - "シャーウッドの森" - "スペル" - "サスペンス" - "シュッ" - "電信" - "つま先" - "トリトーン" - "さえずり" - "タイプライター" - "アップデート" + "サイレント" + "システムのデフォルト" "通知を受け取るには、%1$s を変更してください。" "システム設定" "システムで通知がオフです" diff --git a/features/preferences/impl/src/main/res/values-ko/translations.xml b/features/preferences/impl/src/main/res/values-ko/translations.xml index e2c5e8e83b..dcff2d7b6c 100644 --- a/features/preferences/impl/src/main/res/values-ko/translations.xml +++ b/features/preferences/impl/src/main/res/values-ko/translations.xml @@ -11,6 +11,13 @@ "방 초대 요청에서 아바타 숨기기" "타임라인에서 미디어 미리 보기 숨기기" "실험실" + "위치 업데이트 전환 기준 거리" + "이 앱에 \"정확한 위치\" 권한이 허용되어 있는지 확인해 주세요. 권한을 변경하려면 %1$s(으)로 이동하세요." + "앱 설정" + "실시간 위치 업데이트" + + "%1$d미터마다" + "사진과 동영상을 더 빠르게 업로드하고 데이터 사용량을 줄이세요" "미디어 품질 최적화" "중재와 안전" @@ -51,6 +58,7 @@ "새로운 것을 시도해보고 싶으신가요?" "실험실" "추가 설정" + "통화 벨소리" "음성 및 동영상 통화" "구성 불일치" "알림 설정을 간소화하여 옵션을 더 쉽게 찾을 수 있도록 했습니다. 과거에 선택한 일부 맞춤 설정은 여기에서 표시되지 않지만, 여전히 활성화되어 있습니다. @@ -69,14 +77,31 @@ "초대" "귀하의 홈서버는 암호화된 방에서 이 옵션을 지원하지 않으므로, 일부 방에서는 알림이 표시되지 않을 수 있습니다." "언급" + "다른 소리를 선택하세요…" + "현재 사용 중: %1$s" + "메시지 소리" + "메시지 소리" "모두" "언급" "나에게 알려주세요" @room 에서 알림 받기 + "사용자 지정" + "소리 사용자 지정" + "파일 삭제 오류" + "Element 기본 설정" + "엘리먼트 페이드" + "파일 가져오기 오류" + "알림음 미리듣기 문제 발생" + "소리" + "알림음 오류 해제" + "알림 소리 설정 문제" + "무음" + "시스템 기본값" "알림을 받으려면 %1$s 을 변경해 주세요." "시스템 설정" "시스템 알림이 꺼져 있습니다." "알림" + "검은색" "다크" "라이트" "시스템" diff --git a/features/preferences/impl/src/main/res/values-pl/translations.xml b/features/preferences/impl/src/main/res/values-pl/translations.xml index ca81984032..03be155520 100644 --- a/features/preferences/impl/src/main/res/values-pl/translations.xml +++ b/features/preferences/impl/src/main/res/values-pl/translations.xml @@ -59,6 +59,7 @@ "Chcesz poeksperymentować?" "Laboratoria" "Dodatkowe ustawienia" + "Dzwonek połączenia" "Połączenia audio i wideo" "Niezgodność konfiguracji" "Uprościliśmy Ustawienia powiadomień, aby ułatwić nawigowanie między opcjami. Niektóre ustawienia, które wybrałeś mogły zniknąć, lecz są wciąż aktywne. @@ -77,10 +78,15 @@ Niektóre ustawienia mogą ulec zmianie, jeśli kontynuujesz." "Zaproszenia" "Twój serwer domowy nie wspiera tej opcji w pokojach szyfrowanych, możesz nie otrzymać powiadomień z niektórych pokoi." "Wzmianki" + "Wybierz inny dźwięk…" + "Aktualnie używany %1$s" + "Dźwięk wiadomości" + "Dźwięk wiadomości" "Wszystkie" "Wzmianki" "Powiadamiaj mnie przez" "Powiadom mnie na @pokój" + "Własny" "Własny dźwięk…" "Błąd usuwania pliku" "Domyślny Element" @@ -88,33 +94,10 @@ Niektóre ustawienia mogą ulec zmianie, jeśli kontynuujesz." "Błąd importowania pliku" "Wystąpił błąd podczas podglądania dźwięku powiadomień" "Dźwięk" + "Pomiń dźwięk błędu" "Nie udało się ustawić dźwięku powiadomień" - "Alert" - "Oczekiwanie" - "Dzwonek" - "Rozkwit" - "Kalipso" - "Gong" - "Ciuchcia" - "Opadający" - "Elektroniczna" - "Fanfary" - "Szkło" - "Róg" - "Drabina" - "Minuet" - "Wiadomości" - "Kryminał" - "Las Sherwood" - "Zaklęcie" - "Napięcie" - "Świst" - "Telegraf" - "Na palcach" - "Trójdźwięk" - "Tweet" - "Maszyna do pisania" - "Aktualizacja" + "Cichy" + "Ustawienie domyślne" "Aby otrzymywać powiadomienia, zmień swoje%1$s." "ustawienia systemowe" "Powiadomienia systemowe wyłączone" diff --git a/features/preferences/impl/src/main/res/values-ru/translations.xml b/features/preferences/impl/src/main/res/values-ru/translations.xml index eb4ad2245d..e81bd50021 100644 --- a/features/preferences/impl/src/main/res/values-ru/translations.xml +++ b/features/preferences/impl/src/main/res/values-ru/translations.xml @@ -23,8 +23,8 @@ "Загружайте фотографии и видео быстрее и сокращайте потребление трафика" "Оптимизировать качество мультимедиа" "Модерация и безопасность" - "Автоматически оптимизируйте изображения для более быстрой загрузки и уменьшения размера файлов." - "Оптимизируйте качество загрузки изображения" + "Автоматически оптимизировать изображения для более быстрой загрузки и уменьшения размера файлов." + "Оптимизировать качество загрузки изображений" "%1$s. Нажмите здесь, чтобы изменить." "Высокое (1080p)" "Низкое (480p)" @@ -35,14 +35,14 @@ "Уведомления о прочтении" "Если этот параметр выключен, другие пользователи не будут видеть, прочитали ли вы сообщения. Вы по-прежнему будете видеть статус прочтения других пользователей." "Делиться присутствием" - "Если выключено, вы не будете видеть, кто печатает и читает сообщения, а также другие пользователи не будут знать, когда вы печатаете или читаете сообщения." + "Если выключено, Вы не будете видеть, кто печатает и читает сообщения, а также другие пользователи не будут знать, когда Вы печатаете или читаете сообщения." "Всегда скрывать" "Всегда показывать" "В приватных комнатах" "Скрытые медиа всегда можно просмотреть, нажав на них." "Показать медиа в истории сообщений" "Включить опцию просмотра источника сообщения в истории сообщений." - "У вас нет заблокированных пользователей" + "У Вас нет заблокированных пользователей" "Разблокировать" "Вы снова сможете увидеть все сообщения." "Разблокировать пользователя" @@ -59,11 +59,12 @@ "Хотите попробовать?" "Лаборатория" "Дополнительные параметры" + "Мелодия звонка" "Аудио и видео звонки" "Несоответствие конфигурации" - "Мы упростили настройки уведомлений, чтобы упростить поиск опций. Некоторые пользовательские настройки, выбранные вами ранее, не отображаются в данном меню, но они все еще активны. + "Мы упростили настройки уведомлений, чтобы упростить поиск опций. Некоторые пользовательские настройки, выбранные вами ранее, не отображаются в данном меню, но они всё ещё активны. -Если вы продолжите, некоторые настройки могут быть изменены." +Если Вы продолжите, некоторые настройки могут быть изменены." "В личных чатах" "Отдельные настройки для каждого чата" "Произошла ошибка при обновлении настройки уведомления." @@ -72,15 +73,31 @@ "Уведомлять меня в личных чатах" "Уведомлять меня в групповых чатах" "Включить уведомления на данном устройстве" - "Конфигурация не была исправлена, попробуйте еще раз." + "Конфигурация не была исправлена, попробуйте ещё раз." "В групповых чатах" "Приглашения" - "Ваш сервер не поддерживает эту опцию для зашифрованных комнат, вы можете не получать некоторые уведомления." + "Ваш сервер не поддерживает эту опцию для зашифрованных комнат, Вы можете не получать некоторые уведомления." "Упоминания" + "Выбрать другой звук…" + "Сейчас используется %1$s" + "Звук сообщения" + "Звук сообщения" "Все" "Упоминания" "Уведомлять меня" "Уведомлять меня при упоминании @room" + "Пользовательский" + "Пользовательский звук…" + "Ошибка при удалении файла" + "Element по умолчанию" + "Element Fade" + "Ошибка импорта файла" + "Ошибка предварительного прослушиванием звука" + "Звук" + "Отклонить ошибку о звуке" + "Проблема с настройкой звукового оповещения" + "Без звука" + "Как в системе" "Чтобы получать уведомления, измените %1$s." "системные настройки" "Системные уведомления выключены" @@ -91,5 +108,5 @@ "Системное" "История уведомлений" "Устранение неполадок" - "Уведомления об устранении неполадок" + "Устранение неполадок с уведомлениями" diff --git a/features/preferences/impl/src/main/res/values-uk/translations.xml b/features/preferences/impl/src/main/res/values-uk/translations.xml index 4d8d738122..28dfd799f8 100644 --- a/features/preferences/impl/src/main/res/values-uk/translations.xml +++ b/features/preferences/impl/src/main/res/values-uk/translations.xml @@ -1,7 +1,7 @@ "Щоб ніколи не пропустити важливий виклик, змініть налаштування, щоб увімкнути повноекранні сповіщення, коли телефон заблоковано." - "Покращуйте досвід дзвінків" + "Покращуйте якість викликів" "Виберіть спосіб отримання сповіщень" "Режим розробника" "Увімкніть доступ до функцій і можливостей для розробників." @@ -10,18 +10,18 @@ "Неправильна URL-адреса. Переконайтеся, що ви вказали протокол (http/https) та правильну адресу." "Сховати аватари у запитах на запрошення до кімнат" "Сховати попередній перегляд медіа у стрічці" - "Лабораторії" + "Лабораторія" "Відстань, яку потрібно пройти, щоб ініціювати оновлення." - "Переконайтеся, що для цього додатка увімкнено функцію «Точна геолокація». Щоб змінити дозвіл, перейдіть на сторінку %1$s." - "Налаштування додатка" + "Переконайтеся, що для цього застосунку ввімкнено функцію «Точна геолокація». Щоб змінити дозвіл, перейдіть на сторінку %1$s." + "Налаштування застосунку" "Оновлення місцезнаходження в реальному часі" "Кожен %1$d метр" "Кожні %1$d метри" "Кожні %1$d метрів" - "Швидше завантажуйте фотографії та відео та зменшуйте використання даних" - "Оптимізуйте медіаякість" + "Швидше завантаження світлин і відео та зменшення обсягу трафіку" + "Оптимізація якості медіа" "Модерування й безпека" "Автоматична оптимізація зображень для швидшого вивантаження та зменшення розміру файлів." "Оптимізація якості вивантажуваних зображень" @@ -34,14 +34,14 @@ "Вимкніть редактор розширеного тексту, щоб вводити Markdown вручну." "Читати журнали" "Якщо вимкнено, ваші сповіщення про прочитання нікому не надсилатимуться. Ви все одно отримуватимете сповіщення про прочитання від інших користувачів." - "Поділіться присутністю" - "Якщо цей параметр вимкнено, ви не зможете надсилати й отримувати звіти про прочитання чи сповіщення про введення тексту." + "Ділитися присутністю" + "Якщо вимкнути цю функцію, ви не зможете надсилати чи отримувати підтвердження прочитання або сповіщення про набір тексту." "Завжди ховати" "Завжди показувати" "У приватних кімнатах" "Сховані медіа завжди можна переглянути, натиснувши на нього" "Показувати медіа у стрічці" - "Увімкнути опцію для перегляду коду повідомлення в стрічці" + "Увімкнення цього параметра уможливить перегляд джерела повідомлень зі стрічки." "У вас немає заблокованих користувачів." "Розблокувати" "Ви знову зможете бачити всі повідомлення від них." @@ -55,11 +55,12 @@ "Оновлення профілю…" "Увімкнути відповіді в гілках" "Застосунок перезапуститься, щоб застосувати цю зміну." - "Випробуйте наші останні ідеї, що перебувають на стадії розробки. Ці функції ще не остаточні; вони можуть бути нестабільними та змінюватися." + "Випробуйте найновіші ідеї наших розробників. Ці функції ще не завершені, вони можуть бути нестабільними та змінюватись." "Хочете поекспериментувати?" - "Лабораторії" + "Лабораторія" "Додаткові налаштування" - "Аудіо та відеодзвінки" + "Мелодія виклику" + "Аудіо та відеовиклики" "Невідповідність конфігурації" "Ми спростили налаштування сповіщень, щоб полегшити пошук параметрів. Деякі користувацькі налаштування, які ви вибрали раніше, тут не відображаються, але вони все ще активні. @@ -77,14 +78,30 @@ "Запрошення" "Ваш домашній сервер не підтримує цю опцію в зашифрованих кімнатах, ви можете не отримати сповіщення в деяких кімнатах." "Згадки" + "Обрати інший звук…" + "Наразі використовується %1$s" + "Звук повідомлення" + "Звук повідомлення" "Усі" "Згадки" "Сповіщати мене про" "Сповіщати про @room" + "Власний" + "Користувацький звук…" + "Помилка видалення файлу" + "Типово Element" + "Згасання Element" + "Помилка імпорту файлу" + "Проблема з попереднім прослуховуванням звуку сповіщення" + "Звук" + "Проблема налаштовування звуку сповіщення" + "Без звуку" + "Як у системі" "Щоб отримувати сповіщення змініть свої %1$s." "системні налаштування" "Системні сповіщення вимкнені" "Сповіщення" + "Темна" "Темна" "Світла" "Системна" diff --git a/features/preferences/impl/src/main/res/values-zh/translations.xml b/features/preferences/impl/src/main/res/values-zh/translations.xml index 3726b82206..0b8bbd2a07 100644 --- a/features/preferences/impl/src/main/res/values-zh/translations.xml +++ b/features/preferences/impl/src/main/res/values-zh/translations.xml @@ -57,6 +57,7 @@ "想尝试新功能?" "实验室" "更多设置" + "来电铃声" "音视频通话" "配置不匹配" "我们简化了通知设置,使选项更易于查找。你曾经选择的某些自定义设置未在此处显示,但它们仍然有效。 @@ -75,44 +76,26 @@ "邀请" "主服务器不支持在加密房间中的此选项,因此在某些房间你可能无法收到通知。" "提及" + "选择其它提示音…" + "当前正在使用 %1$s" + "消息提示音" + "消息提示音" "全部" "提及" "通知我以下类型" "提及所有成员(@room)时通知我" - "自定义声音…" + "自定义" + "自定义提示音…" "删除文件时出错" "Element 默认" "Element 淡入" "导入文件时出错" "预览提示音时出现问题" - "声音" + "提示音" + "忽略提示音错误" "设置提示音时出现问题" - "提醒声" - "悉心期盼" - "铃铛" - "百花怒放" - "即兴曲调" - "风铃" - "火车鸣笛" - "渐弱" - "电子乐" - "嘹亮吹奏声" - "玻璃声" - "圆号" - "连音效果" - "小步舞曲" - "新闻快讯" - "夜色" - "绿林好汉的旋律" - "神奇魔咒" - "侦探悬念" - "嗖嗖声" - "敲打电报" - "蹑手蹑脚" - "三全音" - "鸟鸣声" - "敲打字机" - "整点新闻" + "静默" + "系统默认" "要接收通知,请更改 %1$s。" "系统设置" "系统通知已关闭" diff --git a/features/preferences/impl/src/main/res/values/localazy.xml b/features/preferences/impl/src/main/res/values/localazy.xml index f2a3d87770..cca92d0032 100644 --- a/features/preferences/impl/src/main/res/values/localazy.xml +++ b/features/preferences/impl/src/main/res/values/localazy.xml @@ -96,33 +96,7 @@ If you proceed, some of your settings may change." "Dismiss alert sound error" "Problem setting alert sound" "Silent" - "Alert" - "Anticipate" - "Bell" - "Bloom" - "Calypso" - "Chime" - "Choo Choo" "System Default" - "Descent" - "Electronic" - "Fanfare" - "Glass" - "Horn" - "Ladder" - "Minuet" - "News Flash" - "Noir" - "Sherwood Forest" - "Spell" - "Suspense" - "Swish" - "Telegraph" - "Tiptoes" - "Tri-tone" - "Tweet" - "Typewriters" - "Update" "To receive notifications, please change your %1$s." "system settings" "System notifications turned off" diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/about/AboutViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/about/AboutViewTest.kt index e7ce526843..6d18bfeebf 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/about/AboutViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/about/AboutViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalledWithParam @@ -22,11 +21,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class AboutViewTest { +class AboutViewTest : RobolectricTest() { @Test fun `clicking on back invokes back callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsViewTest.kt index 302a209578..fa4ecfd829 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.preferences.impl.R @@ -32,13 +31,12 @@ import io.element.android.tests.testutils.assertNoNodeWithText import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.toImmutableList import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class AdvancedSettingsViewTest { +class AdvancedSettingsViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUserViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUserViewTest.kt index 993d14caab..467ace4675 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUserViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUserViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.preferences.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.ui.components.aMatrixUserList @@ -26,11 +25,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class BlockedUserViewTest { +class BlockedUserViewTest : RobolectricTest() { @Test fun `clicking on back invokes back callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt index ec70b19eab..52d1247668 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt @@ -17,6 +17,7 @@ import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.preferences.impl.developer.appsettings.anAppDeveloperSettingsState import io.element.android.features.preferences.impl.tasks.FakeClearCacheUseCase import io.element.android.features.preferences.impl.tasks.FakeComputeCacheSizeUseCase +import io.element.android.features.preferences.impl.tasks.FakeMarkAllRoomsAsRead import io.element.android.features.preferences.impl.tasks.VacuumStoresUseCase import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter import io.element.android.libraries.architecture.AsyncAction @@ -127,6 +128,28 @@ class DeveloperSettingsPresenterTest { } } + @Test + fun `present - confirm mark all rooms as read`() = runTest { + val markAllRoomsAsRead = FakeMarkAllRoomsAsRead() + val presenter = createDeveloperSettingsPresenter(markAllRoomsAsRead = markAllRoomsAsRead) + presenter.test { + skipItems(2) + val initialState = awaitItem() + initialState.eventSink(DeveloperSettingsEvents.MarkAllRoomsAsRead(needsConfirmation = true)) + val stateWithConfirmation = awaitItem() + assertThat(stateWithConfirmation.markAllRoomsAsReadAction.isConfirming()).isTrue() + stateWithConfirmation.eventSink(DeveloperSettingsEvents.MarkAllRoomsAsRead(needsConfirmation = false)) + awaitItem().also { state -> + assertThat(state.markAllRoomsAsReadAction.isConfirming()).isFalse() + assertThat(state.markAllRoomsAsReadAction).isInstanceOf(AsyncAction.Loading::class.java) + } + awaitItem().also { state -> + assertThat(state.markAllRoomsAsReadAction).isInstanceOf(AsyncAction.Success::class.java) + assertThat(markAllRoomsAsRead.invokeCallCount).isEqualTo(1) + } + } + } + @Test fun `present - VacuumStores action invokes the VacuumStoresUseCase`() = runTest { var vacuumCalled = false @@ -151,6 +174,7 @@ class DeveloperSettingsPresenterTest { enterpriseService: EnterpriseService = FakeEnterpriseService(), vacuumStoresUseCase: VacuumStoresUseCase = VacuumStoresUseCase {}, databaseSizesUseCase: GetDatabaseSizesUseCase = GetDatabaseSizesUseCase { Result.success(SdkStoreSizes(null, null, null, null)) }, + markAllRoomsAsRead: FakeMarkAllRoomsAsRead = FakeMarkAllRoomsAsRead(), ): DeveloperSettingsPresenter { return DeveloperSettingsPresenter( appDeveloperSettingsPresenter = { anAppDeveloperSettingsState() }, @@ -161,6 +185,7 @@ class DeveloperSettingsPresenterTest { vacuumStoresUseCase = vacuumStoresUseCase, databaseSizesUseCase = databaseSizesUseCase, fileSizeFormatter = FakeFileSizeFormatter(), + markAllRoomsAsRead = markAllRoomsAsRead, ) } } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt index 61d7278a8a..adae2ca816 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt @@ -16,19 +16,17 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.preferences.impl.R import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class DeveloperSettingsViewTest { +class DeveloperSettingsViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) @@ -73,7 +71,7 @@ class DeveloperSettingsViewTest { } } - @Config(qualifiers = "h2200dp") + @Config(qualifiers = "h2400dp") @Test fun `clicking on clear cache emits the expected event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPageTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPageTest.kt index 17218c6ab5..3500b96731 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPageTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPageTest.kt @@ -21,7 +21,6 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.preferences.impl.R import io.element.android.features.preferences.impl.developer.tracing.LogLevelItem import io.element.android.libraries.ui.strings.CommonStrings @@ -30,12 +29,11 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class AppDeveloperSettingsPageTest { +class AppDeveloperSettingsPageTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt index dee0df511c..57edf01a1d 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.preferences.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.test.AN_EXCEPTION @@ -29,12 +28,11 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class NotificationSettingsViewTest { +class NotificationSettingsViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSoundPickerTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSoundPickerTest.kt index 3031187f25..48f5a21eca 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSoundPickerTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSoundPickerTest.kt @@ -14,12 +14,10 @@ import android.provider.Settings import androidx.core.net.toUri import com.google.common.truth.Truth.assertThat import io.element.android.libraries.preferences.api.store.NotificationSound +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class NotificationSoundPickerTest { +class NotificationSoundPickerTest : RobolectricTest() { @Test fun `buildRingtonePickerIntent encodes SystemDefault as the system default URI`() { val intent = buildRingtonePickerIntent( diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootViewTest.kt index 88ebbf64a1..aded097059 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootViewTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.preferences.impl.R import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.A_USER_ID_2 @@ -28,11 +27,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class PreferencesRootViewTest { +class PreferencesRootViewTest : RobolectricTest() { @Test fun `clicking on back invokes back callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt index 1c1cb83def..ed1eb4255b 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt @@ -24,16 +24,14 @@ import io.element.android.libraries.sessionstorage.test.aCacheData import io.element.android.services.appnavstate.impl.DefaultActiveRoomsHolder import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import okhttp3.OkHttpClient import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultClearCacheUseCaseTest { +class DefaultClearCacheUseCaseTest : RobolectricTest() { @Test fun `execute clear cache should do all the expected tasks`() = runTest { val activeRoomsHolder = DefaultActiveRoomsHolder().apply { addRoom(FakeJoinedRoom()) } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/FakeMarkAllRoomsAsRead.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/FakeMarkAllRoomsAsRead.kt new file mode 100644 index 0000000000..cbb5992b77 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/FakeMarkAllRoomsAsRead.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.tasks + +import io.element.android.tests.testutils.simulateLongTask + +class FakeMarkAllRoomsAsRead( + private val invokeLambda: suspend () -> Result = { Result.success(Unit) }, +) : MarkAllRoomsAsRead { + var invokeCallCount = 0 + private set + + override suspend fun invoke(): Result = simulateLongTask { + invokeCallCount++ + invokeLambda() + } +} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/FakeMarkRoomAsRead.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/FakeMarkRoomAsRead.kt new file mode 100644 index 0000000000..3c1a3687bc --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/FakeMarkRoomAsRead.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.tasks + +import io.element.android.libraries.matrix.api.core.RoomId + +class FakeMarkRoomAsRead( + private val invokeLambda: suspend (RoomId) -> Result = { Result.success(Unit) }, +) : MarkRoomAsRead { + val invokedRoomIds = mutableListOf() + + override suspend fun invoke(roomId: RoomId): Result { + invokedRoomIds.add(roomId) + return invokeLambda(roomId) + } +} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/MarkAllRoomsAsReadTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/MarkAllRoomsAsReadTest.kt new file mode 100644 index 0000000000..4079d19564 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/MarkAllRoomsAsReadTest.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.tasks + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.test.A_SESSION_ID +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class MarkAllRoomsAsReadTest { + @Test + fun `invoke - delegates to client and clears all notifications`() = runTest { + val markAllRoomsAsReadLambda = lambdaRecorder> { Result.success(Unit) } + val clearAllMessagesEventsLambda = lambdaRecorder { } + val markAllRoomsAsRead = DefaultMarkAllRoomsAsRead( + client = FakeMatrixClient( + markAllRoomsAsReadResult = markAllRoomsAsReadLambda, + ), + notificationCleaner = FakeNotificationCleaner( + clearAllMessagesEventsLambda = clearAllMessagesEventsLambda, + ), + coroutineDispatchers = testCoroutineDispatchers(), + ) + + val result = markAllRoomsAsRead() + + assertThat(result.isSuccess).isTrue() + markAllRoomsAsReadLambda.assertions().isCalledOnce() + clearAllMessagesEventsLambda.assertions().isCalledOnce().with(value(A_SESSION_ID)) + } + + @Test + fun `invoke - does not clear notifications when client fails`() = runTest { + val clearAllMessagesEventsLambda = lambdaRecorder { } + val markAllRoomsAsRead = DefaultMarkAllRoomsAsRead( + client = FakeMatrixClient( + markAllRoomsAsReadResult = { Result.failure(IllegalStateException("Failed")) }, + ), + notificationCleaner = FakeNotificationCleaner( + clearAllMessagesEventsLambda = clearAllMessagesEventsLambda, + ), + coroutineDispatchers = testCoroutineDispatchers(), + ) + + val result = markAllRoomsAsRead() + + assertThat(result.isFailure).isTrue() + clearAllMessagesEventsLambda.assertions().isNeverCalled() + } +} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/MarkRoomAsReadTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/MarkRoomAsReadTest.kt new file mode 100644 index 0000000000..301b18b285 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/MarkRoomAsReadTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package io.element.android.features.preferences.impl.tasks + +import com.google.common.truth.Truth.assertThat +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.timeline.ReceiptType +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.room.FakeBaseRoom +import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore +import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class MarkRoomAsReadTest { + @Test + fun `invoke - clears notifications, clears unread flag and sends public read receipt`() = runTest { + val markAsReadResult = lambdaRecorder> { Result.success(Unit) } + val room = FakeBaseRoom(markAsReadResult = markAsReadResult) + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, room) + } + val clearMessagesForRoomLambda = lambdaRecorder { _: SessionId, _: RoomId -> } + val notificationCleaner = FakeNotificationCleaner(clearMessagesForRoomLambda = clearMessagesForRoomLambda) + val sessionPreferencesStore = InMemorySessionPreferencesStore() + val markRoomAsRead = DefaultMarkRoomAsRead( + client = matrixClient, + notificationCleaner = notificationCleaner, + sessionPreferencesStore = sessionPreferencesStore, + coroutineDispatchers = testCoroutineDispatchers(), + ) + + val result = markRoomAsRead(A_ROOM_ID) + runCurrent() + + assertThat(result.isSuccess).isTrue() + clearMessagesForRoomLambda.assertions().isCalledOnce() + .with(value(A_SESSION_ID), value(A_ROOM_ID)) + assertThat(room.setUnreadFlagCalls).isEqualTo(listOf(false)) + markAsReadResult.assertions().isCalledOnce().with(value(ReceiptType.READ)) + } + + @Test + fun `invoke - sends private read receipt when public receipts are disabled`() = runTest { + val markAsReadResult = lambdaRecorder> { Result.success(Unit) } + val room = FakeBaseRoom(markAsReadResult = markAsReadResult) + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, room) + } + val sessionPreferencesStore = InMemorySessionPreferencesStore(isSendPublicReadReceiptsEnabled = false) + val markRoomAsRead = DefaultMarkRoomAsRead( + client = matrixClient, + notificationCleaner = FakeNotificationCleaner(clearMessagesForRoomLambda = { _, _ -> }), + sessionPreferencesStore = sessionPreferencesStore, + coroutineDispatchers = testCoroutineDispatchers(), + ) + + val result = markRoomAsRead(A_ROOM_ID) + runCurrent() + + assertThat(result.isSuccess).isTrue() + markAsReadResult.assertions().isCalledOnce().with(value(ReceiptType.READ_PRIVATE)) + } +} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileViewTest.kt index 20db955955..a9bce23e45 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/user/editprofile/EditUserProfileViewTest.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.ui.strings.CommonStrings @@ -26,11 +25,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class EditUserProfileViewTest { +class EditUserProfileViewTest : RobolectricTest() { @Test fun `clicking on back emits the expected event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/rageshake/api/src/main/res/values-be/translations.xml b/features/rageshake/api/src/main/res/values-be/translations.xml index 3d9eec29d2..f08697c71d 100644 --- a/features/rageshake/api/src/main/res/values-be/translations.xml +++ b/features/rageshake/api/src/main/res/values-be/translations.xml @@ -1,6 +1,6 @@ - "Пры апошнім выкарыстанні %1$s адбыўся збой. Хочаце падзяліцца справаздачай аб збоі?" + "Пры апошнім выкарыстанні %1$s адбыўся збой. Хочаце абагуліць справаздачу аб збоі?" "Падобна, што вы трасеце тэлефон. Хочаце адкрыць экран паведамлення пра памылку?" "Rageshake" "Парог выяўлення" diff --git a/features/rageshake/api/src/main/res/values-ru/translations.xml b/features/rageshake/api/src/main/res/values-ru/translations.xml index 8a3df584d7..c0448b7498 100644 --- a/features/rageshake/api/src/main/res/values-ru/translations.xml +++ b/features/rageshake/api/src/main/res/values-ru/translations.xml @@ -1,7 +1,7 @@ "При последнем использовании %1$s произошел сбой. Хотите отправить отчет?" - "Похоже, что вы трясете телефон. Хотите открыть экран сообщения об ошибке?" + "Похоже, что Вы трясете телефон в раздражении. Хотите открыть экран сообщения об ошибке?" "Встряхните" "Порог обнаружения" diff --git a/features/rageshake/impl/src/main/res/values-be/translations.xml b/features/rageshake/impl/src/main/res/values-be/translations.xml index f927ba3c5e..50f8bb6052 100644 --- a/features/rageshake/impl/src/main/res/values-be/translations.xml +++ b/features/rageshake/impl/src/main/res/values-be/translations.xml @@ -12,6 +12,6 @@ "Дазволіць журналы" "Адправіць здымак экрана" "Каб пераканацца, што ўсё працуе правільна, у паведамленне будуць уключаны часопісы. Каб адправіць паведамленне без часопісаў, адключыце гэтую наладу." - "Пры апошнім выкарыстанні %1$s адбыўся збой. Хочаце падзяліцца справаздачай аб збоі?" + "Пры апошнім выкарыстанні %1$s адбыўся збой. Хочаце абагуліць справаздачу аб збоі?" "Прагляд журналаў" diff --git a/features/rageshake/impl/src/main/res/values-et/translations.xml b/features/rageshake/impl/src/main/res/values-et/translations.xml index 2f55a9b6b5..1f61849fa5 100644 --- a/features/rageshake/impl/src/main/res/values-et/translations.xml +++ b/features/rageshake/impl/src/main/res/values-et/translations.xml @@ -8,6 +8,8 @@ "Palun kirjelda probleemi…" "Kui vähegi võimalik, siis kirjuta inglise keeles." "Kirjeldus on liiga lühike. Palun jaga täpsemat teavet selle kohta, mis juhtus. Tänud juba ette!" + "Võid sisestada seotud GitHubi veateate numbri, kui see on olemas." + "Veateade GitHubis" "Saada krahhilogid" "Luba logide saatmine" "Sinu logid on väga mahukad ja neid ei saa siia lisada. Palun saada logid meile mõnel muul viisil." diff --git a/features/rageshake/impl/src/main/res/values-fi/translations.xml b/features/rageshake/impl/src/main/res/values-fi/translations.xml index 1970d538fd..5590602367 100644 --- a/features/rageshake/impl/src/main/res/values-fi/translations.xml +++ b/features/rageshake/impl/src/main/res/values-fi/translations.xml @@ -8,6 +8,8 @@ "Kuvaile ongelmaasi…" "Jos mahdollista, kirjoita englanniksi." "Kuvaus on liian lyhyt. Kerro tarkemmin mitä tapahtui, kiitos!" + "Voit kirjoittaa mahdollisen GitHub-issuen numeron." + "GitHub-issue" "Lähetä kaatumislokit" "Lähetä lokitiedostot" "Lokitiedostosi ovat liian suuria, joten niitä ei voida sisällyttää tähän raporttiin. Lähetä ne meille toisella tavalla." diff --git a/features/rageshake/impl/src/main/res/values-fr/translations.xml b/features/rageshake/impl/src/main/res/values-fr/translations.xml index 6685903146..7f0e3c0e54 100644 --- a/features/rageshake/impl/src/main/res/values-fr/translations.xml +++ b/features/rageshake/impl/src/main/res/values-fr/translations.xml @@ -8,6 +8,8 @@ "Décrire le problème…" "Si possible, veuillez rédiger la description en anglais." "La description est trop courte, veuillez fournir plus de détails sur ce qui s’est passé. Merci !" + "Vous pouvez saisir le numéro d’un ticket GitHub associé, le cas échéant." + "Ticket GitHub" "Envoyer des journaux d’incident" "Autoriser à inclure les journaux techniques" "Vos fichiers de log sont trop volumineux et ne peuvent donc pas être inclus dans ce rapport, veuillez nous les envoyer par un autre moyen." diff --git a/features/rageshake/impl/src/main/res/values-hu/translations.xml b/features/rageshake/impl/src/main/res/values-hu/translations.xml index 851d3f0067..db665a1253 100644 --- a/features/rageshake/impl/src/main/res/values-hu/translations.xml +++ b/features/rageshake/impl/src/main/res/values-hu/translations.xml @@ -8,6 +8,8 @@ "Írja le a problémát…" "Ha lehetséges, a leírást angolul írja meg." "A leírás túl rövid, adjon meg további részleteket a történtekről. Köszönjük!" + "Megadhatja egy kapcsolódó GitHub-probléma számát, ha van ilyen." + "GitHub-jegy" "Összeomlásnaplók küldése" "Naplók engedélyezése" "A naplófájlok túl nagyok, ezért nem szerepelhetnek ebben a jelentésben. Más módon küldje el őket." diff --git a/features/rageshake/impl/src/main/res/values-ja/translations.xml b/features/rageshake/impl/src/main/res/values-ja/translations.xml index 7c46d2beb5..53d25b364f 100644 --- a/features/rageshake/impl/src/main/res/values-ja/translations.xml +++ b/features/rageshake/impl/src/main/res/values-ja/translations.xml @@ -8,6 +8,8 @@ "問題の説明…" "可能であれば英語で記入してください。" "説明が過度に短いです。問題についてより詳細にご記入ください。" + "関連したGitHubのissueがある場合はIDを記入してください。" + "GitHub issue" "クラッシュログを送信" "ログの記録を許可" "ログのサイズが大きく、報告に添付することができません。ログは別の方法で送信してください。" diff --git a/features/rageshake/impl/src/main/res/values-ko/translations.xml b/features/rageshake/impl/src/main/res/values-ko/translations.xml index ef4978924c..1b15ce3f5a 100644 --- a/features/rageshake/impl/src/main/res/values-ko/translations.xml +++ b/features/rageshake/impl/src/main/res/values-ko/translations.xml @@ -8,6 +8,8 @@ "문제를 설명해 주세요…" "가능하다면 영어로 설명을 작성해 주십시오." "설명 내용이 너무 짧습니다. 발생한 상황에 대해 더 자세한 내용을 제공해 주시기 바랍니다. 감사합니다!" + "연관된 GitHub 이슈 번호가 있다면 입력할 수 있습니다." + "GitHub 이슈" "충돌 로그 보내기" "로그 허용" "귀하의 로그가 너무 커서 이 보고서에 포함할 수 없습니다. 다른 방법으로 보내주시기 바랍니다." diff --git a/features/rageshake/impl/src/main/res/values-pl/translations.xml b/features/rageshake/impl/src/main/res/values-pl/translations.xml index c433071584..2b0feb0851 100644 --- a/features/rageshake/impl/src/main/res/values-pl/translations.xml +++ b/features/rageshake/impl/src/main/res/values-pl/translations.xml @@ -8,6 +8,8 @@ "Opisz problem…" "Jeśli to możliwe, napisz zgłoszenje w języku angielskim." "Opis jest zbyt krótki, podaj więcej szczegółów na temat tego co się stało. Dzięki!" + "Możesz wpisać numer powiązanego zgłoszenia w serwisie GitHub, jeśli takie istnieje." + "Zgłoszenie Github" "Wyślij logi awarii" "Zezwól na logi" "Twoje dzienniki są zbyt duże, więc nie można ich uwzględnić w tym raporcie. Prześlij je do nas w inny sposób." diff --git a/features/rageshake/impl/src/main/res/values-ru/translations.xml b/features/rageshake/impl/src/main/res/values-ru/translations.xml index d4224a6dcb..4934266798 100644 --- a/features/rageshake/impl/src/main/res/values-ru/translations.xml +++ b/features/rageshake/impl/src/main/res/values-ru/translations.xml @@ -8,13 +8,15 @@ "Опишите проблему…" "Если возможно, пожалуйста, напишите описание на английском языке." "Описание слишком короткое, пожалуйста, расскажите подробнее о том, что произошло. Спасибо!" + "При наличии, Вы можете ввести номер связанной проблемы из GitHub." + "Проблема на GitHub" "Отправка журналов сбоев" "Разрешить ведение журналов" "Ваши журналы слишком большие для включения в этот отчет. Пожалуйста, отправьте их нам другим способом." "Отправить скриншот" "Чтобы убедиться, что всё работает правильно, к сообщению будут прикреплены журналы. Чтобы отправить сообщение без журналов, отключите эту настройку." "При последнем использовании %1$s произошел сбой. Хотите отправить отчет?" - "Если у вас возникли проблемы с уведомлениями, загрузка настроек уведомлений может помочь нам определить основную причину." + "Если у Вас возникли проблемы с уведомлениями, загрузка настроек уведомлений может помочь нам определить причину проблемы. Обратите внимание, что эти правила могут содержать конфиденциальную информацию, такую ​​как Ваше отображаемое имя или ключевые слова, по которым должны срабатывать уведомления." "Настройки отправки уведомлений" "Просмотр журналов" diff --git a/features/rageshake/impl/src/main/res/values-uk/translations.xml b/features/rageshake/impl/src/main/res/values-uk/translations.xml index c29306b9bf..d42f6e5501 100644 --- a/features/rageshake/impl/src/main/res/values-uk/translations.xml +++ b/features/rageshake/impl/src/main/res/values-uk/translations.xml @@ -8,6 +8,8 @@ "Опишіть проблему…" "Якщо можливо, будь ласка, напишіть опис англійською мовою." "Опис закороткий, будь ласка, надайте докладнішу інформацію про те, що сталося. Дякуємо!" + "Ви можете ввести номер вже існуючої проблеми на GitHub, якщо така є." + "Тікет на GitHub" "Надіслати журнали збоїв" "Дозволити журнали" "Ваші журнали надмірно великі, тому їх не можна включити в цей звіт, будь ласка, надішліть їх нам іншим способом." diff --git a/features/rageshake/impl/src/main/res/values-zh/translations.xml b/features/rageshake/impl/src/main/res/values-zh/translations.xml index c42141d291..ea795037d1 100644 --- a/features/rageshake/impl/src/main/res/values-zh/translations.xml +++ b/features/rageshake/impl/src/main/res/values-zh/translations.xml @@ -8,6 +8,8 @@ "描述问题…" "请尽可能用英文描述。" "描述太短,请提供详细情况。谢谢!" + "你可以输入与之相关的 GitHub issue 编号(如果有)。" + "GitHub issue" "发送崩溃日志" "允许日志" "日志文件过大,无法包含在本次报告中,请通过其它方式发送给我们。" diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/VectorUncaughtExceptionHandlerTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/VectorUncaughtExceptionHandlerTest.kt index 665e1ce4bd..70abe99469 100644 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/VectorUncaughtExceptionHandlerTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/crash/VectorUncaughtExceptionHandlerTest.kt @@ -11,14 +11,12 @@ package io.element.android.features.rageshake.impl.crash import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.preferences.test.FakePreferenceDataStoreFactory +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class VectorUncaughtExceptionHandlerTest { +class VectorUncaughtExceptionHandlerTest : RobolectricTest() { @Test fun `activate should change the default handler`() { val sut = VectorUncaughtExceptionHandler(PreferencesCrashDataStore(FakePreferenceDataStoreFactory())) diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt index 6dd6f81e5f..4f666d374b 100755 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt @@ -32,6 +32,7 @@ import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.test.InMemorySessionStore import io.element.android.libraries.sessionstorage.test.aSessionData import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf @@ -46,12 +47,9 @@ import okhttp3.mockwebserver.RecordedRequest import okio.buffer import okio.source import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment -@RunWith(RobolectricTestRunner::class) -class DefaultBugReporterTest { +class DefaultBugReporterTest : RobolectricTest() { @Test fun `test sendBugReport success`() = runTest { val server = MockWebServer() diff --git a/features/reportroom/impl/src/main/res/values-ru/translations.xml b/features/reportroom/impl/src/main/res/values-ru/translations.xml index 24a46b5f3d..22ff15c1cd 100644 --- a/features/reportroom/impl/src/main/res/values-ru/translations.xml +++ b/features/reportroom/impl/src/main/res/values-ru/translations.xml @@ -1,6 +1,6 @@ - "Ваша жалоба была успешно отправлена, но мы столкнулись с проблемой при попытке покинуть комнату. Пожалуйста, попробуйте еще раз." + "Ваша жалоба была успешно отправлена, но мы столкнулись с проблемой при попытке покинуть комнату. Пожалуйста, попробуйте ещё раз." "Невозможно покинуть комнату" "Пожалуйтесь на комнату администратору. Если сообщения зашифрованы, ваш администратор не сможет их прочитать." "Опишите причину жалобы…" diff --git a/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomViewTest.kt b/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomViewTest.kt index a18c82b275..0e43cf6594 100644 --- a/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomViewTest.kt +++ b/features/reportroom/impl/src/test/kotlin/io/element/android/features/reportroom/impl/ReportRoomViewTest.kt @@ -16,18 +16,16 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ReportRoomViewTest { +class ReportRoomViewTest : RobolectricTest() { @Test fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsNode.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsNode.kt index da69ee52a9..050027bb1c 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsNode.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsNode.kt @@ -26,12 +26,8 @@ class RolesAndPermissionsNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: RolesAndPermissionsPresenter, -) : Node(buildContext, plugins = plugins), RolesAndPermissionsNavigator { +) : Node(buildContext, plugins = plugins) { interface Callback : Plugin, RolesAndPermissionsNavigator { - override fun openAdminList() - override fun openModeratorList() - override fun openEditPermissions() - override fun onBackClick() {} } @@ -56,8 +52,8 @@ class RolesAndPermissionsNode( } interface RolesAndPermissionsNavigator { - fun onBackClick() {} - fun openAdminList() {} - fun openModeratorList() {} - fun openEditPermissions() {} + fun onBackClick() + fun openAdminList() + fun openModeratorList() + fun openEditPermissions() } diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt index 2f8dab8029..07d2711cc6 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt @@ -12,7 +12,8 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -141,7 +142,10 @@ private fun ChangeOwnRoleBottomSheet( eventSink: (RolesAndPermissionsEvents) -> Unit, ) { val coroutineScope = rememberCoroutineScope() - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), + ) fun dismiss() { sheetState.hide(coroutineScope) { eventSink(RolesAndPermissionsEvents.CancelPendingAction) @@ -181,7 +185,6 @@ private fun ChangeOwnRoleBottomSheet( ListItem( headlineContent = { Text(stringResource(CommonStrings.action_cancel)) }, onClick = ::dismiss, - style = ListItemStyle.Primary, ) } } @@ -192,7 +195,12 @@ internal fun RolesAndPermissionsViewPreview(@PreviewParameter(RolesAndPermission ElementPreview { RolesAndPermissionsView( state = state, - rolesAndPermissionsNavigator = object : RolesAndPermissionsNavigator {}, + rolesAndPermissionsNavigator = object : RolesAndPermissionsNavigator { + override fun onBackClick() {} + override fun openAdminList() {} + override fun openModeratorList() {} + override fun openEditPermissions() {} + }, ) } } diff --git a/features/rolesandpermissions/impl/src/main/res/values-be/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-be/translations.xml index 44841d1207..4e4ff9bb58 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-be/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-be/translations.xml @@ -1,11 +1,12 @@ - "Толькі адміністратары" + "Адміністратар" "Заблакіраваць людзей" "Выдаліць паведамленні" - "Запрашайце людзей і прымайце запыты на далучэнне" + "Удзельнік" + "Запрасіць людзей" "Паведамленні і змест" - "Адміністратары і мадэратары" + "Мадэратар" "Выдаляйце людзей і адхіляйце запыты на далучэнне" "Змяніць аватар пакоя" "Рэдагаваць пакой" @@ -39,8 +40,8 @@ "Яны змогуць зноў далучыцца да гэтага пакоя, калі іх запросяць." "Заблакіраваныя" "Удзельнікі" - "Толькі адміністратары" - "Адміністратары і мадэратары" + "Адміністратар" + "Мадэратар" "Удзельнікі пакоя" "Разблакіроўка %1$s" "Адміністратары" diff --git a/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml index 7e5736bbed..677a4ba33b 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-fr/translations.xml @@ -6,6 +6,7 @@ "Supprimer des messages" "Membre" "Inviter des personnes" + "Partager la position en continu" "Gérer l’espace" "Gérer les salons" "Gérer les membres" diff --git a/features/rolesandpermissions/impl/src/main/res/values-ko/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-ko/translations.xml index 4ad64f1723..c9de19a43a 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-ko/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-ko/translations.xml @@ -6,6 +6,7 @@ "메시지 삭제" "멤버" "사람 초대하기" + "실시간 위치 공유" "스페이스 관리" "방 관리" "멤버 관리" diff --git a/features/rolesandpermissions/impl/src/main/res/values-ru/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-ru/translations.xml index 425da3e2ce..8ec7d7579c 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-ru/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-ru/translations.xml @@ -20,7 +20,7 @@ "Отправлять сообщения" "Разрешения" "Редактировать администраторов" - "Вы не сможете отменить это действие. Вы даете пользователю такой же уровень прав, как и у вас" + "Вы не сможете отменить это действие. Вы даете пользователю такой же уровень прав, как и у Вас" "Добавить администратора?" "Отменить данное действие будет невозможно. Права передадутся выбранным пользователям. После вашего выхода действие станет необратимым." "Передать владение?" @@ -36,7 +36,7 @@ "Администраторы" "Модераторы" "Участники" - "У вас есть несохраненные изменения." + "У Вас есть несохраненные изменения." "Сохранить изменения?" "В этой комнате нет заблокированных пользователей." diff --git a/features/rolesandpermissions/impl/src/main/res/values-uk/translations.xml b/features/rolesandpermissions/impl/src/main/res/values-uk/translations.xml index 99f21bb403..5690886c60 100644 --- a/features/rolesandpermissions/impl/src/main/res/values-uk/translations.xml +++ b/features/rolesandpermissions/impl/src/main/res/values-uk/translations.xml @@ -6,6 +6,7 @@ "Вилучати повідомлення" "Учасник" "Запрошувати людей" + "Ділитися місцезнаходженням у реальному часі" "Керувати простором" "Керувати кімнатами" "Керувати учасниками" diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/permissions/ChangeRoomPermissionsViewTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/permissions/ChangeRoomPermissionsViewTest.kt index 668c6bb221..57307706e0 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/permissions/ChangeRoomPermissionsViewTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/permissions/ChangeRoomPermissionsViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.rolesandpermissions.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.ui.strings.CommonStrings @@ -24,13 +23,12 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentMapOf import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ChangeRoomPermissionsViewTest { +class ChangeRoomPermissionsViewTest : RobolectricTest() { @Test fun `click on back icon invokes Exit`() = runAndroidComposeUiTest { val recorder = EventsRecorder() diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt index 62d0608f26..dfc2b88e25 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.extensions.runCatchingExceptions @@ -32,13 +31,12 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.toImmutableList import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class ChangeRolesViewTest { +class ChangeRolesViewTest : RobolectricTest() { @Test fun `passing a 'User' role throws an exception`() = runAndroidComposeUiTest { val exception = runCatchingExceptions { diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/DefaultChangeRoomMemberRolesEntyPointTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/DefaultChangeRoomMemberRolesEntyPointTest.kt index 7d190b85f4..8add944927 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/DefaultChangeRoomMemberRolesEntyPointTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/DefaultChangeRoomMemberRolesEntyPointTest.kt @@ -8,18 +8,16 @@ package io.element.android.features.rolesandpermissions.impl.roles -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.bumble.appyx.core.modality.BuildContext import com.google.common.truth.Truth.assertThat import io.element.android.features.rolesandpermissions.api.ChangeRoomMemberRolesListType import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.tests.testutils.node.TestParentNode +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultChangeRoomMemberRolesEntyPointTest { +class DefaultChangeRoomMemberRolesEntyPointTest : RobolectricTest() { @Test fun `test node builder`() = runTest { val entryPoint = DefaultChangeRoomMemberRolesEntyPoint() diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsViewTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsViewTest.kt index d8908c405d..8a3b6fd766 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsViewTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.rolesandpermissions.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.room.RoomMember @@ -25,13 +24,12 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledTimes import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class RolesAndPermissionsViewTest { +class RolesAndPermissionsViewTest : RobolectricTest() { @Test fun `click on back invokes expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperViewTest.kt b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperViewTest.kt index 5f871183d6..ae33517732 100644 --- a/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperViewTest.kt +++ b/features/roomaliasresolver/impl/src/test/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasHelperViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.ui.strings.CommonStrings @@ -25,11 +24,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class RoomAliasHelperViewTest { +class RoomAliasHelperViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index d4108a77e3..7574863962 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -258,6 +258,10 @@ class RoomDetailsFlowNode( override fun navigateToInviteMembers() { backstack.push(NavTarget.InviteMembers) } + + override fun navigateToAvatarPreview(username: String, avatarUrl: String) { + overlay.show(NavTarget.AvatarPreview(username, avatarUrl)) + } } createNode(buildContext, listOf(roomMemberListCallback)) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index e6617d1dd5..9a602d06c0 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -38,6 +38,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDis import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -117,7 +118,7 @@ class RoomDetailsPresenter( val canonicalAlias by remember { derivedStateOf { roomInfo.canonicalAlias } } val isEncrypted by remember { derivedStateOf { roomInfo.isEncrypted == true } } val dmMember by room.getDirectRoomMember(membersState) - val roomMemberDetailsPresenter = roomMemberDetailsPresenter(dmMember) + val roomMemberDetailsPresenter = roomMemberDetailsPresenter(dmMember?.userId) val roomType = getRoomType(dmMember) val roomCallState = roomCallStatePresenter.present() val joinedMemberCount by remember { derivedStateOf { roomInfo.joinedMembersCount } } @@ -174,7 +175,7 @@ class RoomDetailsPresenter( } } - val roomMemberDetailsState = roomMemberDetailsPresenter?.present() + val dmOtherMemberDetailsState = roomMemberDetailsPresenter?.present() val hasMemberVerificationViolations by produceState(false) { room.roomMemberIdentityStateChange(waitForEncryption = true) @@ -196,7 +197,7 @@ class RoomDetailsPresenter( canEdit = roomType == RoomDetailsType.Room && permissions.editDetailsPermissions.hasAny, roomCallState = roomCallState, roomType = roomType, - roomMemberDetailsState = roomMemberDetailsState, + dmOtherMemberDetailsState = dmOtherMemberDetailsState, leaveRoomState = leaveRoomState, roomNotificationSettings = roomNotificationSettingsState.roomNotificationSettings(), isFavorite = isFavorite, @@ -209,7 +210,7 @@ class RoomDetailsPresenter( knockRequestsCount = knockRequestsCount, canShowSecurityAndPrivacy = canShowSecurityAndPrivacy, hasMemberVerificationViolations = hasMemberVerificationViolations, - canReportRoom = canReportRoom, + canReportRoom = !isDm && canReportRoom, isTombstoned = roomInfo.successorRoom != null, showDebugInfo = isDeveloperModeEnabled, roomVersion = roomInfo.roomVersion, @@ -220,9 +221,9 @@ class RoomDetailsPresenter( } @Composable - private fun roomMemberDetailsPresenter(dmMemberState: RoomMember?) = remember(dmMemberState) { - dmMemberState?.let { roomMember -> - roomMembersDetailsPresenterFactory.create(roomMember.userId) + private fun roomMemberDetailsPresenter(userId: UserId?) = remember(userId) { + userId?.let { userId -> + roomMembersDetailsPresenterFactory.create(userId) } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt index bd3b90d416..4464058701 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt @@ -31,7 +31,7 @@ data class RoomDetailsState( val memberCount: Long, val isEncrypted: Boolean, val roomType: RoomDetailsType, - val roomMemberDetailsState: UserProfileState?, + val dmOtherMemberDetailsState: UserProfileState?, val canEdit: Boolean, val canInvite: Boolean, val roomCallState: RoomCallState, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt index 7182d2ec04..935b7293ae 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt @@ -106,7 +106,7 @@ fun aRoomDetailsState( canEdit: Boolean = false, roomCallState: RoomCallState = aStandByCallState(), roomType: RoomDetailsType = RoomDetailsType.Room, - roomMemberDetailsState: UserProfileState? = null, + dmOtherMemberDetailsState: UserProfileState? = null, leaveRoomState: LeaveRoomState = aLeaveRoomState(), roomNotificationSettings: RoomNotificationSettings = aRoomNotificationSettings(), isFavorite: Boolean = false, @@ -137,7 +137,7 @@ fun aRoomDetailsState( canEdit = canEdit, roomCallState = roomCallState, roomType = roomType, - roomMemberDetailsState = roomMemberDetailsState, + dmOtherMemberDetailsState = dmOtherMemberDetailsState, leaveRoomState = leaveRoomState, roomNotificationSettings = roomNotificationSettings, isFavorite = isFavorite, @@ -184,7 +184,7 @@ fun aDmRoomDetailsState( isEncrypted = isEncrypted, canInvite = true, roomType = RoomDetailsType.Dm(otherMember = aDmRoomMember(isIgnored = isDmMemberIgnored)), - roomMemberDetailsState = aUserProfileState( + dmOtherMemberDetailsState = aUserProfileState( isBlocked = AsyncData.Success(isDmMemberIgnored), verificationState = dmRoomMemberVerificationState, ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index 40210279fa..591ff7ff1e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -43,6 +43,7 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.roomcall.api.hasPermissionToJoin +import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState import io.element.android.features.userprofile.shared.blockuser.BlockUserDialogs import io.element.android.features.userprofile.shared.blockuser.BlockUserSection @@ -64,7 +65,7 @@ import io.element.android.libraries.designsystem.modifiers.niceClickable import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight -import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight +import io.element.android.libraries.designsystem.preview.PreviewWithExtraLargeHeight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.DropdownMenu import io.element.android.libraries.designsystem.theme.components.DropdownMenuItem @@ -96,6 +97,9 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +/** + * Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=21-120385 + */ @Composable fun RoomDetailsView( state: RoomDetailsState, @@ -229,66 +233,11 @@ fun RoomDetailsView( ) } } + // Room content PreferenceCategory { - if (state.roomNotificationSettings != null) { - NotificationItem( - isDefaultMode = state.roomNotificationSettings.isDefault, - openRoomNotificationSettings = openRoomNotificationSettings - ) - } - - FavoriteItem( - isFavorite = state.isFavorite, - onFavoriteChanges = { - state.eventSink(RoomDetailsEvent.SetFavorite(it)) - } + MediaGalleryItem( + onClick = openMediaGallery ) - - if (state.canShowSecurityAndPrivacy) { - SecurityAndPrivacyItem( - onClick = onSecurityAndPrivacyClick - ) - } - } - - state.roomMemberDetailsState?.let { dmMemberDetails -> - if (state.canInvite) { - PreferenceCategory { - InviteItem(onClick = invitePeople) - } - } - PreferenceCategory { - ProfileItem( - verificationState = dmMemberDetails.verificationState, - onClick = { onProfileClick(dmMemberDetails.userId) } - ) - } - } - - if (state.roomType is RoomDetailsType.Room) { - PreferenceCategory { - MembersItem( - memberCount = state.memberCount, - hasVerificationViolations = state.hasMemberVerificationViolations, - openRoomMemberList = openRoomMemberList, - ) - if (state.canShowKnockRequests) { - KnockRequestsItem( - knockRequestsCount = state.knockRequestsCount, - onKnockRequestsClick = onKnockRequestsClick - ) - } - if (state.displayRolesAndPermissionsSettings) { - ListItem( - headlineContent = { Text(stringResource(R.string.screen_room_details_roles_and_permissions)) }, - leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Admin())), - onClick = openAdminSettings, - ) - } - } - } - - PreferenceCategory { PinnedMessagesItem( pinnedMessagesCount = state.pinnedMessagesCount, onPinnedMessagesClick = onPinnedMessagesClick @@ -296,23 +245,87 @@ fun RoomDetailsView( PollsItem( openPollHistory = openPollHistory ) - MediaGalleryItem( - onClick = openMediaGallery + } + when (state.roomType) { + is RoomDetailsType.Room -> { + PreferenceCategory { + MembersItem( + memberCount = state.memberCount, + hasVerificationViolations = state.hasMemberVerificationViolations, + openRoomMemberList = openRoomMemberList, + ) + if (state.canShowKnockRequests) { + KnockRequestsItem( + knockRequestsCount = state.knockRequestsCount, + onKnockRequestsClick = onKnockRequestsClick + ) + } + if (state.displayRolesAndPermissionsSettings) { + ListItem( + headlineContent = { Text(stringResource(R.string.screen_room_details_roles_and_permissions)) }, + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Admin())), + onClick = openAdminSettings, + ) + } + } + } + is RoomDetailsType.Dm -> { + if (state.canInvite) { + // Note: for rooms the invite action is a Main action + PreferenceCategory { + InviteItem(onClick = invitePeople) + } + } + state.dmOtherMemberDetailsState?.let { dmMemberDetails -> + PreferenceCategory { + ProfileItem( + verificationState = dmMemberDetails.verificationState, + onClick = { onProfileClick(dmMemberDetails.userId) } + ) + } + } + } + } + PreferenceCategory { + if (state.roomNotificationSettings != null) { + NotificationItem( + isDefaultMode = state.roomNotificationSettings.isDefault, + openRoomNotificationSettings = openRoomNotificationSettings + ) + } + FavoriteItem( + isFavorite = state.isFavorite, + onFavoriteChanges = { + state.eventSink(RoomDetailsEvent.SetFavorite(it)) + } ) + if (state.canShowSecurityAndPrivacy && state.roomType is RoomDetailsType.Room) { + SecurityAndPrivacyItem( + onClick = onSecurityAndPrivacyClick + ) + } } - - if (state.roomType is RoomDetailsType.Dm && state.roomMemberDetailsState != null) { - val roomMemberState = state.roomMemberDetailsState - BlockUserSection(roomMemberState) - BlockUserDialogs(roomMemberState) + if (state.isEncrypted) { + PreferenceCategory( + title = stringResource(R.string.screen_room_details_security_title) + ) { + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Lock())), + headlineContent = { + Text(stringResource(id = R.string.screen_room_details_encryption_enabled_title)) + }, + supportingContent = { + Text(stringResource(id = R.string.screen_room_details_encryption_enabled_subtitle)) + }, + ) + } } - OtherActionsSection( + dmOtherMemberDetailsState = state.dmOtherMemberDetailsState, canReportRoom = state.canReportRoom, onReportRoomClick = onReportRoomClick, onLeaveRoomClick = { state.eventSink(RoomDetailsEvent.LeaveRoom(needsConfirmation = true)) } ) - if (state.showDebugInfo) { DebugInfoSection( roomId = state.roomId, @@ -803,8 +816,13 @@ private fun OtherActionsSection( canReportRoom: Boolean, onReportRoomClick: () -> Unit, onLeaveRoomClick: () -> Unit, + dmOtherMemberDetailsState: UserProfileState?, ) { - PreferenceCategory(showTopDivider = true) { + PreferenceCategory { + if (dmOtherMemberDetailsState != null) { + BlockUserSection(dmOtherMemberDetailsState) + BlockUserDialogs(dmOtherMemberDetailsState) + } if (canReportRoom) { ListItem( headlineContent = { @@ -832,7 +850,7 @@ private fun DebugInfoSection( roomVersion: String?, ) { val context = LocalContext.current - PreferenceCategory(showTopDivider = true) { + PreferenceCategory { val toastMessage = stringResource(CommonStrings.common_copied_to_clipboard) ListItem( headlineContent = { @@ -870,17 +888,17 @@ private fun DebugInfoSection( } } -@PreviewWithLargeHeight +@PreviewWithExtraLargeHeight @Composable internal fun RoomDetailsPreview(@PreviewParameter(RoomDetailsStateProvider::class) state: RoomDetailsState) = ElementPreviewLight { ContentToPreview(state) } -@PreviewWithLargeHeight +@PreviewWithExtraLargeHeight @Composable internal fun RoomDetailsDarkPreview(@PreviewParameter(RoomDetailsStateProvider::class) state: RoomDetailsState) = ElementPreviewDark { ContentToPreview(state) } -@PreviewWithLargeHeight +@PreviewWithExtraLargeHeight @Composable internal fun RoomDetailsA11yPreview() = ElementPreview { ContentToPreview( diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListNode.kt index 750b111fc3..37f107e784 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListNode.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.architecture.appyx.launchMolecule import io.element.android.libraries.architecture.callback import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.services.analytics.api.AnalyticsService @ContributesNode(RoomScope::class) @@ -41,6 +42,7 @@ class RoomMemberListNode( interface Callback : Plugin { fun navigateToRoomMemberDetails(roomMemberId: UserId) fun navigateToInviteMembers() + fun navigateToAvatarPreview(username: String, avatarUrl: String) } private val callback: Callback = callback() @@ -82,13 +84,18 @@ class RoomMemberListNode( else -> state.moderationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target)) } }, + onAvatarClick = { user -> + user.avatarUrl?.let { url -> + callback.navigateToAvatarPreview(user.getBestName(), url) + } + }, modifier = Modifier, ) } } interface RoomMemberListNavigator { - fun exitRoomMemberList() {} - fun openRoomMemberDetails(roomMemberId: UserId) {} - fun openInviteMembers() {} + fun exitRoomMemberList() + fun openRoomMemberDetails(roomMemberId: UserId) + fun openInviteMembers() } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt index 146d2f7952..0e6f5b6c88 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt @@ -50,6 +50,7 @@ import io.element.android.libraries.designsystem.theme.components.SegmentedButto import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.getBestName @@ -355,6 +356,10 @@ private fun RoomMemberListTopBar( internal fun RoomMemberListViewPreview(@PreviewParameter(RoomMemberListStateProvider::class) state: RoomMemberListState) = ElementPreview { RoomMemberListView( state = state, - navigator = object : RoomMemberListNavigator {}, + navigator = object : RoomMemberListNavigator { + override fun exitRoomMemberList() {} + override fun openRoomMemberDetails(roomMemberId: UserId) {} + override fun openInviteMembers() {} + }, ) } diff --git a/features/roomdetails/impl/src/main/res/values-be/translations.xml b/features/roomdetails/impl/src/main/res/values-be/translations.xml index 69c5be0021..2b0b59e359 100644 --- a/features/roomdetails/impl/src/main/res/values-be/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-be/translations.xml @@ -1,14 +1,16 @@ + "Рэдагаваць адрас" "Пры абнаўленні налад апавяшчэнняў адбылася памылка." "Ваш хатні сервер не падтрымлівае гэтую опцыю ў зашыфраваных пакоях, вы можаце не атрымаць апавяшчэнне ў некаторых пакоях." "Апытанні" - "Толькі адміністратары" + "Адміністратар" "Заблакіраваць людзей" "Выдаліць паведамленні" - "Запрашайце людзей і прымайце запыты на далучэнне" + "Удзельнік" + "Запрасіць людзей" "Паведамленні і змест" - "Адміністратары і мадэратары" + "Мадэратар" "Выдаляйце людзей і адхіляйце запыты на далучэнне" "Змяніць аватар пакоя" "Рэдагаваць пакой" @@ -52,8 +54,9 @@ "Замацаваныя паведамленні" "Профіль" "Ролі і дазволы" + "Імя" "Бяспека" - "Падзяліцца пакоем" + "Абагуліць пакой" "Інфармацыя аб пакоі" "Тэма" "Ідзе абнаўленне пакоя…" @@ -69,8 +72,8 @@ "Яны змогуць зноў далучыцца да гэтага пакоя, калі іх запросяць." "Заблакіраваныя" "Удзельнікі" - "Толькі адміністратары" - "Адміністратары і мадэратары" + "Адміністратар" + "Мадэратар" "Удзельнікі пакоя" "Разблакіроўка %1$s" "Дазволіць уласную наладу" @@ -102,4 +105,5 @@ "Ролі і дазволы" "Пазначыць як прачытанае" "Пазначыць як непрачытанае" + "Адрас" diff --git a/features/roomdetails/impl/src/main/res/values-pl/translations.xml b/features/roomdetails/impl/src/main/res/values-pl/translations.xml index 2979fcacdf..b79d3014e5 100644 --- a/features/roomdetails/impl/src/main/res/values-pl/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pl/translations.xml @@ -48,7 +48,7 @@ "Edytuj szczegóły" "Wystąpił nieznany błąd i nie można było zmienić informacji." "Nie można zaktualizować pokoju" - "Wiadomości są zabezpieczone kłódkami. Tylko Ty i odbiorcy macie unikalne klucze do ich odblokowania." + "Wiadomości są zabezpieczone kłódkami. Tylko Ty i Twoi odbiorcy posiadacie klucze do ich otwarcia." "Szyfrowanie wiadomości włączone" "Wystąpił błąd podczas ładowania ustawień powiadomień." "Wyciszenie tego pokoju nie powiodło się, spróbuj ponownie." diff --git a/features/roomdetails/impl/src/main/res/values-ru/translations.xml b/features/roomdetails/impl/src/main/res/values-ru/translations.xml index bb36b3b23b..ebe1448aa9 100644 --- a/features/roomdetails/impl/src/main/res/values-ru/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ru/translations.xml @@ -6,7 +6,7 @@ "Необходимо задать адрес комнаты, чтобы опубликовать ее в каталоге комнат." "Редактировать адрес комнаты" "Произошла ошибка при обновлении настройки уведомления." - "Ваш сервер не поддерживает эту опцию для зашифрованных комнат, вы можете не получать некоторые уведомления." + "Ваш сервер не поддерживает эту опцию для зашифрованных комнат, Вы можете не получать некоторые уведомления." "Опросы" "Администраторы" "Блокировать пользователей" @@ -23,7 +23,7 @@ "Менять тему комнаты" "Отправлять сообщения" "Редактировать администраторов" - "Вы не сможете отменить это действие. Вы даете пользователю такой же уровень прав, как и у вас" + "Вы не сможете отменить это действие. Вы даете пользователю такой же уровень прав, как и у Вас" "Добавить администратора?" "Отменить данное действие будет невозможно. Права передадутся выбранным пользователям. После вашего выхода действие станет необратимым." "Передать владение?" @@ -39,7 +39,7 @@ "Администраторы" "Модераторы" "Участники" - "У вас есть несохраненные изменения." + "У Вас есть несохраненные изменения." "Сохранить изменения?" "Добавить тему" "Зашифровано" @@ -51,8 +51,8 @@ "Сообщения зашифрованы. Только вы и ваши собеседники имеют доступ к сообщениям." "Шифрование сообщений включено" "Произошла ошибка при загрузке настроек уведомлений." - "Не удалось отключить звук в этой комнате, попробуйте еще раз." - "Не удалось включить звук в эту комнату, попробуйте еще раз." + "Не удалось отключить звук в этой комнате, попробуйте ещё раз." + "Не удалось включить звук в этой комнате, попробуйте ещё раз." "Не закрывайте приложение, пока не закончите." "Подготовка приглашений…" "Пригласить в комнату" @@ -63,7 +63,7 @@ "Пользовательские" "По умолчанию" "Уведомления" - "Закрепленные сообщения" + "Закреплённые сообщения" "Профиль" "Запросы на вступление" "Роли и разрешения" @@ -113,8 +113,8 @@ "Настройка по умолчанию" "Удалить пользовательскую настройку" "Произошла ошибка при загрузке настроек уведомлений." - "Не удалось восстановить режим по умолчанию, попробуйте еще раз." - "Не удалось настроить режим, попробуйте еще раз." + "Не удалось восстановить режим по умолчанию, попробуйте ещё раз." + "Не удалось настроить режим, попробуйте ещё раз." "Ваш домашний сервер не поддерживает эту опцию в зашифрованных комнатах, вы не будете получать уведомления в этой комнате." "О всех сообщениях" "Только упоминания и ключевые слова" @@ -153,7 +153,7 @@ "Любой желающий может присоединиться" "Кто угодно" "Выберите, участники каких пространств могут присоединиться к этой комнате без приглашения.%1$s" - "Управление пространством" + "Управление пространствами" "Присоединиться могут только приглашенные люди." "Только по приглашению" "Доступ" diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsViewTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsViewTest.kt index 9494df5d44..767ddd5dd9 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsViewTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsViewTest.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.userprofile.shared.aUserProfileState import io.element.android.libraries.matrix.api.core.UserId @@ -37,12 +36,11 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class RoomDetailsViewTest { +class RoomDetailsViewTest : RobolectricTest() { @Test fun `click on back invokes expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> @@ -334,7 +332,8 @@ class RoomDetailsViewTest { setRoomDetailView( state = aRoomDetailsState( eventSink = EventsRecorder(expectEvents = false), - roomMemberDetailsState = aUserProfileState(userId = A_USER_ID), + roomType = RoomDetailsType.Dm(aDmRoomMember(userId = A_USER_ID)), + dmOtherMemberDetailsState = aUserProfileState(userId = A_USER_ID), ), onProfileClick = callback, ) @@ -352,7 +351,7 @@ class RoomDetailsViewTest { roomType = RoomDetailsType.Dm( aDmRoomMember(userId = UserId("@other:local.org")), ), - roomMemberDetailsState = aUserProfileState(userId = A_USER_ID), + dmOtherMemberDetailsState = aUserProfileState(userId = A_USER_ID), canInvite = true, ), invitePeople = callback, diff --git a/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditViewTest.kt b/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditViewTest.kt index 686794d641..dab0381232 100644 --- a/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditViewTest.kt +++ b/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditViewTest.kt @@ -20,7 +20,6 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.testtags.TestTags @@ -30,12 +29,11 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Ignore import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class RoomDetailsEditViewTest { +class RoomDetailsEditViewTest : RobolectricTest() { @Test fun `clicking on back emits the expected Event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt index f9d60f87da..b3b935596f 100644 --- a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt +++ b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt @@ -18,18 +18,16 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.roomdirectory.api.RoomDescription import io.element.android.libraries.testtags.TestTags import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.ensureCalledOnceWithParam +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class RoomDirectoryViewTest { +class RoomDirectoryViewTest : RobolectricTest() { @Test fun `typing text in search field emits the expected Event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationRenderer.kt b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationRenderer.kt index 8fb1ae0c03..efc87d8a40 100644 --- a/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationRenderer.kt +++ b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationRenderer.kt @@ -17,6 +17,7 @@ interface RoomMemberModerationRenderer { fun Render( state: RoomMemberModerationState, onSelectAction: (ModerationAction, MatrixUser) -> Unit, + onAvatarClick: ((MatrixUser) -> Unit)?, modifier: Modifier, ) } diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/DefaultRoomMemberModerationRenderer.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/DefaultRoomMemberModerationRenderer.kt index 05bf00c7eb..0eeded6434 100644 --- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/DefaultRoomMemberModerationRenderer.kt +++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/DefaultRoomMemberModerationRenderer.kt @@ -25,10 +25,11 @@ class DefaultRoomMemberModerationRenderer : RoomMemberModerationRenderer { override fun Render( state: RoomMemberModerationState, onSelectAction: (ModerationAction, MatrixUser) -> Unit, + onAvatarClick: ((MatrixUser) -> Unit)?, modifier: Modifier ) { if (state is InternalRoomMemberModerationState) { - RoomMemberModerationView(state, onSelectAction, modifier) + RoomMemberModerationView(modifier = modifier, state = state, onSelectAction = onSelectAction, onAvatarClick = onAvatarClick) } else { SideEffect { Timber.d("RoomMemberModerationRenderer: Render called with unsupported state: $state") diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt index 53bf667c6e..410c573e4d 100644 --- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt +++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn @@ -21,7 +22,8 @@ import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope @@ -64,6 +66,7 @@ import timber.log.Timber fun RoomMemberModerationView( state: InternalRoomMemberModerationState, onSelectAction: (ModerationAction, MatrixUser) -> Unit, + onAvatarClick: ((MatrixUser) -> Unit)?, modifier: Modifier = Modifier, ) { Box(modifier = modifier) { @@ -73,6 +76,7 @@ fun RoomMemberModerationView( user = selectedUser, actions = state.actions, onSelectAction = onSelectAction, + onAvatarClick = onAvatarClick, onDismiss = { state.eventSink(InternalRoomMemberModerationEvents.Reset) }, ) } @@ -214,10 +218,14 @@ private fun RoomMemberActionsBottomSheet( user: MatrixUser, actions: ImmutableList, onSelectAction: (ModerationAction, MatrixUser) -> Unit, + onAvatarClick: ((MatrixUser) -> Unit)? = null, onDismiss: () -> Unit, ) { val coroutineScope = rememberCoroutineScope() - val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val bottomSheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), + ) ModalBottomSheet( modifier = Modifier.systemBarsPadding(), sheetState = bottomSheetState, @@ -240,10 +248,11 @@ private fun RoomMemberActionsBottomSheet( modifier = Modifier .padding(bottom = 24.dp) .align(Alignment.CenterHorizontally) - .clickable { + .clickable(enabled = user.avatarUrl != null && onAvatarClick != null) { coroutineScope.launch { - onSelectAction(ModerationAction.DisplayProfile, user) bottomSheetState.hide() + onAvatarClick?.invoke(user) + onDismiss() } } ) @@ -278,13 +287,12 @@ private fun RoomMemberActionsBottomSheet( when (val action = actionState.action) { is ModerationAction.DisplayProfile -> { ListItem( - style = ListItemStyle.Primary, headlineContent = { Text(stringResource(R.string.screen_bottom_sheet_manage_room_member_member_user_info)) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.UserProfile())), onClick = { coroutineScope.launch { - onSelectAction(action, user) bottomSheetState.hide() + onSelectAction(action, user) } }, enabled = actionState.isEnabled @@ -341,16 +349,18 @@ private fun RoomMemberActionsBottomSheet( @PreviewsDayNight @Composable internal fun RoomMemberModerationViewPreview(@PreviewParameter(InternalRoomMemberModerationStateProvider::class) state: InternalRoomMemberModerationState) { + val isDoingAction = listOf(state.kickUserAsyncAction, state.banUserAsyncAction, state.unbanUserAsyncAction).any { it is AsyncAction.Loading } + val modifier = if (isDoingAction) { + Modifier.fillMaxWidth().heightIn(min = 64.dp) + } else { + Modifier.fillMaxSize() + } ElementPreview { - Box( - modifier = Modifier - .fillMaxWidth() - .heightIn(min = 64.dp) - ) { + Box(modifier) { RoomMemberModerationView( state = state, - onSelectAction = { _, _ -> - }, + onSelectAction = { _, _ -> }, + onAvatarClick = {}, ) } } diff --git a/features/roommembermoderation/impl/src/main/res/values-be/translations.xml b/features/roommembermoderation/impl/src/main/res/values-be/translations.xml index b4b1f35f18..d6d5fc1b8e 100644 --- a/features/roommembermoderation/impl/src/main/res/values-be/translations.xml +++ b/features/roommembermoderation/impl/src/main/res/values-be/translations.xml @@ -7,7 +7,7 @@ "Блакіроўка %1$s" "Яны змогуць зноў далучыцца да гэтага пакоя, калі іх запросяць." "Прагляд профілю" - "Выдаліць удзельніка з пакоя" + "Выдаліць удзельніка" "Выдаліць удзельніка і забараніць далучацца ў будучыні?" "Выдаленне %1$s…" "Разблакіраваць" diff --git a/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationViewTest.kt b/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationViewTest.kt index 646481715a..f99e517767 100644 --- a/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationViewTest.kt +++ b/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationViewTest.kt @@ -14,24 +14,23 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.roommembermoderation.api.ModerationAction import io.element.android.features.roommembermoderation.api.ModerationActionState import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.testtags.TestTags +import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnceWithTwoParams import io.element.android.tests.testutils.pressTag +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class RoomMemberModerationViewTest { +class RoomMemberModerationViewTest : RobolectricTest() { @Test fun `clicking on display profile action calls onSelectAction`() = runAndroidComposeUiTest { val user = anAlice() @@ -48,6 +47,8 @@ class RoomMemberModerationViewTest { onSelectAction = callback ) clickOn(R.string.screen_bottom_sheet_manage_room_member_member_user_info) + // Gives time for bottomsheet to hide + mainClock.advanceTimeBy(1_000) } } @@ -217,11 +218,13 @@ class RoomMemberModerationViewTest { private fun AndroidComposeUiTest.setRoomMemberModerationView( state: InternalRoomMemberModerationState, onSelectAction: (ModerationAction, MatrixUser) -> Unit = EnsureNeverCalledWithTwoParams(), + onAvatarClick: ((MatrixUser) -> Unit)? = EnsureNeverCalledWithParam(), ) { setSafeContent { RoomMemberModerationView( state = state, onSelectAction = onSelectAction, + onAvatarClick = onAvatarClick, ) } } diff --git a/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupSetupEntryPoint.kt b/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupSetupEntryPoint.kt new file mode 100644 index 0000000000..f674dac690 --- /dev/null +++ b/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupSetupEntryPoint.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.securebackup.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import io.element.android.libraries.architecture.FeatureEntryPoint +import io.element.android.libraries.architecture.NodeInputs + +interface SecureBackupSetupEntryPoint : FeatureEntryPoint { + data class Inputs(val isChangeRecoveryKeyUserStory: Boolean) : NodeInputs + + fun createNode( + parentNode: Node, + buildContext: BuildContext, + inputs: Inputs, + ): Node +} diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPoint.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPoint.kt new file mode 100644 index 0000000000..29465b1be1 --- /dev/null +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPoint.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.securebackup.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.securebackup.api.SecureBackupSetupEntryPoint +import io.element.android.features.securebackup.impl.setup.SecureBackupSetupNode +import io.element.android.libraries.architecture.createNode + +@ContributesBinding(AppScope::class) +class DefaultSecureBackupSetupEntryPoint : SecureBackupSetupEntryPoint { + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + inputs: SecureBackupSetupEntryPoint.Inputs, + ): Node { + return parentNode.createNode( + buildContext = buildContext, + plugins = listOf( + SecureBackupSetupNode.Inputs( + isChangeRecoveryKeyUserStory = inputs.isChangeRecoveryKeyUserStory, + ) + ), + ) + } +} diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt index d9fd8a1785..035e47d1c7 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt @@ -21,11 +21,11 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.features.securebackup.api.SecureBackupEntryPoint +import io.element.android.features.securebackup.api.SecureBackupSetupEntryPoint import io.element.android.features.securebackup.impl.disable.SecureBackupDisableNode import io.element.android.features.securebackup.impl.enter.SecureBackupEnterRecoveryKeyNode import io.element.android.features.securebackup.impl.reset.ResetIdentityFlowNode import io.element.android.features.securebackup.impl.root.SecureBackupRootNode -import io.element.android.features.securebackup.impl.setup.SecureBackupSetupNode import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.appyx.canPop @@ -39,6 +39,7 @@ import kotlinx.parcelize.Parcelize class SecureBackupFlowNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, + private val secureBackupSetupEntryPoint: SecureBackupSetupEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = when (plugins.filterIsInstance().first().initialElement) { @@ -97,16 +98,18 @@ class SecureBackupFlowNode( createNode(buildContext, listOf(callback)) } NavTarget.Setup -> { - val inputs = SecureBackupSetupNode.Inputs( - isChangeRecoveryKeyUserStory = false, + secureBackupSetupEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + inputs = SecureBackupSetupEntryPoint.Inputs(isChangeRecoveryKeyUserStory = false), ) - createNode(buildContext, listOf(inputs)) } NavTarget.Change -> { - val inputs = SecureBackupSetupNode.Inputs( - isChangeRecoveryKeyUserStory = true, + secureBackupSetupEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + inputs = SecureBackupSetupEntryPoint.Inputs(isChangeRecoveryKeyUserStory = true), ) - createNode(buildContext, listOf(inputs)) } NavTarget.Disable -> { createNode(buildContext) diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyView.kt index 8b2bc4dc90..34fca33e96 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyView.kt @@ -9,22 +9,10 @@ package io.element.android.features.securebackup.impl.enter import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.isImeVisible import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.relocation.BringIntoViewRequester -import androidx.compose.foundation.relocation.bringIntoViewRequester import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -34,13 +22,11 @@ import io.element.android.features.securebackup.impl.setup.views.RecoveryKeyView import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.components.async.AsyncActionView +import io.element.android.libraries.designsystem.modifiers.bringIntoViewOnImeVisible import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.ui.strings.CommonStrings -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlin.time.Duration.Companion.milliseconds @Composable fun SecureBackupEnterRecoveryKeyView( @@ -71,29 +57,13 @@ fun SecureBackupEnterRecoveryKeyView( } } -@OptIn(ExperimentalLayoutApi::class) @Composable private fun Content( state: SecureBackupEnterRecoveryKeyState, ) { - val bringIntoViewRequester = remember { BringIntoViewRequester() } - var isFocused by remember { mutableStateOf(false) } - val isImeVisible = WindowInsets.isImeVisible - val coroutineScope = rememberCoroutineScope() - LaunchedEffect(isImeVisible, isFocused) { - // When the keyboard is shown, we want to scroll the text field into view - if (isImeVisible && isFocused) { - coroutineScope.launch { - // Delay to ensure the keyboard is fully shown - delay(100.milliseconds) - bringIntoViewRequester.bringIntoView() - } - } - } RecoveryKeyView( modifier = Modifier - .onFocusChanged { isFocused = it.isFocused } - .bringIntoViewRequester(bringIntoViewRequester) + .bringIntoViewOnImeVisible() .padding(top = 52.dp, bottom = 32.dp), state = state.recoveryKeyViewState, onClick = null, diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordView.kt index 8d32433ac5..3bb77ac206 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordView.kt @@ -8,8 +8,6 @@ package io.element.android.features.securebackup.impl.reset.password -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -32,7 +30,7 @@ import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusN import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button -import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.PasswordVisibilityToggle import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.designsystem.theme.components.TextFieldValidity import io.element.android.libraries.ui.strings.CommonStrings @@ -92,14 +90,10 @@ private fun Content(text: String, onTextChange: (String) -> Unit, hasError: Bool singleLine = true, visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { - val image = - if (showPassword) CompoundIcons.VisibilityOn() else CompoundIcons.VisibilityOff() - val description = - if (showPassword) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password) - - Box(Modifier.clickable { showPassword = !showPassword }) { - Icon(imageVector = image, description) - } + PasswordVisibilityToggle( + visible = showPassword, + onToggle = { showPassword = !showPassword }, + ) }, validity = if (hasError) TextFieldValidity.Invalid else TextFieldValidity.None, supportingText = if (hasError) { diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt index 97c82f446d..7ac8dbe4cf 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootView.kt @@ -22,11 +22,11 @@ import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.securebackup.impl.R -import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem -import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog +import io.element.android.libraries.designsystem.components.visuallist.VisualList +import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button @@ -79,10 +79,10 @@ private fun Content() { modifier = Modifier.padding(top = 8.dp, bottom = 40.dp), verticalArrangement = Arrangement.spacedBy(24.dp), ) { - InfoListOrganism( + VisualList( modifier = Modifier.fillMaxWidth(), items = persistentListOf( - InfoListItem( + VisualListItemData( message = stringResource(R.string.screen_encryption_reset_bullet_1), iconComposable = { Icon( @@ -93,7 +93,7 @@ private fun Content() { ) }, ), - InfoListItem( + VisualListItemData( message = stringResource(R.string.screen_encryption_reset_bullet_2), iconComposable = { Icon( @@ -104,7 +104,7 @@ private fun Content() { ) }, ), - InfoListItem( + VisualListItemData( message = stringResource(R.string.screen_encryption_reset_bullet_3), iconComposable = { Icon( diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt index 198891473c..8055709f20 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt @@ -9,7 +9,6 @@ package io.element.android.features.securebackup.impl.setup.views import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -50,6 +49,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.PasswordVisibilityToggle import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.testtags.TestTags @@ -223,16 +223,10 @@ private fun RecoveryKeyFormContent( ), placeholder = stringResource(id = R.string.screen_recovery_key_confirm_key_placeholder), trailingIcon = { - val image = - if (state.displayTextFieldContents) CompoundIcons.VisibilityOn() else CompoundIcons.VisibilityOff() - val description = - if (state.displayTextFieldContents) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password) - Box(Modifier.clickable { toggleRecoveryKeyVisibility(!state.displayTextFieldContents) }) { - Icon( - imageVector = image, - contentDescription = description, - ) - } + PasswordVisibilityToggle( + visible = state.displayTextFieldContents, + onToggle = { toggleRecoveryKeyVisibility(!state.displayTextFieldContents) }, + ) }, ) } diff --git a/features/securebackup/impl/src/main/res/values-et/translations.xml b/features/securebackup/impl/src/main/res/values-et/translations.xml index 860d017781..9958628dee 100644 --- a/features/securebackup/impl/src/main/res/values-et/translations.xml +++ b/features/securebackup/impl/src/main/res/values-et/translations.xml @@ -20,6 +20,27 @@ "Uue taastevõtme loomiseks palun järgi juhendit" "Salvesta oma uus taastevõti kas salasõnahalduris, krüptitud failis või mõnel muul turvalisel viisil" "Lähtesta oma konto krüptimine mõnest muust oma seadmest" + "Sisestatud taastevõti ei vasta süsteemis leiduvale" + "Lõpeta seadistus" + "Sisesta oma taastevõti uuesti." + "Korda oma taastevõtit" + + "Vähemalt %1$d tähemärk. Ära pruugi kasutajakonto salasõna." + "Vähemalt %1$d tähemärki. Ära pruugi kasutajakonto salasõna." + + "Tugevus" + "Salafraasi tugevus: %1$s" + "Mõõdukas" + "Tugev" + "Väga tugev" + "Väga kehv" + "Kehv" + "Sisesta taastevõti, mille saad meelde jätta." + "Sisesta taastevõti" + "Laadin taastevõtme nõudeid" + "Taastevõtme muutmiseks ava menüü: Seadistused → Krüptimine → Varundamine" + "Võid oma taastevõtit kasutada uute seadmete verifitseerimiseks või krüptitud vestluste taastamiseks, kui kaotate juurdepääsu kõigile oma seadmetele." + "Sinu varundus on nüüd täielikult seadistatud" "Jätka lähtestamisega" "Sinu kasutajakonto andmed, kontaktid, eelistused ja vestluste loend säiluvad" "Sa kaotad seniste sõnumite ajaloo" diff --git a/features/securebackup/impl/src/main/res/values-fr/translations.xml b/features/securebackup/impl/src/main/res/values-fr/translations.xml index dcdac3d919..3b738bf61e 100644 --- a/features/securebackup/impl/src/main/res/values-fr/translations.xml +++ b/features/securebackup/impl/src/main/res/values-fr/translations.xml @@ -20,6 +20,27 @@ "Suivez les instructions pour créer une nouvelle clé de récupération" "Enregistrez votre nouvelle clé dans un gestionnaire de mots de passe ou dans une note chiffrée" "Réinitialisez le chiffrement de votre compte en utilisant un autre appareil" + "La clé de récupération ne correspond pas" + "Terminer la configuration" + "Saisissez à nouveau votre clé de récupération." + "Confirmez votre clé de récupération" + + "%1$d caractère minimum. N’utilisez pas le mot de passe de votre compte" + "%1$d caractères minimum. N’utilisez pas le mot de passe de votre compte" + + "Force" + "Force du mot de passe : %1$s" + "Moyenne" + "Forte" + "Très forte" + "Très faible" + "Faible" + "Choisissez une clé de récupération que vous pouvez mémoriser." + "Saisissez une clé de récupération" + "Chargement des exigences relatives à la clé de récupération" + "Pour modifier votre clé de récupération, accédez à Paramètres → Chiffrement → Changer la clé de récupération" + "Vous pouvez utiliser votre clé de récupération pour vérifier de nouveaux appareils ou restaurer vos conversations chiffrées si vous perdez l’accès à tous vos appareils." + "Votre sauvegarde est maintenant entièrement configurée." "Continuer la réinitialisation" "Les détails de votre compte, vos contacts, vos préférences et votre liste de discussions seront conservés" "Vous perdrez l’historique de vos messages" diff --git a/features/securebackup/impl/src/main/res/values-hu/translations.xml b/features/securebackup/impl/src/main/res/values-hu/translations.xml index a5d910e76b..3d89c15c5c 100644 --- a/features/securebackup/impl/src/main/res/values-hu/translations.xml +++ b/features/securebackup/impl/src/main/res/values-hu/translations.xml @@ -20,6 +20,27 @@ "Kövesse az utasításokat egy új helyreállítási kulcs létrehozásához" "Mentse az új helyreállítási kulcsot egy jelszókezelőbe vagy egy titkosított jegyzetbe." "A fiók titkosításának visszaállítása egy másik eszköz használatával" + "A megadott helyreállítási kulcsok nem egyeznek" + "Beállítás befejezése" + "Írja be újra a helyreállítási kulcsot." + "Erősítse meg a helyreállítási kulcsát" + + "Minimum %1$d karakter. Ne használja a fiók jelszavát." + "Minimum %1$d karakter. Ne használja a fiók jelszavát." + + "Erősség" + "Jelszó erőssége: %1$s" + "Mérsékelt" + "Erős" + "Nagyon erős" + "Nagyon gyenge" + "Gyenge" + "Válasszon egy olyan helyreállítási kulcsot, amelyet könnyen megjegyezhet." + "Adja meg a helyreállítási kulcsot" + "Helyreállítási kulcs követelményeinek betöltése" + "A helyreállítási kulcs módosításához lépjen a Beállítások → Titkosítás → Biztonsági mentés menüpontra." + "A helyreállítási kulcs segítségével megerősítheti az új eszközöket, vagy visszaállíthatja a titkosított csevegéseket, ha elveszítette a hozzáférését az összes eszközéhez." + "A biztonsági mentés most már teljesen be van állítva" "Visszaállítás folytatása" "A fiókadatok, a kapcsolatok, a beállítások és a csevegéslista megmarad" "Elveszíti meglévő üzenetelőzményeit" diff --git a/features/securebackup/impl/src/main/res/values-in/translations.xml b/features/securebackup/impl/src/main/res/values-in/translations.xml index 577093cb52..2fd2c044fc 100644 --- a/features/securebackup/impl/src/main/res/values-in/translations.xml +++ b/features/securebackup/impl/src/main/res/values-in/translations.xml @@ -11,7 +11,7 @@ "Pulihkan identitas kriptografi dan riwayat pesan Anda dengan kunci pemulihan jika Anda kehilangan semua perangkat yang ada." "Masukkan kunci pemulihan" "Penyimpanan kunci Anda saat ini tidak sinkron." - "Siapkan pemulihan" + "Siapkan Kunci pemulihan" "Buka %1$s di perangkat desktop" "Masuk ke akun Anda lagi" "Saat diminta untuk memverifikasi perangkat Anda, pilih %1$s" @@ -25,8 +25,8 @@ "Anda perlu memverifikasi semua perangkat dan kontak yang ada lagi" "Hanya atur ulang identitas Anda jika Anda tidak memiliki akses ke perangkat lain yang masuk dan Anda kehilangan kunci pemulihan." "Tidak dapat mengonfirmasi? Anda perlu mengatur ulang identitas Anda." - "Matikan" - "Anda akan kehilangan pesan terenkripsi jika Anda keluar dari semua perangkat." + "Hapus" + "Anda akan kehilangan pesan terenkripsi jika Anda menghapusnya dari semua perangkat." "Apakah Anda yakin ingin mematikan pencadangan?" "Mematikan pencadangan akan menghapus pencadangan kunci terenkripsi saat ini dan mematikan fitur keamanan lainnya. Dalam hal ini, Anda akan:" "Tidak memiliki riwayat pesan terenkripsi di perangkat baru" @@ -58,7 +58,7 @@ "Buat kunci pemulihan Anda" "Jangan bagikan ini kepada siapa pun!" "Penyiapan pemulihan berhasil" - "Siapkan pemulihan" + "Siapkan Kunci pemulihan" "Ya, atur ulang sekarang" "Proses ini tidak dapat diurungkan." "Apakah Anda yakin ingin mengatur ulang identitas Anda?" diff --git a/features/securebackup/impl/src/main/res/values-ja/translations.xml b/features/securebackup/impl/src/main/res/values-ja/translations.xml index 72c8c90809..b9612c4e09 100644 --- a/features/securebackup/impl/src/main/res/values-ja/translations.xml +++ b/features/securebackup/impl/src/main/res/values-ja/translations.xml @@ -6,7 +6,7 @@ "鍵の保管庫" "チャットをバックアップするには、鍵の保管庫を使用する必要があります。" "この端末上の鍵をアップロードします" - "鍵の保管庫を使用します" + "鍵の保管庫を使用" "回復鍵を変更" "あなたのチャットはエンドツーエンド暗号化を使用して自動的にバックアップされています。すべての端末を使用できない状況で、このバックアップからデジタルIDを復元するには、回復鍵が必要となります。" "回復鍵を入力" diff --git a/features/securebackup/impl/src/main/res/values-pl/translations.xml b/features/securebackup/impl/src/main/res/values-pl/translations.xml index 99bbcc8159..fb1da3ca04 100644 --- a/features/securebackup/impl/src/main/res/values-pl/translations.xml +++ b/features/securebackup/impl/src/main/res/values-pl/translations.xml @@ -20,6 +20,28 @@ "Postępuj zgodnie z instrukcjami, aby utworzyć nowy klucz przywracania" "Zapisz nowy klucz przywracania w menedżerze haseł lub notatce szyfrowanej" "Zresetuj szyfrowanie swojego konta za pomocą drugiego urządzenia" + "Wprowadzony klucz przywracania nie pasuje" + "Zakończ konfigurację" + "Wprowadź ponownie klucz przywracania." + "Potwierdź swój klucz przywracania" + + "Co najmniej %1$d znak. Nie wykorzystuj swojego hasła." + "Co najmniej %1$d znaki. Nie wykorzystuj swojego hasła." + "Co najmniej %1$d znaków. Nie wykorzystuj swojego hasła." + + "Siła" + "Siła hasła: %1$s" + "Średnie" + "Silne" + "Bardzo silne" + "Bardzo słabe" + "Słabe" + "Wybierz klucz przywracania, który łatwo zapamiętasz." + "Wprowadź klucz przywracania" + "Wczytywanie wymagań hasła" + "Aby zmienić klucz przywracania przejdź do Ustawienia → Szyfrowanie → Kopia zapasowa" + "Możesz użyć klucza przywracania, żeby potwierdzić nowe urządzenia lub przywrócić zaszyfrowane czaty, jeśli stracisz dostęp do wszystkich swoich urządzeń." + "Twoja kopia zapasowa jest gotowa." "Kontynuuj resetowanie" "Szczegóły konta, kontakty, preferencje i lista czatów zostaną zachowane" "Utracisz istniejącą historię wiadomości" diff --git a/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml b/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml index 4423ae60ee..4dc368046d 100644 --- a/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/securebackup/impl/src/main/res/values-pt-rBR/translations.xml @@ -2,7 +2,7 @@ "Apagar o armazenamento de chaves" "Ativar o backup" - "Armazene sua identidade criptográfica e chaves de mensagem com segurança no servidor. Isso permitirá que você visualize seu histórico de mensagens em dispositivos futuros. %1$s." + "Isso te permite ver seu histórico de conversas em dispositivos novos, e é necessário para o backup de conversas e identidade digital. %1$s" "Armazenamento de chaves" "O armazenamento de chaves deve ser ativado para configurar a recuperação." "Enviar chaves a partir deste dispositivo" @@ -11,7 +11,7 @@ "Recupere sua identidade criptográfica e o histórico de mensagens com uma chave de recuperação, caso você tenha perdido todos os dispositivos existentes." "Digitar chave de recuperação" "Seu armazenamento de chaves está fora de sincronia no momento." - "Configurar a recuperação" + "Receber chave de recuperação" "Abra o %1$s em um computador" "Entre na sua conta novamente" "Ao ser solicitado para verificar o seu dispositivo, selecione %1$s" @@ -25,10 +25,10 @@ "Você precisará verificar todos os seus dispositivos e contatos existentes novamente." "Redefina sua identidade somente se você não tiver acesso a outro dispositivo conectado e se tiver perdido sua chave de recuperação." "Não consegue confirmar? Você precisará redefinir sua identidade." - "Desativar" - "Você perderá suas mensagens criptografadas se for desconectado de todos os dispositivos." - "Tem certeza de que deseja desativar o backup?" - "Ao apagar o armazenamento de chaves, a sua identidade criptográfica e as chaves das mensagens serão apagadas do servidor e os seguintes recursos de segurança serão desativados:" + "Apagar" + "Você perderá o seu histórico de mensagens criptografadas e precisará reconfigurar sua identidade digital se remover todos os dispositivos." + "Tem certeza de que deseja apagar o armazenamento de chaves?" + "Ao apagar o armazenamento de chaves, a sua identidade digital e as chaves das mensagens serão apagadas do servidor e os seguintes recursos de segurança serão desativados:" "Você não terá o histórico de mensagens criptografadas em dispositivos novos" "Você perderá o acesso às suas mensagens criptografadas se for desconectado de %1$s em todos os dispositivos" "Tem certeza de que deseja desativar o armazenamento de chaves e apagá-lo?" @@ -58,7 +58,7 @@ "Gere sua chave de recuperação" "Não compartilhe isso com ninguém!" "Configuração de recuperação bem-sucedida" - "Configurar a recuperação" + "Receber chave de recuperação" "Sim, redefinir agora" "Esse processo é irreversível." "Você tem certeza de que deseja redefinir sua identidade?" diff --git a/features/securebackup/impl/src/main/res/values-ru/translations.xml b/features/securebackup/impl/src/main/res/values-ru/translations.xml index ef80347ea4..1417de5766 100644 --- a/features/securebackup/impl/src/main/res/values-ru/translations.xml +++ b/features/securebackup/impl/src/main/res/values-ru/translations.xml @@ -8,13 +8,13 @@ "Загрузить ключи с этого устройства" "Разрешить хранение ключей" "Изменить ключ восстановления" - "Если вы потеряли доступ к другим устройствам, то сможете восстановить свою идентификацию и историю сообщений с помощью ключа восстановления." + "Ваши чаты автоматически резервируются с помощью сквозного шифрования. Для восстановления резервной копии и сохранения Вашей цифровой личности в случае потери доступа ко всем устройствам потребуется ключ восстановления." "Введите ключ восстановления" "В настоящее время резервная копия ваших чатов не синхронизирована." "Получить ключ восстановления" "Ваши чаты автоматически резервируются с использованием сквозного шифрования. Для восстановления этой резервной копии и сохранения вашей цифровой личности в случае потери доступа ко всем вашим устройствам вам потребуется ключ восстановления." "Откройте %1$s на компьютере" - "Войдите в свой аккаунт еще раз" + "Войдите в свой аккаунт ещё раз" "Когда потребуется подтвердить устройство, выберите %1$s" "«Сбросить все»" "Следуйте инструкциям, чтобы создать новый ключ восстановления" @@ -24,7 +24,7 @@ "Данные вашего аккаунта, контакты, настройки и список чатов будут сохранены" "Вы потеряете историю тех сообщений, которые хранятся только на сервере" "Вам нужно будет заново подтвердить все существующие устройства и контакты." - "Сбрасывайте ключ шифрования только в том случае, если у вас нет доступа к другому устройству, на котором выполнен вход, и вы потеряли ключ восстановления." + "Сбрасывайте ключ шифрования только в том случае, если у Вас нет доступа к другому устройству, на котором выполнен вход, и Вы потеряли ключ восстановления." "Не можете подтвердить? Вам потребуется сбросить свою цифровую идентификацию." "Удалить" "Вы потеряете зашифрованные сообщения, если выйдете из всех устройств." @@ -40,9 +40,9 @@ "Изменить ключ восстановления?" "Создать новый ключ восстановления" "Убедитесь, что никто не подсматривает)" - "Пожалуйста, попробуйте еще раз, чтобы подтвердить доступ к резервной копии чата." + "Пожалуйста, попробуйте ещё раз, чтобы подтвердить доступ к резервной копии чата." "Неверный ключ восстановления" - "Если у вас есть пароль для восстановления или секретный пароль/ключ, это тоже сработает." + "Если у Вас есть ключ/фраза для восстановления, это тоже сработает." "Введите…" "Потеряли ключ восстановления?" "Ключ восстановления подтвержден" diff --git a/features/securebackup/impl/src/main/res/values-sk/translations.xml b/features/securebackup/impl/src/main/res/values-sk/translations.xml index 3e92a39df0..4e646ef47e 100644 --- a/features/securebackup/impl/src/main/res/values-sk/translations.xml +++ b/features/securebackup/impl/src/main/res/values-sk/translations.xml @@ -11,7 +11,7 @@ "Obnovte svoju kryptografickú totožnosť a históriu správ pomocou kľúča na obnovenie, ak ste stratili všetky svoje existujúce zariadenia." "Zadajte kľúč na obnovenie" "Vaše úložisko kľúčov nie je momentálne synchronizované." - "Nastaviť obnovenie" + "Získať kľúč na obnovenie" "Otvoriť %1$s v stolnom počítači" "Znova sa prihláste do svojho účtu" "Keď sa zobrazí výzva na overenie vášho zariadenia, vyberte %1$s" @@ -25,10 +25,10 @@ "Budete musieť znova overiť všetky existujúce zariadenia a kontakty" "Obnovte svoju totožnosť iba vtedy, ak nemáte prístup k inému prihlásenému zariadeniu a stratili ste kľúč na obnovenie." "Znovu nastavte svoju totožnosť v prípade, že ju nemôžete potvrdiť iným spôsobom" - "Vypnúť" + "Odstrániť" "Ak odstránite všetky svoje zariadenia, stratíte svoju zašifrovanú históriu správ a budete si musieť obnoviť svoju digitálnu identitu." - "Ste si istí, že chcete vypnúť zálohovanie?" - "Vypnutím zálohovania sa odstráni aktuálna záloha šifrovacích kľúčov a vypnú sa ďalšie bezpečnostné funkcie. V tomto prípade:" + "Naozaj chcete odstrániť úložisko kľúčov?" + "Odstránením úložiska kľúčov sa zo servera odstránia vaše kľúče digitálnej identity a správ a vypnú sa nasledujúce bezpečnostné funkcie:" "Na nových zariadeniach nebudete mať zašifrovanú históriu správ" "Stratíte prístup k svojim zašifrovaným správam, ak sa odhlásite z aplikácie %1$s na všetkých zariadeniach" "Ste si istí, že chcete vypnúť zálohovanie?" @@ -58,7 +58,7 @@ "Vygenerujte si váš kľúč na obnovenie" "Nezdieľajte to s nikým!" "Úspešné nastavenie obnovy" - "Nastaviť obnovenie" + "Získať kľúč na obnovenie" "Áno, znovu nastaviť teraz" "Tento proces je nezvratný." "Naozaj chcete obnoviť svoje šifrovanie?" diff --git a/features/securebackup/impl/src/main/res/values-uk/translations.xml b/features/securebackup/impl/src/main/res/values-uk/translations.xml index 82a96fcab9..c75f300b05 100644 --- a/features/securebackup/impl/src/main/res/values-uk/translations.xml +++ b/features/securebackup/impl/src/main/res/values-uk/translations.xml @@ -2,34 +2,56 @@ "Вимкнути резервне копіювання" "Увімкнути резервне копіювання" - "Зберігайте свій криптографічний ідентифікатор і ключі повідомлень на сервері. Це дозволить вам переглядати історію повідомлень на будь-яких нових пристроях. %1$s." + "Це дозволить вам переглядати історію бесід на нових пристроях і необхідно для резервного копіювання бесід і цифрової ідентичності. %1$s." "Резервне копіювання" - "Щоб налаштувати відновлення, потрібно ввімкнути зберігання ключів." + "Для створення резервної копії ваших бесід необхідно ввімкнути функцію зберігання ключів." "Завантажте ключі з цього пристрою" "Дозволити зберігання ключів" "Змінити ключ відновлення" - "Відновіть криптографічну ідентичність та історію повідомлень за допомогою ключа відновлення, якщо ви втратили всі наявні пристрої." + "Ваші бесіди автоматично резервуються з використанням наскрізного шифрування. Щоб відновити цю резервну копію та зберегти свою цифрову ідентичність у разі втрати доступу до всіх своїх пристроїв, вам знадобиться ключ відновлення." "Введіть ключ відновлення" "Сховище ключів наразі не синхронізовано." - "Налаштувати відновлення" - "Ваші чати автоматично резервуються з використанням наскрізного шифрування. Щоб відновити цю резервну копію та зберегти свою цифрову ідентичність у разі втрати доступу до всіх своїх пристроїв, вам знадобиться ключ відновлення." + "Отримати ключ відновлення" + "Ваші бесіди автоматично резервуються з використанням наскрізного шифрування. Щоб відновити цю резервну копію та зберегти свою цифрову ідентичність у разі втрати доступу до всіх своїх пристроїв, вам знадобиться ключ відновлення." "Відкрийте %1$s на комп\'ютері" "Увійдіть до вашого облікового запису знову" - "Коли вас попросять підтвердити пристрій, виберіть %1$s" + "Коли вас попросять звірити пристрій, виберіть %1$s" "“Скинути все”" "Дотримуйтесь інструкцій, щоб створити новий ключ відновлення" "Збережіть новий ключ відновлення у менеджері паролів або зашифрованій нотатці" "Скинути шифрування облікового запису за допомогою іншого пристрою" + "Введений ключ відновлення не збігається" + "Завершити налаштування" + "Повторно введіть свій ключ відновлення." + "Підтвердьте свій ключ відновлення" + + "Щонайменше %1$d символ. Не використовуйте пароль облікового запису." + "Щонайменше %1$d символи. Не використовуйте пароль облікового запису." + "Щонайменше %1$d символів. Не використовуйте пароль облікового запису." + + "Надійність" + "Надійність парольної фрази: %1$s" + "Посередня" + "Надійна" + "Дуже надійна" + "Дуже ненадійна" + "Ненадійна" + "Оберіть ключ відновлення, який ви зможете запам\'ятати." + "Введіть ключ відновлення" + "Завантаження вимог до ключа відновлення" + "Щоб змінити ключ відновлення, перейдіть до Налаштування → Шифрування → Резервне копіювання" + "Ви можете використовувати свій ключ відновлення для підтвердження нових пристроїв або відновлення зашифрованих бесід, якщо втратите доступ до всіх своїх пристроїв." + "Налаштування резервного копіювання завершено" "Продовжити скидання налаштувань" "Дані вашого облікового запису, контакти, налаштування й бесіди будуть збережені" "Ви втратите свою наявну історію повідомлень" - "Вам доведеться верифікувати всі наявні пристрої та контакти повторно" - "Скидайте ідентичність тільки якщо ви не маєте доступу до інших пристроїв в обліковому записі та втратили свій ключ відновлення." - "Не можете підтвердити? Вам доведеться скинути свою ідентичність." - "Вимкнути" - "Ви втратите зашифровані повідомлення, якщо вийдете з усіх пристроїв." - "Ви впевнені, що хочете вимкнути резервне копіювання?" - "Вимкнення резервного копіювання призведе до видалення поточної резервної копії ключа шифрування та вимкнення інших функцій безпеки. В такому разі ви:" + "Вам потрібно буде повторно звірити всі наявні пристрої та контакти" + "Скидайте свою цифрову ідентичність лише якщо у вас немає доступу до іншого звіреного пристрою та ключа відновлення." + "Не можете підтвердити? Вам доведеться скинути свою цифрову ідентичність." + "Видалити" + "Якщо ви вилучите всі свої пристрої, ви втратите історію зашифрованих бесід і вам доведеться скинути свою цифрову ідентичність." + "Ви впевнені, що хочете видалити сховище ключів?" + "Видалення сховища ключів призведе до видалення вашої цифрової ідентичності та ключів повідомлень із сервера, а також вимкне ці функції безпеки:" "Не матимете історії зашифрованих повідомлень на нових пристроях" "Втратите доступ до зашифрованих повідомлень, якщо вийдете з усіх сеансів %1$s" "Ви впевнені, що хочете вимкнути резервне копіювання?" @@ -55,16 +77,16 @@ "Збережіть ключ відновлення" "Після цього кроку ви не зможете отримати доступ до нового ключа відновлення." "Ви зберегли ключ відновлення?" - "Ваша резервна копія чату захищена ключем відновлення. Якщо вам потрібен новий ключ відновлення після налаштування, ви можете відтворити, вибравши «Змінити ключ відновлення»." + "Ваше сховище ключів захищено ключем відновлення. Якщо вам знадобиться новий ключ відновлення після налаштування, ви можете створити його повторно, вибравши «Змінити ключ відновлення»." "Згенеруйте ключ відновлення" "Не діліться цим ні з ким!" "Налаштування відновлення виконано успішно" - "Налаштувати відновлення" + "Отримати ключ відновлення" "Так, скинути зараз" "Цей процес незворотний." - "Ви впевнені, що хочете скинути шифрування?" + "Ви впевнені, що хочете скинути свою цифрову ідентичність?" "Сталася невідома помилка. Будь ласка, перевірте правильність пароля свого облікового запису та повторіть спробу." "Входимо…" - "Підтвердьте, що ви хочете скинути шифрування." + "Підтвердьте, що ви хочете скинути свою цифрову ідентичність." "Введіть пароль облікового запису, щоб продовжити" diff --git a/features/securebackup/impl/src/main/res/values-zh/translations.xml b/features/securebackup/impl/src/main/res/values-zh/translations.xml index 459291614e..2b59a54ada 100644 --- a/features/securebackup/impl/src/main/res/values-zh/translations.xml +++ b/features/securebackup/impl/src/main/res/values-zh/translations.xml @@ -20,6 +20,26 @@ "按照说明创建新的恢复密钥" "将新的恢复密钥保存在密码管理器或加密备忘录中" "使用其它设备重置账户的加密" + "输入的恢复密钥不匹配" + "完成设置" + "再次输入恢复密钥。" + "确认恢复密钥" + + "最少 %1$d 个字符。请勿使此处的内容与账户密码相同。" + + "强度" + "口令强度:%1$s" + "中等" + "强" + "非常强" + "非常弱" + "弱" + "选择你能记住的恢复密钥。" + "输入恢复密钥" + "正在加载恢复密钥要求" + "转到“设置”→“加密”→“备份”以更改恢复密钥。" + "如果你无法访问所有设备,可以使用恢复密钥以确认新设备或恢复加密聊天。" + "你已完成备份设置" "继续重置" "你的账户信息、联系人、偏好和聊天列表将被保留" "你将丢失所有仅存储在服务器上的消息历史" diff --git a/features/securebackup/impl/src/main/res/values/localazy.xml b/features/securebackup/impl/src/main/res/values/localazy.xml index e0fc2d37e7..5acae5f07f 100644 --- a/features/securebackup/impl/src/main/res/values/localazy.xml +++ b/features/securebackup/impl/src/main/res/values/localazy.xml @@ -20,6 +20,27 @@ "Follow the instructions to create a new recovery key" "Save your new recovery key in a password manager or encrypted note" "Reset the encryption for your account using another device" + "The recovery key you entered doesn\'t match" + "Finish setup" + "Enter your recovery key again." + "Confirm your recovery key" + + "Minimum %1$d character. Do not use your account password" + "Minimum %1$d characters. Do not use your account password" + + "Strength" + "Passphrase strength: %1$s" + "Moderate" + "Strong" + "Very strong" + "Very weak" + "Weak" + "Choose a recovery key that you can memorize." + "Enter a recovery key" + "Loading recovery key requirements" + "To change your recovery key, go to Settings → Encryption → Backup" + "You can use your recovery key to confirm new devices or restore your encrypted chats if you lose access to all your devices." + "Your backup is now fully set up" "Continue reset" "Your account details, contacts, preferences, and chat list will be kept" "You will lose any message history that’s stored only on the server" diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt index 9e984f1ec0..6c2cb9984f 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPointTest.kt @@ -32,6 +32,7 @@ class DefaultSecureBackupEntryPointTest { SecureBackupFlowNode( buildContext = buildContext, plugins = plugins, + secureBackupSetupEntryPoint = DefaultSecureBackupSetupEntryPoint(), ) } val callback = object : SecureBackupEntryPoint.Callback { diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPointTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPointTest.kt new file mode 100644 index 0000000000..e37dab748f --- /dev/null +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupSetupEntryPointTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.securebackup.impl + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.testing.junit4.util.MainDispatcherRule +import com.google.common.truth.Truth.assertThat +import io.element.android.features.securebackup.api.SecureBackupSetupEntryPoint +import io.element.android.features.securebackup.impl.setup.SecureBackupSetupNode +import io.element.android.features.securebackup.impl.setup.SecureBackupSetupPresenter +import io.element.android.features.securebackup.impl.setup.SecureBackupSetupStateMachine +import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher +import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService +import io.element.android.tests.testutils.node.TestParentNode +import org.junit.Rule +import org.junit.Test + +class DefaultSecureBackupSetupEntryPointTest { + @get:Rule + val instantTaskExecutorRule = InstantTaskExecutorRule() + + @get:Rule + val mainDispatcherRule = MainDispatcherRule() + + @Test + fun `test node builder`() { + val entryPoint = DefaultSecureBackupSetupEntryPoint() + val parentNode = TestParentNode.create { buildContext, plugins -> + SecureBackupSetupNode( + buildContext = buildContext, + plugins = plugins, + presenterFactory = object : SecureBackupSetupPresenter.Factory { + override fun create(isChangeRecoveryKeyUserStory: Boolean) = SecureBackupSetupPresenter( + isChangeRecoveryKeyUserStory = isChangeRecoveryKeyUserStory, + stateMachine = SecureBackupSetupStateMachine(), + encryptionService = FakeEncryptionService(), + ) + }, + snackbarDispatcher = SnackbarDispatcher(), + ) + } + val inputs = SecureBackupSetupEntryPoint.Inputs(isChangeRecoveryKeyUserStory = true) + val result = entryPoint.createNode( + parentNode = parentNode, + buildContext = BuildContext.root(null), + inputs = inputs, + ) + assertThat(result).isInstanceOf(SecureBackupSetupNode::class.java) + assertThat(result.plugins).contains(SecureBackupSetupNode.Inputs(isChangeRecoveryKeyUserStory = true)) + } +} diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyViewTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyViewTest.kt index f9729f74f0..fcf050f925 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyViewTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyViewTest.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performImeAction import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.securebackup.impl.setup.views.aFormattedRecoveryKey import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.ui.strings.CommonStrings @@ -29,12 +28,11 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class SecureBackupEnterRecoveryKeyViewTest { +class SecureBackupEnterRecoveryKeyViewTest : RobolectricTest() { @Test fun `back key pressed - calls onBackClick`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordViewTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordViewTest.kt index ce5972f66b..8173c20b3d 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordViewTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/password/ResetIdentityPasswordViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -25,11 +24,10 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ResetIdentityPasswordViewTest { +class ResetIdentityPasswordViewTest : RobolectricTest() { @Test fun `pressing the back HW button invokes the expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt index 0126d0d879..0d95bf709f 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/reset/root/ResetIdentityRootViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.securebackup.impl.R import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -23,12 +22,11 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class ResetIdentityRootViewTest { +class ResetIdentityRootViewTest : RobolectricTest() { @Test fun `pressing the back HW button invokes the expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { diff --git a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupPresenterTest.kt b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupPresenterTest.kt index a3cf920d82..4aede3c534 100644 --- a/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupPresenterTest.kt +++ b/features/securebackup/impl/src/test/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupPresenterTest.kt @@ -117,7 +117,7 @@ class SecureBackupSetupPresenterTest { @Test fun `present - handle errors`() = runTest { val encryptionService = FakeEncryptionService( - enableRecoveryLambda = { Result.failure(IllegalStateException("Test error")) } + enableRecoveryLambda = { _, _ -> Result.failure(IllegalStateException("Test error")) } ) val presenter = createSecureBackupSetupPresenter( isChangeRecoveryKeyUserStory = false, @@ -189,7 +189,7 @@ class SecureBackupSetupPresenterTest { private fun createSecureBackupSetupPresenter( isChangeRecoveryKeyUserStory: Boolean = false, encryptionService: EncryptionService = FakeEncryptionService( - enableRecoveryLambda = { Result.success(Unit) }, + enableRecoveryLambda = { _, _ -> Result.success("") }, ), ): SecureBackupSetupPresenter { return SecureBackupSetupPresenter( diff --git a/features/securityandprivacy/impl/src/main/res/values-be/translations.xml b/features/securityandprivacy/impl/src/main/res/values-be/translations.xml index 45ca9760ac..b2e90afeee 100644 --- a/features/securityandprivacy/impl/src/main/res/values-be/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-be/translations.xml @@ -1,4 +1,6 @@ + "Рэдагаваць адрас" "Вашы прасторы" + "Адрас" diff --git a/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml b/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml index 2cae719a03..bd6ad0081d 100644 --- a/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml +++ b/features/securityandprivacy/impl/src/main/res/values-ru/translations.xml @@ -3,7 +3,7 @@ "Необходимо задать адрес комнаты, чтобы опубликовать ее в каталоге комнат." "Редактировать адрес комнаты" "Пространства, где участники могут присоединиться к комнате без приглашения." - "Управление пространством" + "Управление пространствами" "(неизвестное пространство)" "Другие пространства, в которых вы не состоите" "Ваши пространства" @@ -23,7 +23,7 @@ "Любой желающий может присоединиться" "Кто угодно" "Выберите, участники каких пространств могут присоединиться к этой комнате без приглашения.%1$s" - "Управление пространством" + "Управление пространствами" "Присоединиться могут только приглашенные люди." "Только по приглашению" "Доступ" diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNodeTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNodeTest.kt index a6f21c0162..5578d6b01c 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNodeTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNodeTest.kt @@ -8,7 +8,6 @@ package io.element.android.features.securityandprivacy.impl -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.bumble.appyx.core.modality.AncestryInfo import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.navmodel.backstack.activeElement @@ -20,12 +19,11 @@ import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class SecurityAndPrivacyFlowNodeTest { +class SecurityAndPrivacyFlowNodeTest : RobolectricTest() { @Test fun `initial backstack contains SecurityAndPrivacy`() = runTest { val flowNode = createFlowNode() diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/editroomaddress/EditRoomAddressViewTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/editroomaddress/EditRoomAddressViewTest.kt index 2c0a6c9acb..1d0886f52a 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/editroomaddress/EditRoomAddressViewTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/editroomaddress/EditRoomAddressViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity import io.element.android.libraries.testtags.TestTags @@ -26,11 +25,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class EditRoomAddressViewTest { +class EditRoomAddressViewTest : RobolectricTest() { @Test fun `click on back invokes expected callback`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/manageauthorizedspaces/ManageAuthorizedSpacesViewTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/manageauthorizedspaces/ManageAuthorizedSpacesViewTest.kt index de6da41823..7d0a1aea16 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/manageauthorizedspaces/ManageAuthorizedSpacesViewTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/manageauthorizedspaces/ManageAuthorizedSpacesViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.spaces.SpaceRoom import io.element.android.libraries.matrix.test.A_ROOM_ID @@ -25,13 +24,12 @@ import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableSet import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class ManageAuthorizedSpacesViewTest { +class ManageAuthorizedSpacesViewTest : RobolectricTest() { @Test fun `clicking back emits Cancel event`() = runAndroidComposeUiTest { val recorder = EventsRecorder() diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyViewTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyViewTest.kt index c46accbc91..220a8d3d6d 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyViewTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyViewTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.securityandprivacy.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData @@ -25,13 +24,12 @@ import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.persistentListOf import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class SecurityAndPrivacyViewTest { +class SecurityAndPrivacyViewTest : RobolectricTest() { @Test fun `click on back invokes emits the expected event`() = runAndroidComposeUiTest { val recorder = EventsRecorder() diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt index 3a71f02dc3..daab3787b3 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/DefaultOnSharedData.kt @@ -7,6 +7,7 @@ package io.element.android.features.share.impl +import android.content.ContentResolver import android.content.Context import android.content.Intent import android.net.Uri @@ -15,13 +16,14 @@ import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import io.element.android.features.share.api.OnSharedData import io.element.android.features.share.api.ShareIntentData +import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.di.annotations.ApplicationContext import timber.log.Timber -import kotlin.collections.forEach @ContributesBinding(AppScope::class) class DefaultOnSharedData( @ApplicationContext private val context: Context, + private val buildMeta: BuildMeta, ) : OnSharedData { override fun invoke(data: ShareIntentData) { when (data) { @@ -29,6 +31,13 @@ class DefaultOnSharedData( // No-op, there is nothing to do for plain text intents. } is ShareIntentData.Uris -> { + val fileProvider = "${buildMeta.applicationId}.fileprovider" + for (sharedUri in data.uris) { + // Remove the local copy of the shared file, as it is not needed anymore + if (sharedUri.uri.scheme == ContentResolver.SCHEME_CONTENT && sharedUri.uri.host == fileProvider) { + context.contentResolver.delete(sharedUri.uri, null, emptyArray()) + } + } revokeUriPermissions(data.uris.map { it.uri }) } } diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt index 0597b3b678..1abac1afa6 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/ShareNode.kt @@ -70,7 +70,10 @@ class ShareNode( return roomSelectEntryPoint.createNode( parentNode = this, buildContext = buildContext, - params = RoomSelectEntryPoint.Params(mode = RoomSelectMode.Share), + params = RoomSelectEntryPoint.Params( + mode = RoomSelectMode.Share, + maxNumberOfRooms = RoomSelectEntryPoint.DEFAULT_MAX_NUMBER_OF_ROOMS, + ), callback = callback, ) } diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt index fd2c8ff194..ab3a260c01 100644 --- a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt +++ b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt @@ -32,15 +32,13 @@ import io.element.android.services.appnavstate.api.ActiveRoomsHolder import io.element.android.services.appnavstate.impl.DefaultActiveRoomsHolder import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class SharePresenterTest { +class SharePresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt index f89b36e4d4..41a99713e7 100644 --- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt +++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutView.kt @@ -21,14 +21,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule -import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem -import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.components.BigIcon +import io.element.android.libraries.designsystem.components.visuallist.VisualList +import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button @@ -75,23 +74,21 @@ private fun SignedOutContent() { verticalBias = -0.4f ) ) { - InfoListOrganism( + VisualList( items = persistentListOf( - InfoListItem( + VisualListItemData( message = stringResource(id = R.string.screen_signed_out_reason_1), iconVector = CompoundIcons.Lock(), ), - InfoListItem( + VisualListItemData( message = stringResource(id = R.string.screen_signed_out_reason_2), iconVector = CompoundIcons.Devices(), ), - InfoListItem( + VisualListItemData( message = stringResource(id = R.string.screen_signed_out_reason_3), iconVector = CompoundIcons.Block(), ), ), - textStyle = ElementTheme.typography.fontBodyMdMedium, - iconTint = ElementTheme.colors.iconSecondary, ) } } diff --git a/features/signedout/impl/src/main/res/values-ru/translations.xml b/features/signedout/impl/src/main/res/values-ru/translations.xml index d3fd510afd..042cd0ca08 100644 --- a/features/signedout/impl/src/main/res/values-ru/translations.xml +++ b/features/signedout/impl/src/main/res/values-ru/translations.xml @@ -3,6 +3,6 @@ "Вы изменили свой пароль в другой сессии" "Вы удалили сессию из другой сессии" "Администратор вашего сервера аннулировал ваш доступ" - "Возможно, вы вышли из системы по одной из причин, перечисленных ниже. Пожалуйста, войдите в систему еще раз, чтобы продолжить использование %s." + "Возможно, Вы вышли из системы по одной из причин, перечисленных ниже. Пожалуйста, войдите в систему ещё раз, чтобы продолжить использовать %s." "Вы вышли из системы" diff --git a/features/space/impl/src/main/res/values-zh/translations.xml b/features/space/impl/src/main/res/values-zh/translations.xml index cbe9d54c32..bf5c298590 100644 --- a/features/space/impl/src/main/res/values-zh/translations.xml +++ b/features/space/impl/src/main/res/values-zh/translations.xml @@ -16,7 +16,7 @@ "添加房间不会影响其访问权限。如需更改访问权限,请前往“房间设置” > “安全与隐私”。" "添加第一个房间" "查看成员" - "移除房间不会影响其访问权限。要更改访问权限,请转到“房间信息” > “隐私和安全”。" + "移除房间不会影响其访问权限。要更改访问权限,请转到“房间信息”→“隐私与安全”。" "移除 %2$s 个房间,共 %1$d 个" diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/addroom/AddRoomToSpaceViewTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/addroom/AddRoomToSpaceViewTest.kt index fa47ce63bb..c49144f1c9 100644 --- a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/addroom/AddRoomToSpaceViewTest.kt +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/addroom/AddRoomToSpaceViewTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.ui.strings.CommonStrings @@ -24,13 +23,12 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.toImmutableList import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class AddRoomToSpaceViewTest { +class AddRoomToSpaceViewTest : RobolectricTest() { @Test fun `clicking back when search inactive emits Dismiss and invokes onBackClick`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt index 6632c7f4f8..042d6a00ff 100644 --- a/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt +++ b/features/space/impl/src/test/kotlin/io/element/android/features/space/impl/root/SpaceViewTest.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.spaces.SpaceRoom @@ -36,12 +35,11 @@ import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class SpaceViewTest { +class SpaceViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt index 360c59881c..ffe6a47f0d 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt @@ -18,7 +18,8 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember @@ -47,7 +48,10 @@ fun JoinRoomByAddressView( state: JoinRoomByAddressState, modifier: Modifier = Modifier, ) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), + ) ModalBottomSheet( modifier = modifier, sheetState = sheetState, diff --git a/features/startchat/impl/src/main/res/values-el/translations.xml b/features/startchat/impl/src/main/res/values-el/translations.xml index 19e6250d12..b07e1a827c 100644 --- a/features/startchat/impl/src/main/res/values-el/translations.xml +++ b/features/startchat/impl/src/main/res/values-el/translations.xml @@ -5,7 +5,7 @@ "Παρουσιάστηκε σφάλμα κατά την προσπάθεια έναρξης μιας συνομιλίας" "Συμμετοχή σε αίθουσα μέσω διεύθυνσης" "Μη έγκυρη διεύθυνση" - "Εισάγετε…" + "Εισαγάγετε διεύθυνση…" "Βρέθηκε η αντίστοιχη αίθουσα" "Η αίθουσα δεν βρέθηκε" "π.χ. #όνομα-αίθουσας:matrix.org" diff --git a/features/startchat/impl/src/main/res/values-et/translations.xml b/features/startchat/impl/src/main/res/values-et/translations.xml index 65459475a8..527d036cd4 100644 --- a/features/startchat/impl/src/main/res/values-et/translations.xml +++ b/features/startchat/impl/src/main/res/values-et/translations.xml @@ -5,7 +5,7 @@ "Vestluse alustamisel tekkis viga" "Liitu jututoaga aadressi alusel" "See pole kehtiv aadress" - "Sisene…" + "Sisesta aadress…" "Leidsime vastava jututoa" "Jututuba ei leidu" "nt. #jututoa-nimi:matrix.org" diff --git a/features/startchat/impl/src/main/res/values-in/translations.xml b/features/startchat/impl/src/main/res/values-in/translations.xml index 5f796bb8da..b711d6c6cb 100644 --- a/features/startchat/impl/src/main/res/values-in/translations.xml +++ b/features/startchat/impl/src/main/res/values-in/translations.xml @@ -5,7 +5,7 @@ "Terjadi kesalahan saat mencoba memulai obrolan" "Bergabung dalam ruangan berdasarkan alamat" "Bukan alamat yang valid" - "Masuk…" + "Masukkan alamat…" "Ruangan yang cocok ditemukan" "Ruangan tidak ditemukan" "mis. #nama-ruangan:matrix.org" diff --git a/features/startchat/impl/src/main/res/values-pl/translations.xml b/features/startchat/impl/src/main/res/values-pl/translations.xml index fe6b4a2c8d..10b88f0658 100644 --- a/features/startchat/impl/src/main/res/values-pl/translations.xml +++ b/features/startchat/impl/src/main/res/values-pl/translations.xml @@ -5,7 +5,7 @@ "Wystąpił błąd podczas próby rozpoczęcia czatu" "Dołącz do pokoju za pomocą adresu" "Nieprawidłowy adres" - "Wprowadź…" + "Wprowadź adres…" "Znaleziono pasujący pokój" "Nie znaleziono pokoju" "np. #room-name:matrix.org" diff --git a/features/startchat/impl/src/main/res/values-uk/translations.xml b/features/startchat/impl/src/main/res/values-uk/translations.xml index 3c2b09939c..5d7e0f13b3 100644 --- a/features/startchat/impl/src/main/res/values-uk/translations.xml +++ b/features/startchat/impl/src/main/res/values-uk/translations.xml @@ -5,7 +5,7 @@ "Під час спроби почати бесіду сталася помилка" "Приєднатися до кімнати за адресою" "Недійсна адреса" - "Введіть…" + "Увести адресу…" "Знайдено відповідну кімнату" "Кімната не знайдена" "наприклад, #room-name:matrix.org" diff --git a/features/startchat/impl/src/main/res/values-zh/translations.xml b/features/startchat/impl/src/main/res/values-zh/translations.xml index 0467ab9c0e..bd41a627b1 100644 --- a/features/startchat/impl/src/main/res/values-zh/translations.xml +++ b/features/startchat/impl/src/main/res/values-zh/translations.xml @@ -5,7 +5,7 @@ "在开始聊天时发生了错误" "输入地址加入房间" "地址无效" - "输入…" + "输入地址…" "找到匹配的房间" "未找到房间" "例如 #room-name:matrix.org" diff --git a/features/startchat/impl/src/main/res/values/localazy.xml b/features/startchat/impl/src/main/res/values/localazy.xml index 48b6449263..dedfbfb5cc 100644 --- a/features/startchat/impl/src/main/res/values/localazy.xml +++ b/features/startchat/impl/src/main/res/values/localazy.xml @@ -5,7 +5,7 @@ "An error occurred when trying to start a chat" "Join room by address" "Not a valid address" - "Enter…" + "Enter address…" "Matching room found" "Room not found" "e.g. #room-name:matrix.org" diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt index dd992a9d2f..421f8c7089 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt @@ -16,17 +16,15 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performTextInput import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.startchat.impl.R import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class JoinBaseRoomByAddressViewTest { +class JoinBaseRoomByAddressViewTest : RobolectricTest() { @Test fun `entering text emits the expected event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt index 916611bf20..8b5e1da8e6 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.startchat.impl.R import io.element.android.features.startchat.impl.userlist.aRecentDirectRoomList import io.element.android.features.startchat.impl.userlist.aUserListState @@ -30,12 +29,11 @@ import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class StartChatViewTest { +class StartChatViewTest : RobolectricTest() { @Test fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserSection.kt b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserSection.kt index c3caffa7f3..62efbf1f0f 100644 --- a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserSection.kt +++ b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserSection.kt @@ -84,7 +84,6 @@ private fun PreferenceBlockUser( leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Block())), onClick = { if (!isLoading) eventSink(UserProfileEvents.UnblockUser(needsConfirmation = true)) }, trailingContent = if (isLoading) ListItemContent.Custom(loadingCurrentValue) else null, - style = ListItemStyle.Primary, ) } else { ListItem( diff --git a/features/userprofile/shared/src/main/res/values-uk/translations.xml b/features/userprofile/shared/src/main/res/values-uk/translations.xml index 40dfa190ba..8d50f5aeb7 100644 --- a/features/userprofile/shared/src/main/res/values-uk/translations.xml +++ b/features/userprofile/shared/src/main/res/values-uk/translations.xml @@ -13,7 +13,7 @@ "Розблокувати" "Ви знову зможете бачити всі повідомлення від них." "Розблокувати користувача" - "Використовуйте веб-додаток, щоб верифікувати цього користувача." - "Перевірте %1$s" + "Використовуйте вебзастосунок, щоб звірити цього користувача." + "Звірити %1$s" "Під час спроби почати бесіду сталася помилка" diff --git a/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/UserProfileViewTest.kt b/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/UserProfileViewTest.kt index b1d81f374c..63930affee 100644 --- a/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/UserProfileViewTest.kt +++ b/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/UserProfileViewTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState @@ -42,12 +41,11 @@ import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam import io.element.android.tests.testutils.ensureCalledOnceWithTwoParams import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class UserProfileViewTest { +class UserProfileViewTest : RobolectricTest() { @Test fun `on back button click - the expected callback is called`() = runAndroidComposeUiTest { ensureCalledOnce { callback -> diff --git a/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserDialogsTest.kt b/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserDialogsTest.kt index 3498ad7714..b0a2590e8a 100644 --- a/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserDialogsTest.kt +++ b/features/userprofile/shared/src/test/kotlin/io/element/android/features/userprofile/shared/blockuser/BlockUserDialogsTest.kt @@ -12,7 +12,6 @@ package io.element.android.features.userprofile.shared.blockuser import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.shared.R @@ -20,11 +19,10 @@ import io.element.android.features.userprofile.shared.aUserProfileState import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class BlockUserDialogsTest { +class BlockUserDialogsTest : RobolectricTest() { @Test fun `confirm block user emit expected Event`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/features/verifysession/impl/src/main/res/values-be/translations.xml b/features/verifysession/impl/src/main/res/values-be/translations.xml index a11cb7d607..375274c05e 100644 --- a/features/verifysession/impl/src/main/res/values-be/translations.xml +++ b/features/verifysession/impl/src/main/res/values-be/translations.xml @@ -11,11 +11,11 @@ "Выкарыстоўвайце іншую прыладу" "Чаканне на іншай прыладзе…" "Здаецца, нешта не так. Альбо час чакання запыту скончыўся, альбо запыт быў адхілены." - "Пераканайцеся, што прыведзеныя ніжэй эмодзі супадаюць з эмодзі, паказанымі ў вашым іншым сеансе." + "Пераканайцеся, што эмодзі ніжэй супадаюць з тымі, што паказаны на вашай іншай прыладзе." "Параўнайце эмодзі" "Пераканайцеся, што прыведзеныя ніжэй лічбы супадаюць з лічбамі, паказанымі ў іншым сеансе." "Параўнайце лічбы" - "Ваш новы сеанс пацверджаны. Ён мае доступ да вашых зашыфраваных паведамленняў, і іншыя карыстальнікі будуць лічыць яго давераным." + "Цяпер вы можаце бяспечна чытаць або адпраўляць паведамленні на іншай прыладзе." "Прылада праверана" "Увядзіце ключ аднаўлення" "Дакажыце, што гэта вы, каб атрымаць доступ да вашай зашыфраванай гісторыі паведамленняў." @@ -25,11 +25,11 @@ "Чаканне супадзення" "Параўнайце ўнікальны набор эмодзі." "Параўнайце ўнікальныя эмодзі, пераканаўшыся, што яны размешчаны ў тым жа парадку." - "Ваш новы сеанс пацверджаны. Ён мае доступ да вашых зашыфраваных паведамленняў, і іншыя карыстальнікі будуць лічыць яго давераным." + "Цяпер вы можаце бяспечна чытаць або адпраўляць паведамленні на іншай прыладзе." "Прылада праверана" "Яны не супадаюць" "Яны супадаюць" "Для працягу працы прыміце запыт на запуск працэсу праверкі ў іншым сеансе." "Чаканне прыняцця запыту" - "Выхад…" + "Выдаленне прылады…" diff --git a/features/verifysession/impl/src/main/res/values-in/translations.xml b/features/verifysession/impl/src/main/res/values-in/translations.xml index 05a5bae0ab..7c84cd5d05 100644 --- a/features/verifysession/impl/src/main/res/values-in/translations.xml +++ b/features/verifysession/impl/src/main/res/values-in/translations.xml @@ -2,7 +2,7 @@ "Tidak dapat mengonfirmasi?" "Buat kunci pemulihan baru" - "Verifikasi perangkat ini untuk menyiapkan perpesanan aman." + "Pilih cara verifikasi untuk mengatur pengiriman pesan yang aman." "Konfirmasi bahwa ini Anda" "Gunakan perangkat lain" "Gunakan kunci pemulihan" diff --git a/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml b/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml index 591c482ca6..30db294efa 100644 --- a/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/verifysession/impl/src/main/res/values-pt-rBR/translations.xml @@ -50,5 +50,5 @@ "Depois de aceito, você poderá continuar com a verificação." "Aceite a solicitação para iniciar o processo de verificação na sua outra sessão para continuar." "Aguardando para aceitar a solicitação" - "Saindo…" + "Removendo dispositivo…" diff --git a/features/verifysession/impl/src/main/res/values-ru/translations.xml b/features/verifysession/impl/src/main/res/values-ru/translations.xml index 91974caa1f..d90cd71386 100644 --- a/features/verifysession/impl/src/main/res/values-ru/translations.xml +++ b/features/verifysession/impl/src/main/res/values-ru/translations.xml @@ -6,7 +6,7 @@ "Подтвердите личность" "Использовать другое устройство" "Использовать ключ восстановления" - "Теперь вы можете безопасно читать и отправлять сообщения, и все, с кем вы общаетесь в чате, также могут доверять этому устройству." + "Теперь Вы можете безопасно читать и отправлять сообщения, и все, с кем Вы общаетесь в чате, также могут доверять этому устройству." "Устройство проверено" "Использовать другое устройство" "Ожидание другого устройства…" diff --git a/features/verifysession/impl/src/main/res/values-uk/translations.xml b/features/verifysession/impl/src/main/res/values-uk/translations.xml index 03fe318d13..a81fdd3395 100644 --- a/features/verifysession/impl/src/main/res/values-uk/translations.xml +++ b/features/verifysession/impl/src/main/res/values-uk/translations.xml @@ -2,12 +2,12 @@ "Не можете підтвердити?" "Створити новий ключ відновлення" - "Верифікуйте цей пристрій, щоб налаштувати безпечний обмін повідомленнями." - "Підтвердьте, що це ви" + "Виберіть спосіб звіряння, щоб налаштувати безпечний обмін повідомленнями." + "Підтвердьте свою цифрову ідентичність" "Використовуйте інший пристрій" "Використовуйте ключ відновлення" "Тепер ви можете безпечно читати або надсилати повідомлення, і кожен, з ким ви спілкуєтесь, також може довіряти цьому пристрою." - "Пристрій перевірено" + "Пристрій звірено" "Використовуйте інший пристрій" "Чекає на інше пристрій…" "Щось не так. Або час очікування запиту минув, або в запиті було відмовлено." @@ -17,38 +17,38 @@ "Переконайтеся, що наведені нижче цифри збігаються з тими, що показані під час вашого іншого сеансу." "Порівняйте цифри" "Тепер ви можете безпечно читати або надсилати повідомлення на іншому пристрої." - "Тепер ви можете довіряти особистості цього користувача під час надсилання або отримання повідомлень." - "Пристрій перевірено" + "Відтепер ви можете довіряти цифровій ідентичності цього користувача під час надсилання або отримання повідомлень" + "Пристрій звірено" "Введіть ключ відновлення" - "Або час очікування запиту минув, або запит було відхилено, або виникла розбіжність у верифікації." + "Або час очікування запиту минув, або запит було відхилено, або виникла розбіжність у звірянні." "Доведіть, що це ви, щоб отримати доступ до історії зашифрованих повідомлень." "Відкрийте активний сеанс" - "Повторити верифікацію" + "Повторити звіряння" "У мене все готово" "Очікування збігу" "Порівняйте унікальний набір емоджі." "Порівняйте унікальні емоджі, переконавшись, що вони показані в однаковому порядку." "Увійшов" - "Або час очікування запиту минув, або запит було відхилено, або виникла розбіжність у верифікації." - "Перевірка не вдалася" - "Продовжуйте, лише якщо ви ініціювали цю перевірку." - "Перевірте інший пристрій, щоб захистити історію повідомлень." + "Або час очікування запиту минув, або запит було відхилено, або виникла розбіжність у звірянні." + "Не вдалося звірити" + "Продовжуйте, лише якщо ви ініціювали це звіряння." + "Звірте інший пристрій, щоб захистити історію повідомлень." "Тепер ви можете безпечно читати або надсилати повідомлення на іншому пристрої." - "Пристрій перевірено" - "Запитано на верифікацію" + "Пристрій звірено" + "Запит на звіряння" "Вони не збігаються" "Вони збігаються" - "Перш ніж починати перевірку звідси, переконайтеся, що програму відкрито на іншому пристрої." - "Відкрийте додаток на іншому перевіреному пристрої" - "Для додаткової безпеки верифікуйте цього користувача, порівнявши набір емоджі на ваших пристроях. Зробіть це, використовуючи надійний спосіб спілкування." - "Верифікувати цього користувача?" - "Для додаткової безпеки інший користувач хоче верифікувати вашу особистість. Вам буде показано набір емоджі для порівняння." - "Ви повинні побачити спливаюче вікно на іншому пристрої. Почніть перевірку звідти." - "Почніть перевірку на іншому пристрої" - "Почніть перевірку на іншому пристрої" + "Перш ніж розпочати звіряння звідси, переконайтеся, що ви відкрили застосунок на іншому пристрої." + "Відкрийте застосунок на іншому звіреному пристрої" + "Для додаткової безпеки звірте цього користувача, порівнявши набір емоджі на ваших пристроях. Зробіть це, використовуючи надійний спосіб спілкування." + "Звірити цього користувача?" + "Для додаткової безпеки інший користувач хоче звірити вашу цифрову ідентичність. Вам буде показано набір емодзі для порівняння." + "На іншому пристрої має з’явитися спливне вікно. Розпочніть звіряння звідти." + "Розпочати звіряння на іншому пристрої" + "Розпочати звіряння на іншому пристрої" "Очікування іншого користувача" - "Після погодження ви зможете продовжити верифікацію." - "Щоб продовжити, прийміть запит на початок процесу верифікації в іншому сеансі." + "Після схвалення ви зможете продовжити звіряння." + "Прийміть запит, щоб розпочати процес звіряння в іншому сеансі та продовжити роботу." "Очікування на прийняття запиту" "Видалення пристрою…" diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationViewTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationViewTest.kt index afab77ad76..5947d1d0a5 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationViewTest.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationViewTest.kt @@ -14,18 +14,16 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.verifysession.impl.R import io.element.android.features.verifysession.impl.ui.aEmojisSessionVerificationData import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class IncomingVerificationViewTest { +class IncomingVerificationViewTest : RobolectricTest() { // region step Initial @Test fun `back key pressed - ignore the verification`() = runAndroidComposeUiTest { diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationViewTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationViewTest.kt index 1c96c5c2af..311b9c795e 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationViewTest.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationViewTest.kt @@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.verifysession.impl.R import io.element.android.features.verifysession.impl.ui.aEmojisSessionVerificationData import io.element.android.libraries.architecture.AsyncData @@ -24,11 +23,10 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBackKey +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class OutgoingVerificationViewTest { +class OutgoingVerificationViewTest : RobolectricTest() { @Test fun `back key pressed - when canceled resets the flow`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/gradle.properties b/gradle.properties index ce03899940..4ffc90776d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,10 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 -XX:+UseG1GC +# Matches the heap size CI already uses for release builds (see GRADLE_OPTS in +# .github/workflows/release.yml and nightly.yml) - a local `assembleRelease`/`bundleRelease` +# runs R8 on the full app and can run out of heap well before 4g on this codebase's size. +org.gradle.jvmargs=-Xmx8g -Dfile.encoding=UTF-8 -XX:+UseG1GC # AndroidX package structure to make it clearer which packages are bundled with the # Android operating system, and which are packaged with your app"s APK diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 05530df227..906aa73a85 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,26 +3,26 @@ [versions] # Project -android_gradle_plugin = "8.13.2" +android_gradle_plugin = "9.2.1" # When updating this, please also update the version in the file ./idea/kotlinc.xml -kotlin = "2.3.21" +kotlin = "2.4.0" kotlinpoet = "2.3.0" -ksp = "2.3.8" -firebaseAppDistribution = "5.2.1" +ksp = "2.3.9" +firebaseAppDistribution = "5.3.0" # AndroidX core = "1.18.0" datastore = "1.2.1" constraintlayout = "2.2.1" constraintlayout_compose = "1.1.1" -lifecycle = "2.10.0" +lifecycle = "2.11.0" activity = "1.13.0" media3 = "1.10.1" camera = "1.6.1" work = "2.11.2" # Compose -compose_bom = "2026.05.01" +compose_bom = "2026.06.00" # Coroutines coroutines = "1.11.0" @@ -32,29 +32,29 @@ accompanist = "0.37.3" # Test test_core = "1.7.0" -roborazzi = "1.63.0" +roborazzi = "1.64.0" # Jetbrain datetime = "0.8.0" serialization_json = "1.11.0" #other -coil = "3.4.0" +coil = "3.5.0" # Rollback to 1.0.4, 1.0.5 has this issue: https://github.com/airbnb/Showkase/issues/420 showkase = "1.0.5" # There is some custom logic in `RootFlowNode` that may break because it reuses some Appyx internal APIs. # When upgrading this version, check state restoration still works fine. appyx = "1.7.1" sqldelight = "2.3.2" -wysiwyg = "2.41.3" +wysiwyg = "2.42.0" telephoto = "0.19.0" haze = "1.7.2" # Dependency analysis -dependencyAnalysis = "3.12.0" +dependencyAnalysis = "3.16.0" # DI -metro = "1.1.1" +metro = "1.2.1" # Auto service autoservice = "1.1.1" @@ -84,11 +84,12 @@ kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin kover_gradle_plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } ksp_gradle_plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } # https://firebase.google.com/docs/android/setup#available-libraries -google_firebase_bom = "com.google.firebase:firebase-bom:34.13.0" +google_firebase_bom = "com.google.firebase:firebase-bom:34.15.0" firebase_appdistribution_gradle = { module = "com.google.firebase:firebase-appdistribution-gradle", version.ref = "firebaseAppDistribution" } autonomousapps_dependencyanalysis_plugin = { module = "com.autonomousapps:dependency-analysis-gradle-plugin", version.ref = "dependencyAnalysis" } ksp_plugin = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } -google_tink = "com.google.crypto.tink:tink-android:1.21.0" +google_tink = "com.google.crypto.tink:tink-android:1.22.0" +jna = "net.java.dev.jna:jna:5.19.1" # AndroidX androidx_core = { module = "androidx.core:core", version.ref = "core" } @@ -102,7 +103,7 @@ androidx_constraintlayout_compose = { module = "androidx.constraintlayout:constr androidx_camera_lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camera" } androidx_camera_view = { module = "androidx.camera:camera-view", version.ref = "camera" } androidx_camera_camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camera" } -androidx_javascriptengine = "androidx.javascriptengine:javascriptengine:1.0.0" +androidx_javascriptengine = "androidx.javascriptengine:javascriptengine:1.1.0" androidx_workmanager_runtime = { module = "androidx.work:work-runtime-ktx", version.ref = "work" } androidx_recyclerview = "androidx.recyclerview:recyclerview:1.4.0" @@ -125,10 +126,11 @@ androidx_preference = "androidx.preference:preference:1.2.1" androidx_webkit = "androidx.webkit:webkit:1.16.0" androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" } -androidx_compose_material3 = { module = "androidx.compose.material3:material3", version = '1.5.0-alpha15' } +androidx_compose_material3 = { module = "androidx.compose.material3:material3", version = '1.5.0-alpha22' } androidx_compose_material3_windowsizeclass = { module = "androidx.compose.material3:material3-window-size-class" } androidx_compose_material3_adaptive = "androidx.compose.material3:material3-adaptive-android:1.0.0-alpha06" androidx_compose_ui = { module = "androidx.compose.ui:ui" } +androidx_compose_ui_text = { module = "androidx.compose.ui:ui-text" } androidx_compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling" } androidx_compose_ui_tooling_preview = { module = "androidx.compose.ui:ui-tooling-preview" } androidx_compose_ui_test_manifest = { module = "androidx.compose.ui:ui-test-manifest" } @@ -147,7 +149,7 @@ accompanist_permission = { module = "com.google.accompanist:accompanist-permissi squareup_seismic = "com.squareup:seismic:1.0.3" # network -network_okhttp_bom = "com.squareup.okhttp3:okhttp-bom:5.3.2" +network_okhttp_bom = "com.squareup.okhttp3:okhttp-bom:5.4.0" network_okhttp_logging = { module = "com.squareup.okhttp3:logging-interceptor" } network_okhttp_okhttp = { module = "com.squareup.okhttp3:okhttp" } network_okhttp = { module = "com.squareup.okhttp3:okhttp" } @@ -166,7 +168,7 @@ test_corektx = { module = "androidx.test:core-ktx", version.ref = "test_core" } test_arch_core = "androidx.arch.core:core-testing:2.2.0" test_junit = "junit:junit:4.13.2" test_runner = "androidx.test:runner:1.7.0" -test_mockk = "io.mockk:mockk:1.14.9" +test_mockk = "io.mockk:mockk:1.14.11" test_konsist = "com.lemonappdev:konsist:0.17.3" test_turbine = "app.cash.turbine:turbine:1.2.1" test_truth = "com.google.truth:truth:1.4.5" @@ -183,7 +185,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # All new features should not be implemented in the pull request that upgrades the version, developers should # only fix API breaks and may add some TODOs. -matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.05.26" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.06.30" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } @@ -193,7 +195,7 @@ coil_gif = { module = "io.coil-kt.coil3:coil-gif", version.ref = "coil" } coil_test = { module = "io.coil-kt.coil3:coil-test", version.ref = "coil" } datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" } serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_json" } -kotlinx_collections_immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0" +kotlinx_collections_immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.5.0" showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" } showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" } jsoup = "org.jsoup:jsoup:1.22.2" @@ -207,12 +209,12 @@ sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version. sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" } sqlcipher = "net.zetetic:sqlcipher-android:4.16.0" sqlite = "androidx.sqlite:sqlite-ktx:2.6.2" -unifiedpush = "org.unifiedpush.android:connector:3.3.2" +unifiedpush = "org.unifiedpush.android:connector:3.3.3" vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0" telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil3", version.ref = "telephoto" } telephoto_flick = { module = "me.saket.telephoto:flick-android", version.ref = "telephoto" } statemachine = "com.freeletics.flowredux:compose:1.2.2" -maplibre = "org.maplibre.gl:android-sdk:13.1.0" +maplibre = "org.maplibre.gl:android-sdk:13.3.1" maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:3.0.2" maplibre_compose = "org.maplibre.compose:maplibre-compose:0.13.0" maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:3.0.2" @@ -226,10 +228,10 @@ haze_materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = color_picker = "io.mhssn:colorpicker:1.0.0" # Analytics -posthog = "com.posthog:posthog-android:3.43.0" -sentry = "io.sentry:sentry-android:8.41.0" +posthog = "com.posthog:posthog-android:3.51.1" +sentry = "io.sentry:sentry-android:8.46.0" # main branch can be tested replacing the version with main-SNAPSHOT -matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.33.2" +matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.37.0" # Emojibase matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.5.3" @@ -239,7 +241,7 @@ sigpwned_emoji4j = "com.sigpwned:emoji4j-core:16.0.0" metro_runtime = { module = "dev.zacsweers.metro:runtime", version.ref = "metro" } # Element Call -element_call_embedded = "io.element.android:element-call-embedded:0.20.0" +element_call_embedded = "io.element.android:element-call-embedded:0.20.3" # Auto services google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" } @@ -269,11 +271,11 @@ ktlint = "org.jlleitschuh.gradle.ktlint:14.2.0" dependencygraph = "com.savvasdalkitsis.module-dependency-graph:0.12" dependencycheck = "org.owasp.dependencycheck:12.2.2" dependencyanalysis = { id = "com.autonomousapps.dependency-analysis", version.ref = "dependencyAnalysis" } -paparazzi = "app.cash.paparazzi:2.0.0-alpha04" +paparazzi = "app.cash.paparazzi:2.0.0-alpha05" roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" } sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" } firebaseAppDistribution = { id = "com.google.firebase.appdistribution", version.ref = "firebaseAppDistribution" } -sonarqube = "org.sonarqube:7.3.0.8198" +sonarqube = "org.sonarqube:7.3.1.8318" licensee = "app.cash.licensee:1.14.1" compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } -gms_google_services = { id = "com.google.gms.google-services", version = "4.4.4" } +gms_google_services = { id = "com.google.gms.google-services", version = "4.5.0" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f8e1ee3125..61285a659d 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8a848873f3..4bdb2a9ebd 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=72f44c9f8ebcb1af43838f45ee5c4aa9c5444898b3468ab3f4af7b6076c5bc3f -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +distributionSha256Sum=bafc141b619ad6350fd975fc903156dd5c151998cc8b058e8c1044ab5f7b031f +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/browser/ConsoleMessageLogger.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/browser/ConsoleMessageLogger.kt index d165da8640..18d9990c0b 100644 --- a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/browser/ConsoleMessageLogger.kt +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/browser/ConsoleMessageLogger.kt @@ -33,6 +33,11 @@ class DefaultConsoleMessageLogger : ConsoleMessageLogger { else -> Log.DEBUG } + // Avoid logging any messages that contain "password" to prevent leaking sensitive information + if (consoleMessage.message().contains("password=")) { + return + } + val message = buildString { append(consoleMessage.sourceId()) append(":") @@ -41,20 +46,6 @@ class DefaultConsoleMessageLogger : ConsoleMessageLogger { append(consoleMessage.message()) } - // Avoid logging any messages that contain "password" to prevent leaking sensitive information - if (message.contains("password=")) { - return - } - - Timber.tag(tag).log( - priority = priority, - message = buildString { - append(consoleMessage.sourceId()) - append(":") - append(consoleMessage.lineNumber()) - append(" ") - append(consoleMessage.message()) - }, - ) + Timber.tag(tag).log(priority = priority, message = message) } } diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/DeviceHasVulkanSupport.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/DeviceHasVulkanSupport.kt new file mode 100644 index 0000000000..e8e5edcca0 --- /dev/null +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/DeviceHasVulkanSupport.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.androidutils.system + +import android.content.Context +import dev.zacsweers.metro.Inject +import io.element.android.libraries.di.annotations.ApplicationContext + +private const val VULKAN_VERSION_1_0 = 0x400003 + +/** + * Checks if the device supports Vulkan 1.0. + * + * This is needed for the location screens that contain maps using MapLibre UI components. + * + * Needed until https://github.com/maplibre/maplibre-native/issues/3079 is resolved and we can automatically choose between OpenGL and Vulkan renderers, + * or no devices support OpenGL anymore. + */ +@Inject +class DeviceHasVulkanSupport( + @ApplicationContext private val context: Context, +) { + operator fun invoke(): Boolean { + return context.packageManager.hasSystemFeature("android.hardware.vulkan.version", VULKAN_VERSION_1_0) + } +} diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/ui/View.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/ui/View.kt index 5f19cba136..2d63f12f2e 100644 --- a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/ui/View.kt +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/ui/View.kt @@ -72,6 +72,7 @@ fun View.showKeyboard(andRequestFocus: Boolean = false) { windowInsetsController?.show(WindowInsets.Type.ime()) } else { val imm = context?.getSystemService() + @Suppress("DEPRECATION") imm?.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) } } diff --git a/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/filesize/AndroidFileSizeFormatterTest.kt b/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/filesize/AndroidFileSizeFormatterTest.kt index a83aa7d69f..6168f1017e 100644 --- a/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/filesize/AndroidFileSizeFormatterTest.kt +++ b/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/filesize/AndroidFileSizeFormatterTest.kt @@ -11,14 +11,12 @@ package io.element.android.libraries.androidutils.filesize import android.os.Build import com.google.common.truth.Truth.assertThat import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -@RunWith(RobolectricTestRunner::class) -class AndroidFileSizeFormatterTest { +class AndroidFileSizeFormatterTest : RobolectricTest() { @Config(sdk = [Build.VERSION_CODES.N]) @Test fun `test api 24 long format`() { diff --git a/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/media/VideoCompressorHelperTest.kt b/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/media/VideoCompressorHelperTest.kt index 158dd63845..e954d99dfa 100644 --- a/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/media/VideoCompressorHelperTest.kt +++ b/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/media/VideoCompressorHelperTest.kt @@ -9,13 +9,11 @@ package io.element.android.libraries.androidutils.media import android.util.Size -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class VideoCompressorHelperTest { +class VideoCompressorHelperTest : RobolectricTest() { @Test fun `test getOutputSize`() { val helper = VideoCompressorHelper(maxSize = 720) diff --git a/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/text/LinkifierHelperTest.kt b/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/text/LinkifierHelperTest.kt index 22928781c9..bb7a272908 100644 --- a/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/text/LinkifierHelperTest.kt +++ b/libraries/androidutils/src/test/kotlin/io/element/android/libraries/androidutils/text/LinkifierHelperTest.kt @@ -16,16 +16,14 @@ import androidx.core.text.inSpans import androidx.core.text.toSpannable import com.google.common.truth.Truth.assertThat import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.Shadows.shadowOf import org.robolectric.annotation.Config import org.robolectric.shadow.api.Shadow.newInstanceOf -@RunWith(RobolectricTestRunner::class) -class LinkifierHelperTest { +class LinkifierHelperTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/libraries/compound/screenshots/Compound Icons - Dark.png b/libraries/compound/screenshots/Compound Icons - Dark.png index 2e3fd0d04d..6d5057eaac 100644 --- a/libraries/compound/screenshots/Compound Icons - Dark.png +++ b/libraries/compound/screenshots/Compound Icons - Dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7901fea2f578c8ed796160c9c08f417c61f4fb21580f958844fdf0cb794adf8a -size 239731 +oid sha256:78386a58e91be3213485f60909ec8d83cd535aabcec775aadf7b36e77d8542f0 +size 245853 diff --git a/libraries/compound/screenshots/Compound Icons - Light.png b/libraries/compound/screenshots/Compound Icons - Light.png index 6e1bfc80cd..f4f66317c3 100644 --- a/libraries/compound/screenshots/Compound Icons - Light.png +++ b/libraries/compound/screenshots/Compound Icons - Light.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:245f012d419817f6557d92a71729b3b70092f24f0eba37f2f1fc431ad27592be -size 252969 +oid sha256:477ab18ffa1ca81ca5e4c9f30f4466b19e14fcaddf641fc860c6be19a0e33d4f +size 259185 diff --git a/libraries/compound/screenshots/Compound Icons - Rtl.png b/libraries/compound/screenshots/Compound Icons - Rtl.png index aa1b5d93a7..d0374a65fb 100644 --- a/libraries/compound/screenshots/Compound Icons - Rtl.png +++ b/libraries/compound/screenshots/Compound Icons - Rtl.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d15c52b21cc279d306fa187cd0c318820109b5ec66270e6447e1b02e800eeba -size 254206 +oid sha256:7edeebf9876aecd262fceb7d55a4bfd30a859a69b708af8dd4538ffc0f9be419 +size 260400 diff --git a/libraries/compound/screenshots/Compound Vector Icons - Dark.png b/libraries/compound/screenshots/Compound Vector Icons - Dark.png index a01fbf18b4..0d8e07d9fa 100644 --- a/libraries/compound/screenshots/Compound Vector Icons - Dark.png +++ b/libraries/compound/screenshots/Compound Vector Icons - Dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85ef188fa3a27e42f4beafc899c1f3e7e8bcfad980ed76af6a03f76d70d6a511 -size 93807 +oid sha256:cc6cc2d2e89c7460217c2075046e41bef727407ee422dcdea23f161f48441904 +size 97346 diff --git a/libraries/compound/screenshots/Compound Vector Icons - Light.png b/libraries/compound/screenshots/Compound Vector Icons - Light.png index e227f1579c..74b4c859c7 100644 --- a/libraries/compound/screenshots/Compound Vector Icons - Light.png +++ b/libraries/compound/screenshots/Compound Vector Icons - Light.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6e38386e95dc0c50384f06fca122ce14851ceff8ffc7865e394c1b4fccc5db6 -size 100555 +oid sha256:4df16aee4a3a8b10c33e9724904c72b8dc502725204d2f86cf62cc381b35f4a1 +size 103870 diff --git a/libraries/compound/src/main/assets/theme.iife.js b/libraries/compound/src/main/assets/theme.iife.js index e7205e4f81..41e18ba6a0 100644 --- a/libraries/compound/src/main/assets/theme.iife.js +++ b/libraries/compound/src/main/assets/theme.iife.js @@ -1 +1 @@ -var CompoundTheme=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),c=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;lt[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},l=(e,r,i)=>(i=e==null?{}:t(a(e)),c(r||!e||!e.__esModule?n(i,`default`,{value:e,enumerable:!0}):i,e)),{min:u,max:d}=Math,f=(e,t=0,n=1)=>u(d(t,e),n),p=e=>{e._clipped=!1,e._unclipped=e.slice(0);for(let t=0;t<=3;t++)t<3?((e[t]<0||e[t]>255)&&(e._clipped=!0),e[t]=f(e[t],0,255)):t===3&&(e[t]=f(e[t],0,1));return e},m={};for(let e of[`Boolean`,`Number`,`String`,`Function`,`Array`,`Date`,`RegExp`,`Undefined`,`Null`])m[`[object ${e}]`]=e.toLowerCase();function h(e){return m[Object.prototype.toString.call(e)]||`object`}var g=(e,t=null)=>e.length>=3?Array.prototype.slice.call(e):h(e[0])==`object`&&t?t.split(``).filter(t=>e[0][t]!==void 0).map(t=>e[0][t]):e[0].slice(0),_=e=>{if(e.length<2)return null;let t=e.length-1;return h(e[t])==`string`?e[t].toLowerCase():null},{PI:v,min:y,max:b}=Math,x=e=>Math.round(e*100)/100,S=e=>Math.round(e*100)/100,C=v*2,w=v/3,T=v/180,ee=180/v;function E(e){return[...e.slice(0,3).reverse(),...e.slice(3)]}var D={format:{},autodetect:[]},O=class{constructor(...e){let t=this;if(h(e[0])===`object`&&e[0].constructor&&e[0].constructor===this.constructor)return e[0];let n=_(e),r=!1;if(!n){r=!0,D.sorted||=(D.autodetect=D.autodetect.sort((e,t)=>t.p-e.p),!0);for(let t of D.autodetect)if(n=t.test(...e),n)break}if(D.format[n])t._rgb=p(D.format[n].apply(null,r?e:e.slice(0,-1)));else throw Error(`unknown format: `+e);t._rgb.length===3&&t._rgb.push(1)}toString(){return h(this.hex)==`function`?this.hex():`[${this._rgb.join(`,`)}]`}},te=`3.2.0`,k=(...e)=>new O(...e);k.version=te;var A={aliceblue:`#f0f8ff`,antiquewhite:`#faebd7`,aqua:`#00ffff`,aquamarine:`#7fffd4`,azure:`#f0ffff`,beige:`#f5f5dc`,bisque:`#ffe4c4`,black:`#000000`,blanchedalmond:`#ffebcd`,blue:`#0000ff`,blueviolet:`#8a2be2`,brown:`#a52a2a`,burlywood:`#deb887`,cadetblue:`#5f9ea0`,chartreuse:`#7fff00`,chocolate:`#d2691e`,coral:`#ff7f50`,cornflowerblue:`#6495ed`,cornsilk:`#fff8dc`,crimson:`#dc143c`,cyan:`#00ffff`,darkblue:`#00008b`,darkcyan:`#008b8b`,darkgoldenrod:`#b8860b`,darkgray:`#a9a9a9`,darkgreen:`#006400`,darkgrey:`#a9a9a9`,darkkhaki:`#bdb76b`,darkmagenta:`#8b008b`,darkolivegreen:`#556b2f`,darkorange:`#ff8c00`,darkorchid:`#9932cc`,darkred:`#8b0000`,darksalmon:`#e9967a`,darkseagreen:`#8fbc8f`,darkslateblue:`#483d8b`,darkslategray:`#2f4f4f`,darkslategrey:`#2f4f4f`,darkturquoise:`#00ced1`,darkviolet:`#9400d3`,deeppink:`#ff1493`,deepskyblue:`#00bfff`,dimgray:`#696969`,dimgrey:`#696969`,dodgerblue:`#1e90ff`,firebrick:`#b22222`,floralwhite:`#fffaf0`,forestgreen:`#228b22`,fuchsia:`#ff00ff`,gainsboro:`#dcdcdc`,ghostwhite:`#f8f8ff`,gold:`#ffd700`,goldenrod:`#daa520`,gray:`#808080`,green:`#008000`,greenyellow:`#adff2f`,grey:`#808080`,honeydew:`#f0fff0`,hotpink:`#ff69b4`,indianred:`#cd5c5c`,indigo:`#4b0082`,ivory:`#fffff0`,khaki:`#f0e68c`,laserlemon:`#ffff54`,lavender:`#e6e6fa`,lavenderblush:`#fff0f5`,lawngreen:`#7cfc00`,lemonchiffon:`#fffacd`,lightblue:`#add8e6`,lightcoral:`#f08080`,lightcyan:`#e0ffff`,lightgoldenrod:`#fafad2`,lightgoldenrodyellow:`#fafad2`,lightgray:`#d3d3d3`,lightgreen:`#90ee90`,lightgrey:`#d3d3d3`,lightpink:`#ffb6c1`,lightsalmon:`#ffa07a`,lightseagreen:`#20b2aa`,lightskyblue:`#87cefa`,lightslategray:`#778899`,lightslategrey:`#778899`,lightsteelblue:`#b0c4de`,lightyellow:`#ffffe0`,lime:`#00ff00`,limegreen:`#32cd32`,linen:`#faf0e6`,magenta:`#ff00ff`,maroon:`#800000`,maroon2:`#7f0000`,maroon3:`#b03060`,mediumaquamarine:`#66cdaa`,mediumblue:`#0000cd`,mediumorchid:`#ba55d3`,mediumpurple:`#9370db`,mediumseagreen:`#3cb371`,mediumslateblue:`#7b68ee`,mediumspringgreen:`#00fa9a`,mediumturquoise:`#48d1cc`,mediumvioletred:`#c71585`,midnightblue:`#191970`,mintcream:`#f5fffa`,mistyrose:`#ffe4e1`,moccasin:`#ffe4b5`,navajowhite:`#ffdead`,navy:`#000080`,oldlace:`#fdf5e6`,olive:`#808000`,olivedrab:`#6b8e23`,orange:`#ffa500`,orangered:`#ff4500`,orchid:`#da70d6`,palegoldenrod:`#eee8aa`,palegreen:`#98fb98`,paleturquoise:`#afeeee`,palevioletred:`#db7093`,papayawhip:`#ffefd5`,peachpuff:`#ffdab9`,peru:`#cd853f`,pink:`#ffc0cb`,plum:`#dda0dd`,powderblue:`#b0e0e6`,purple:`#800080`,purple2:`#7f007f`,purple3:`#a020f0`,rebeccapurple:`#663399`,red:`#ff0000`,rosybrown:`#bc8f8f`,royalblue:`#4169e1`,saddlebrown:`#8b4513`,salmon:`#fa8072`,sandybrown:`#f4a460`,seagreen:`#2e8b57`,seashell:`#fff5ee`,sienna:`#a0522d`,silver:`#c0c0c0`,skyblue:`#87ceeb`,slateblue:`#6a5acd`,slategray:`#708090`,slategrey:`#708090`,snow:`#fffafa`,springgreen:`#00ff7f`,steelblue:`#4682b4`,tan:`#d2b48c`,teal:`#008080`,thistle:`#d8bfd8`,tomato:`#ff6347`,turquoise:`#40e0d0`,violet:`#ee82ee`,wheat:`#f5deb3`,white:`#ffffff`,whitesmoke:`#f5f5f5`,yellow:`#ffff00`,yellowgreen:`#9acd32`},ne=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,re=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,ie=e=>{if(e.match(ne)){(e.length===4||e.length===7)&&(e=e.substr(1)),e.length===3&&(e=e.split(``),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);let t=parseInt(e,16);return[t>>16,t>>8&255,t&255,1]}if(e.match(re)){(e.length===5||e.length===9)&&(e=e.substr(1)),e.length===4&&(e=e.split(``),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]);let t=parseInt(e,16);return[t>>24&255,t>>16&255,t>>8&255,Math.round((t&255)/255*100)/100]}throw Error(`unknown hex color: ${e}`)},{round:ae}=Math,oe=(...e)=>{let[t,n,r,i]=g(e,`rgba`),a=_(e)||`auto`;i===void 0&&(i=1),a===`auto`&&(a=i<1?`rgba`:`rgb`),t=ae(t),n=ae(n),r=ae(r);let o=`000000`+(t<<16|n<<8|r).toString(16);o=o.substr(o.length-6);let s=`0`+ae(i*255).toString(16);switch(s=s.substr(s.length-2),a.toLowerCase()){case`rgba`:return`#${o}${s}`;case`argb`:return`#${s}${o}`;default:return`#${o}`}};O.prototype.name=function(){let e=oe(this._rgb,`rgb`);for(let t of Object.keys(A))if(A[t]===e)return t.toLowerCase();return e},D.format.named=e=>{if(e=e.toLowerCase(),A[e])return ie(A[e]);throw Error(`unknown color name: `+e)},D.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&h(e)===`string`&&A[e.toLowerCase()])return`named`}}),O.prototype.alpha=function(e,t=!1){return e!==void 0&&h(e)===`number`?t?(this._rgb[3]=e,this):new O([this._rgb[0],this._rgb[1],this._rgb[2],e],`rgb`):this._rgb[3]},O.prototype.clipped=function(){return this._rgb._clipped||!1};var j={Kn:18,labWhitePoint:`d65`,Xn:.95047,Yn:1,Zn:1.08883,t0:.137931034,t1:.206896552,t2:.12841855,t3:.008856452,kE:216/24389,kKE:8,kK:24389/27,RefWhiteRGB:{X:.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:.4124564390896922,m01:.21267285140562253,m02:.0193338955823293,m10:.357576077643909,m11:.715152155287818,m12:.11919202588130297,m20:.18043748326639894,m21:.07217499330655958,m22:.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-.9692660305051868,m02:.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-.2040259135167538,m20:-.498531409556016,m21:.041556017530349834,m22:1.0572251882231791},As:.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:.8951,m01:-.7502,m02:.0389,m10:.2664,m11:1.7135,m12:-.0685,m20:-.1614,m21:.0367,m22:1.0296},MtxAdaptMaI:{m00:.9869929054667123,m01:.43230526972339456,m02:-.008528664575177328,m10:-.14705425642099013,m11:.5183602715367776,m12:.04004282165408487,m20:.15996265166373125,m21:.0492912282128556,m22:.9684866957875502}},se=new Map([[`a`,[1.0985,.35585]],[`b`,[1.0985,.35585]],[`c`,[.98074,1.18232]],[`d50`,[.96422,.82521]],[`d55`,[.95682,.92149]],[`d65`,[.95047,1.08883]],[`e`,[1,1,1]],[`f2`,[.99186,.67393]],[`f7`,[.95041,1.08747]],[`f11`,[1.00962,.6435]],[`icc`,[.96422,.82521]]]);function M(e){let t=se.get(String(e).toLowerCase());if(!t)throw Error(`unknown Lab illuminant `+e);j.labWhitePoint=e,j.Xn=t[0],j.Zn=t[1]}function ce(){return j.labWhitePoint}var N=(...e)=>{e=g(e,`lab`);let[t,n,r]=e,[i,a,o]=le(t,n,r),[s,c,l]=de(i,a,o);return[s,c,l,e.length>3?e[3]:1]},le=(e,t,n)=>{let{kE:r,kK:i,kKE:a,Xn:o,Yn:s,Zn:c}=j,l=(e+16)/116,u=.002*t+l,d=l-.005*n,f=u*u*u,p=d*d*d,m=f>r?f:(116*u-16)/i,h=e>a?((e+16)/116)**3:e/i,g=p>r?p:(116*d-16)/i;return[m*o,h*s,g*c]},ue=e=>{let t=Math.sign(e);return e=Math.abs(e),(e<=.0031308?e*12.92:1.055*e**(1/2.4)-.055)*t},de=(e,t,n)=>{let{MtxAdaptMa:r,MtxAdaptMaI:i,MtxXYZ2RGB:a,RefWhiteRGB:o,Xn:s,Yn:c,Zn:l}=j,u=s*r.m00+c*r.m10+l*r.m20,d=s*r.m01+c*r.m11+l*r.m21,f=s*r.m02+c*r.m12+l*r.m22,p=o.X*r.m00+o.Y*r.m10+o.Z*r.m20,m=o.X*r.m01+o.Y*r.m11+o.Z*r.m21,h=o.X*r.m02+o.Y*r.m12+o.Z*r.m22,g=(e*r.m00+t*r.m10+n*r.m20)*(p/u),_=(e*r.m01+t*r.m11+n*r.m21)*(m/d),v=(e*r.m02+t*r.m12+n*r.m22)*(h/f),y=g*i.m00+_*i.m10+v*i.m20,b=g*i.m01+_*i.m11+v*i.m21,x=g*i.m02+_*i.m12+v*i.m22,S=ue(y*a.m00+b*a.m10+x*a.m20),C=ue(y*a.m01+b*a.m11+x*a.m21),w=ue(y*a.m02+b*a.m12+x*a.m22);return[S*255,C*255,w*255]},fe=(...e)=>{let[t,n,r,...i]=g(e,`rgb`),[a,o,s]=he(t,n,r),[c,l,u]=pe(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]};function pe(e,t,n){let{Xn:r,Yn:i,Zn:a,kE:o,kK:s}=j,c=e/r,l=t/i,u=n/a,d=c>o?c**(1/3):(s*c+16)/116,f=l>o?l**(1/3):(s*l+16)/116,p=u>o?u**(1/3):(s*u+16)/116;return[116*f-16,500*(d-f),200*(f-p)]}function me(e){let t=Math.sign(e);return e=Math.abs(e),(e<=.04045?e/12.92:((e+.055)/1.055)**2.4)*t}var he=(e,t,n)=>{e=me(e/255),t=me(t/255),n=me(n/255);let{MtxRGB2XYZ:r,MtxAdaptMa:i,MtxAdaptMaI:a,Xn:o,Yn:s,Zn:c,As:l,Bs:u,Cs:d}=j,f=e*r.m00+t*r.m10+n*r.m20,p=e*r.m01+t*r.m11+n*r.m21,m=e*r.m02+t*r.m12+n*r.m22,h=o*i.m00+s*i.m10+c*i.m20,g=o*i.m01+s*i.m11+c*i.m21,_=o*i.m02+s*i.m12+c*i.m22,v=f*i.m00+p*i.m10+m*i.m20,y=f*i.m01+p*i.m11+m*i.m21,b=f*i.m02+p*i.m12+m*i.m22;return v*=h/l,y*=g/u,b*=_/d,f=v*a.m00+y*a.m10+b*a.m20,p=v*a.m01+y*a.m11+b*a.m21,m=v*a.m02+y*a.m12+b*a.m22,[f,p,m]};O.prototype.lab=function(){return fe(this._rgb)},Object.assign(k,{lab:(...e)=>new O(...e,`lab`),getLabWhitePoint:ce,setLabWhitePoint:M}),D.format.lab=N,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`lab`),h(e)===`array`&&e.length===3)return`lab`}}),O.prototype.darken=function(e=1){let t=this,n=t.lab();return n[0]-=j.Kn*e,new O(n,`lab`).alpha(t.alpha(),!0)},O.prototype.brighten=function(e=1){return this.darken(-e)},O.prototype.darker=O.prototype.darken,O.prototype.brighter=O.prototype.brighten,O.prototype.get=function(e){let[t,n]=e.split(`.`),r=this[t]();if(n){let e=t.indexOf(n)-(t.substr(0,2)===`ok`?2:0);if(e>-1)return r[e];throw Error(`unknown channel ${n} in mode ${t}`)}else return r};var{pow:ge}=Math,_e=1e-7,ve=20;O.prototype.luminance=function(e,t=`rgb`){if(e!==void 0&&h(e)===`number`){if(e===0)return new O([0,0,0,this._rgb[3]],`rgb`);if(e===1)return new O([255,255,255,this._rgb[3]],`rgb`);let n=this.luminance(),r=ve,i=(n,a)=>{let o=n.interpolate(a,.5,t),s=o.luminance();return Math.abs(e-s)<_e||!r--?o:s>e?i(n,o):i(o,a)};return new O([...(n>e?i(new O([0,0,0]),this):i(this,new O([255,255,255]))).rgb(),this._rgb[3]])}return ye(...this._rgb.slice(0,3))};var ye=(e,t,n)=>(e=be(e),t=be(t),n=be(n),.2126*e+.7152*t+.0722*n),be=e=>(e/=255,e<=.03928?e/12.92:ge((e+.055)/1.055,2.4)),P={},F=(e,t,n=.5,...r)=>{let i=r[0]||`lrgb`;if(!P[i]&&!r.length&&(i=Object.keys(P)[0]),!P[i])throw Error(`interpolation mode ${i} is not defined`);return h(e)!==`object`&&(e=new O(e)),h(t)!==`object`&&(t=new O(t)),P[i](e,t,n).alpha(e.alpha()+n*(t.alpha()-e.alpha()))};O.prototype.mix=O.prototype.interpolate=function(e,t=.5,...n){return F(this,e,t,...n)},O.prototype.premultiply=function(e=!1){let t=this._rgb,n=t[3];return e?(this._rgb=[t[0]*n,t[1]*n,t[2]*n,n],this):new O([t[0]*n,t[1]*n,t[2]*n,n],`rgb`)};var{sin:xe,cos:Se}=Math,Ce=(...e)=>{let[t,n,r]=g(e,`lch`);return isNaN(r)&&(r=0),r*=T,[t,Se(r)*n,xe(r)*n]},we=(...e)=>{e=g(e,`lch`);let[t,n,r]=e,[i,a,o]=Ce(t,n,r),[s,c,l]=N(i,a,o);return[s,c,l,e.length>3?e[3]:1]},Te=(...e)=>we(...E(g(e,`hcl`))),{sqrt:Ee,atan2:De,round:Oe}=Math,ke=(...e)=>{let[t,n,r]=g(e,`lab`),i=Ee(n*n+r*r),a=(De(r,n)*ee+360)%360;return Oe(i*1e4)===0&&(a=NaN),[t,i,a]},Ae=(...e)=>{let[t,n,r,...i]=g(e,`rgb`),[a,o,s]=fe(t,n,r),[c,l,u]=ke(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]};O.prototype.lch=function(){return Ae(this._rgb)},O.prototype.hcl=function(){return E(Ae(this._rgb))},Object.assign(k,{lch:(...e)=>new O(...e,`lch`),hcl:(...e)=>new O(...e,`hcl`)}),D.format.lch=we,D.format.hcl=Te,[`lch`,`hcl`].forEach(e=>D.autodetect.push({p:2,test:(...t)=>{if(t=g(t,e),h(t)===`array`&&t.length===3)return e}})),O.prototype.saturate=function(e=1){let t=this,n=t.lch();return n[1]+=j.Kn*e,n[1]<0&&(n[1]=0),new O(n,`lch`).alpha(t.alpha(),!0)},O.prototype.desaturate=function(e=1){return this.saturate(-e)},O.prototype.set=function(e,t,n=!1){let[r,i]=e.split(`.`),a=this[r]();if(i){let e=r.indexOf(i)-(r.substr(0,2)===`ok`?2:0);if(e>-1){if(h(t)==`string`)switch(t.charAt(0)){case`+`:a[e]+=+t;break;case`-`:a[e]+=+t;break;case`*`:a[e]*=+t.substr(1);break;case`/`:a[e]/=+t.substr(1);break;default:a[e]=+t}else if(h(t)===`number`)a[e]=t;else throw Error(`unsupported value for Color.set`);let i=new O(a,r);return n?(this._rgb=i._rgb,this):i}throw Error(`unknown channel ${i} in mode ${r}`)}else return a},O.prototype.tint=function(e=.5,...t){return F(this,`white`,e,...t)},O.prototype.shade=function(e=.5,...t){return F(this,`black`,e,...t)},P.rgb=(e,t,n)=>{let r=e._rgb,i=t._rgb;return new O(r[0]+n*(i[0]-r[0]),r[1]+n*(i[1]-r[1]),r[2]+n*(i[2]-r[2]),`rgb`)};var{sqrt:je,pow:Me}=Math;P.lrgb=(e,t,n)=>{let[r,i,a]=e._rgb,[o,s,c]=t._rgb;return new O(je(Me(r,2)*(1-n)+Me(o,2)*n),je(Me(i,2)*(1-n)+Me(s,2)*n),je(Me(a,2)*(1-n)+Me(c,2)*n),`rgb`)},P.lab=(e,t,n)=>{let r=e.lab(),i=t.lab();return new O(r[0]+n*(i[0]-r[0]),r[1]+n*(i[1]-r[1]),r[2]+n*(i[2]-r[2]),`lab`)};var Ne=(e,t,n,r)=>{let i,a;r===`hsl`?(i=e.hsl(),a=t.hsl()):r===`hsv`?(i=e.hsv(),a=t.hsv()):r===`hcg`?(i=e.hcg(),a=t.hcg()):r===`hsi`?(i=e.hsi(),a=t.hsi()):r===`lch`||r===`hcl`?(r=`hcl`,i=e.hcl(),a=t.hcl()):r===`oklch`&&(i=e.oklch().reverse(),a=t.oklch().reverse());let o,s,c,l,u,d;(r.substr(0,1)===`h`||r===`oklch`)&&([o,c,u]=i,[s,l,d]=a);let f,p,m,h;return!isNaN(o)&&!isNaN(s)?(h=s>o&&s-o>180?s-(o+360):s180?s+360-o:s-o,p=o+n*h):isNaN(o)?isNaN(s)?p=NaN:(p=s,(u==1||u==0)&&r!=`hsv`&&(f=l)):(p=o,(d==1||d==0)&&r!=`hsv`&&(f=c)),f===void 0&&(f=c+n*(l-c)),m=u+n*(d-u),r===`oklch`?new O([m,f,p],r):new O([p,f,m],r)},Pe=(e,t,n)=>Ne(e,t,n,`lch`);P.lch=Pe,P.hcl=Pe;var Fe=e=>{if(h(e)==`number`&&e>=0&&e<=16777215)return[e>>16,e>>8&255,e&255,1];throw Error(`unknown num color: `+e)},Ie=(...e)=>{let[t,n,r]=g(e,`rgb`);return(t<<16)+(n<<8)+r};O.prototype.num=function(){return Ie(this._rgb)},Object.assign(k,{num:(...e)=>new O(...e,`num`)}),D.format.num=Fe,D.autodetect.push({p:5,test:(...e)=>{if(e.length===1&&h(e[0])===`number`&&e[0]>=0&&e[0]<=16777215)return`num`}}),P.num=(e,t,n)=>{let r=e.num();return new O(r+n*(t.num()-r),`num`)};var{floor:Le}=Math,Re=(...e)=>{e=g(e,`hcg`);let[t,n,r]=e,i,a,o;r*=255;let s=n*255;if(n===0)i=a=o=r;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;let e=Le(t),c=t-e,l=r*(1-n),u=l+s*(1-c),d=l+s*c,f=l+s;switch(e){case 0:[i,a,o]=[f,d,l];break;case 1:[i,a,o]=[u,f,l];break;case 2:[i,a,o]=[l,f,d];break;case 3:[i,a,o]=[l,u,f];break;case 4:[i,a,o]=[d,l,f];break;case 5:[i,a,o]=[f,l,u];break}}return[i,a,o,e.length>3?e[3]:1]},ze=(...e)=>{let[t,n,r]=g(e,`rgb`),i=y(t,n,r),a=b(t,n,r),o=a-i,s=o*100/255,c=i/(255-o)*100,l;return o===0?l=NaN:(t===a&&(l=(n-r)/o),n===a&&(l=2+(r-t)/o),r===a&&(l=4+(t-n)/o),l*=60,l<0&&(l+=360)),[l,s,c]};O.prototype.hcg=function(){return ze(this._rgb)},k.hcg=(...e)=>new O(...e,`hcg`),D.format.hcg=Re,D.autodetect.push({p:1,test:(...e)=>{if(e=g(e,`hcg`),h(e)===`array`&&e.length===3)return`hcg`}}),P.hcg=(e,t,n)=>Ne(e,t,n,`hcg`);var{cos:Be}=Math,Ve=(...e)=>{e=g(e,`hsi`);let[t,n,r]=e,i,a,o;return isNaN(t)&&(t=0),isNaN(n)&&(n=0),t>360&&(t-=360),t<0&&(t+=360),t/=360,t<1/3?(o=(1-n)/3,i=(1+n*Be(C*t)/Be(w-C*t))/3,a=1-(o+i)):t<2/3?(t-=1/3,i=(1-n)/3,a=(1+n*Be(C*t)/Be(w-C*t))/3,o=1-(i+a)):(t-=2/3,a=(1-n)/3,o=(1+n*Be(C*t)/Be(w-C*t))/3,i=1-(a+o)),i=f(r*i*3),a=f(r*a*3),o=f(r*o*3),[i*255,a*255,o*255,e.length>3?e[3]:1]},{min:He,sqrt:Ue,acos:We}=Math,Ge=(...e)=>{let[t,n,r]=g(e,`rgb`);t/=255,n/=255,r/=255;let i,a=He(t,n,r),o=(t+n+r)/3,s=o>0?1-a/o:0;return s===0?i=NaN:(i=(t-n+(t-r))/2,i/=Ue((t-n)*(t-n)+(t-r)*(n-r)),i=We(i),r>n&&(i=C-i),i/=C),[i*360,s,o]};O.prototype.hsi=function(){return Ge(this._rgb)},k.hsi=(...e)=>new O(...e,`hsi`),D.format.hsi=Ve,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`hsi`),h(e)===`array`&&e.length===3)return`hsi`}}),P.hsi=(e,t,n)=>Ne(e,t,n,`hsi`);var Ke=(...e)=>{e=g(e,`hsl`);let[t,n,r]=e,i,a,o;if(n===0)i=a=o=r*255;else{let e=[0,0,0],s=[0,0,0],c=r<.5?r*(1+n):r+n-r*n,l=2*r-c,u=t/360;e[0]=u+1/3,e[1]=u,e[2]=u-1/3;for(let t=0;t<3;t++)e[t]<0&&(e[t]+=1),e[t]>1&&--e[t],6*e[t]<1?s[t]=l+(c-l)*6*e[t]:2*e[t]<1?s[t]=c:3*e[t]<2?s[t]=l+(c-l)*(2/3-e[t])*6:s[t]=l;[i,a,o]=[s[0]*255,s[1]*255,s[2]*255]}return e.length>3?[i,a,o,e[3]]:[i,a,o,1]},qe=(...e)=>{e=g(e,`rgba`);let[t,n,r]=e;t/=255,n/=255,r/=255;let i=y(t,n,r),a=b(t,n,r),o=(a+i)/2,s,c;return a===i?(s=0,c=NaN):s=o<.5?(a-i)/(a+i):(a-i)/(2-a-i),t==a?c=(n-r)/(a-i):n==a?c=2+(r-t)/(a-i):r==a&&(c=4+(t-n)/(a-i)),c*=60,c<0&&(c+=360),e.length>3&&e[3]!==void 0?[c,s,o,e[3]]:[c,s,o]};O.prototype.hsl=function(){return qe(this._rgb)},k.hsl=(...e)=>new O(...e,`hsl`),D.format.hsl=Ke,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`hsl`),h(e)===`array`&&e.length===3)return`hsl`}}),P.hsl=(e,t,n)=>Ne(e,t,n,`hsl`);var{floor:Je}=Math,Ye=(...e)=>{e=g(e,`hsv`);let[t,n,r]=e,i,a,o;if(r*=255,n===0)i=a=o=r;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;let e=Je(t),s=t-e,c=r*(1-n),l=r*(1-n*s),u=r*(1-n*(1-s));switch(e){case 0:[i,a,o]=[r,u,c];break;case 1:[i,a,o]=[l,r,c];break;case 2:[i,a,o]=[c,r,u];break;case 3:[i,a,o]=[c,l,r];break;case 4:[i,a,o]=[u,c,r];break;case 5:[i,a,o]=[r,c,l];break}}return[i,a,o,e.length>3?e[3]:1]},{min:Xe,max:Ze}=Math,Qe=(...e)=>{e=g(e,`rgb`);let[t,n,r]=e,i=Xe(t,n,r),a=Ze(t,n,r),o=a-i,s,c,l;return l=a/255,a===0?(s=NaN,c=0):(c=o/a,t===a&&(s=(n-r)/o),n===a&&(s=2+(r-t)/o),r===a&&(s=4+(t-n)/o),s*=60,s<0&&(s+=360)),[s,c,l]};O.prototype.hsv=function(){return Qe(this._rgb)},k.hsv=(...e)=>new O(...e,`hsv`),D.format.hsv=Ye,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`hsv`),h(e)===`array`&&e.length===3)return`hsv`}}),P.hsv=(e,t,n)=>Ne(e,t,n,`hsv`);function $e(e,t){let n=e.length;Array.isArray(e[0])||(e=[e]),Array.isArray(t[0])||(t=t.map(e=>[e]));let r=t[0].length,i=t[0].map((e,n)=>t.map(e=>e[n])),a=e.map(e=>i.map(t=>Array.isArray(e)?e.reduce((e,n,r)=>e+n*(t[r]||0),0):t.reduce((t,n)=>t+n*e,0)));return n===1&&(a=a[0]),r===1?a.map(e=>e[0]):a}var et=(...e)=>{e=g(e,`lab`);let[t,n,r,...i]=e,[a,o,s]=tt([t,n,r]),[c,l,u]=de(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]};function tt(e){return $e([[1.2268798758459243,-.5578149944602171,.2813910456659647],[-.0405757452148008,1.112286803280317,-.0717110580655164],[-.0763729366746601,-.4214933324022432,1.5869240198367816]],$e([[1,.3963377773761749,.2158037573099136],[1,-.1055613458156586,-.0638541728258133],[1,-.0894841775298119,-1.2914855480194092]],e).map(e=>e**3))}var nt=(...e)=>{let[t,n,r,...i]=g(e,`rgb`);return[...rt(he(t,n,r)),...i.length>0&&i[0]<1?[i[0]]:[]]};function rt(e){return $e([[.210454268309314,.7936177747023054,-.0040720430116193],[1.9779985324311684,-2.42859224204858,.450593709617411],[.0259040424655478,.7827717124575296,-.8086757549230774]],$e([[.819022437996703,.3619062600528904,-.1288737815209879],[.0329836539323885,.9292868615863434,.0361446663506424],[.0481771893596242,.2642395317527308,.6335478284694309]],e).map(e=>Math.cbrt(e)))}O.prototype.oklab=function(){return nt(this._rgb)},Object.assign(k,{oklab:(...e)=>new O(...e,`oklab`)}),D.format.oklab=et,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`oklab`),h(e)===`array`&&e.length===3)return`oklab`}}),P.oklab=(e,t,n)=>{let r=e.oklab(),i=t.oklab();return new O(r[0]+n*(i[0]-r[0]),r[1]+n*(i[1]-r[1]),r[2]+n*(i[2]-r[2]),`oklab`)},P.oklch=(e,t,n)=>Ne(e,t,n,`oklch`);var{pow:it,sqrt:at,PI:ot,cos:st,sin:ct,atan2:lt}=Math,ut=(e,t=`lrgb`,n=null)=>{let r=e.length;n||=Array.from(Array(r)).map(()=>1);let i=r/n.reduce(function(e,t){return e+t});if(n.forEach((e,t)=>{n[t]*=i}),e=e.map(e=>new O(e)),t===`lrgb`)return dt(e,n);let a=e.shift(),o=a.get(t),s=[],c=0,l=0;for(let e=0;e{let i=e.get(t);u+=e.alpha()*n[r+1];for(let e=0;e=360;)t-=360;o[e]=t}else o[e]=o[e]/s[e];return u/=r,new O(o,t).alpha(u>.99999?1:u,!0)},dt=(e,t)=>{let n=e.length,r=[0,0,0,0];for(let i=0;i.9999999&&(r[3]=1),new O(p(r))},{pow:ft}=Math;function pt(e){let t=`rgb`,n=k(`#ccc`),r=0,i=[0,1],a=[0,1],o=[],s=[0,0],c=!1,l=[],u=!1,d=0,p=1,m=!1,g={},_=!0,v=1,y=function(e){if(e||=[`#fff`,`#000`],e&&h(e)===`string`&&k.brewer&&k.brewer[e.toLowerCase()]&&(e=k.brewer[e.toLowerCase()]),h(e)===`array`){e.length===1&&(e=[e[0],e[0]]),e=e.slice(0);for(let t=0;t=c[n];)n++;return n-1}return 0},x=e=>e,S=e=>e,C=function(e,r){let i,a;if(r??=!1,isNaN(e)||e===null)return n;a=r?e:c&&c.length>2?b(e)/(c.length-2):p===d?1:(e-d)/(p-d),a=S(a),r||(a=x(a)),v!==1&&(a=ft(a,v)),a=s[0]+a*(1-s[0]-s[1]),a=f(a,0,1);let u=Math.floor(a*1e4);if(_&&g[u])i=g[u];else{if(h(l)===`array`)for(let e=0;e=n&&e===o.length-1){i=l[e];break}if(a>n&&ag={};y(e);let T=function(e){let t=k(C(e));return u&&t[u]?t[u]():t};return T.classes=function(e){if(e!=null){if(h(e)===`array`)c=e,i=[e[0],e[e.length-1]];else{let t=k.analyze(i);c=e===0?[t.min,t.max]:k.limits(t,`e`,e)}return T}return c},T.domain=function(e){if(!arguments.length)return a;a=e.slice(0),d=e[0],p=e[e.length-1],o=[];let t=l.length;if(e.length===t&&d!==p)for(let t of Array.from(e))o.push((t-d)/(p-d));else{for(let e=0;e2){let t=e.map((t,n)=>n/(e.length-1)),n=e.map(e=>(e-d)/(p-d));n.every((e,n)=>t[n]===e)||(S=e=>{if(e<=0||e>=1)return e;let r=0;for(;e>=n[r+1];)r++;let i=(e-n[r])/(n[r+1]-n[r]);return t[r]+i*(t[r+1]-t[r])})}}return i=[d,p],T},T.mode=function(e){return arguments.length?(t=e,w(),T):t},T.range=function(e,t){return y(e,t),T},T.out=function(e){return u=e,T},T.spread=function(e){return arguments.length?(r=e,T):r},T.correctLightness=function(e){return e??=!0,m=e,w(),x=m?function(e){let t=C(0,!0).lab()[0],n=C(1,!0).lab()[0],r=t>n,i=C(e,!0).lab()[0],a=t+(n-t)*e,o=i-a,s=0,c=1,l=20;for(;Math.abs(o)>.01&&l-- >0;)(function(){return r&&(o*=-1),o<0?(s=e,e+=(c-e)*.5):(c=e,e+=(s-e)*.5),i=C(e,!0).lab()[0],o=i-a})();return e}:e=>e,T},T.padding=function(e){return e==null?s:(h(e)===`number`&&(e=[e,e]),s=e,T)},T.colors=function(t,n){arguments.length<2&&(n=`hex`);let r=[];if(arguments.length===0)r=l.slice(0);else if(t===1)r=[T(.5)];else if(t>1){let e=i[0],n=i[1]-e;r=mt(0,t,!1).map(r=>T(e+r/(t-1)*n))}else{e=[];let t=[];if(c&&c.length>2)for(let e=1,n=c.length,r=1<=n;r?en;r?e++:e--)t.push((c[e-1]+c[e])*.5);else t=i;r=t.map(e=>T(e))}return k[n]&&(r=r.map(e=>e[n]())),r},T.cache=function(e){return e==null?_:(_=e,T)},T.gamma=function(e){return e==null?v:(v=e,T)},T.nodata=function(e){return e==null?n:(n=k(e),T)},T}function mt(e,t,n){let r=[],i=ea;i?t++:t--)r.push(t);return r}var ht=function(e){let t=[1,1];for(let n=1;nnew O(e)),e.length===2)[n,r]=e.map(e=>e.lab()),t=function(e){return new O([0,1,2].map(t=>n[t]+e*(r[t]-n[t])),`lab`)};else if(e.length===3)[n,r,i]=e.map(e=>e.lab()),t=function(e){return new O([0,1,2].map(t=>(1-e)*(1-e)*n[t]+2*(1-e)*e*r[t]+e*e*i[t]),`lab`)};else if(e.length===4){let a;[n,r,i,a]=e.map(e=>e.lab()),t=function(e){return new O([0,1,2].map(t=>(1-e)*(1-e)*(1-e)*n[t]+3*(1-e)*(1-e)*e*r[t]+3*(1-e)*e*e*i[t]+e*e*e*a[t]),`lab`)}}else if(e.length>=5){let n,r,i;n=e.map(e=>e.lab()),i=e.length-1,r=ht(i),t=function(e){let t=1-e;return new O([0,1,2].map(a=>n.reduce((n,o,s)=>n+r[s]*t**(i-s)*e**s*o[a],0)),`lab`)}}else throw RangeError(`No point in running bezier with only one color.`);return t},_t=e=>{let t=gt(e);return t.scale=()=>pt(t),t},{round:vt}=Math;O.prototype.rgb=function(e=!0){return e===!1?this._rgb.slice(0,3):this._rgb.slice(0,3).map(vt)},O.prototype.rgba=function(e=!0){return this._rgb.slice(0,4).map((t,n)=>n<3?e===!1?t:vt(t):t)},Object.assign(k,{rgb:(...e)=>new O(...e,`rgb`)}),D.format.rgb=(...e)=>{let t=g(e,`rgba`);return t[3]===void 0&&(t[3]=1),t},D.autodetect.push({p:3,test:(...e)=>{if(e=g(e,`rgba`),h(e)===`array`&&(e.length===3||e.length===4&&h(e[3])==`number`&&e[3]>=0&&e[3]<=1))return`rgb`}});var I=(e,t,n)=>{if(!I[n])throw Error(`unknown blend mode `+n);return I[n](e,t)},L=e=>(t,n)=>{let r=k(n).rgb(),i=k(t).rgb();return k.rgb(e(r,i))},R=e=>(t,n)=>{let r=[];return r[0]=e(t[0],n[0]),r[1]=e(t[1],n[1]),r[2]=e(t[2],n[2]),r};I.normal=L(R(e=>e)),I.multiply=L(R((e,t)=>e*t/255)),I.screen=L(R((e,t)=>255*(1-(1-e/255)*(1-t/255)))),I.overlay=L(R((e,t)=>t<128?2*e*t/255:255*(1-2*(1-e/255)*(1-t/255)))),I.darken=L(R((e,t)=>e>t?t:e)),I.lighten=L(R((e,t)=>e>t?e:t)),I.dodge=L(R((e,t)=>e===255?255:(e=t/255*255/(1-e/255),e>255?255:e))),I.burn=L(R((e,t)=>255*(1-(1-t/255)/(e/255))));var{pow:yt,sin:bt,cos:xt}=Math;function St(e=300,t=-1.5,n=1,r=1,i=[0,1]){let a=0,o;h(i)===`array`?o=i[1]-i[0]:(o=0,i=[i,i]);let s=function(s){let c=C*((e+120)/360+t*s),l=yt(i[0]+o*s,r),u=(a===0?n:n[0]+s*a)*l*(1-l)/2,d=xt(c),f=bt(c),m=l+u*(-.14861*d+1.78277*f),h=l+u*(-.29227*d-.90649*f),g=l+1.97294*d*u;return k(p([m*255,h*255,g*255,1]))};return s.start=function(t){return t==null?e:(e=t,s)},s.rotations=function(e){return e==null?t:(t=e,s)},s.gamma=function(e){return e==null?r:(r=e,s)},s.hue=function(e){return e==null?n:(n=e,h(n)===`array`?(a=n[1]-n[0],a===0&&(n=n[1])):a=0,s)},s.lightness=function(e){return e==null?i:(h(e)===`array`?(i=e,o=e[1]-e[0]):(i=[e,e],o=0),s)},s.scale=()=>k.scale(s),s.hue(n),s}var Ct=`0123456789abcdef`,{floor:wt,random:Tt}=Math,Et=(e=Tt)=>{let t=`#`;for(let n=0;n<6;n++)t+=Ct.charAt(wt(e()*16));return new O(t,`hex`)},{log:Dt,pow:Ot,floor:kt,abs:At}=Math;function jt(e,t=null){let n={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};return h(e)===`object`&&(e=Object.values(e)),e.forEach(e=>{t&&h(e)===`object`&&(e=e[t]),e!=null&&!isNaN(e)&&(n.values.push(e),n.sum+=e,en.max&&(n.max=e),n.count+=1)}),n.domain=[n.min,n.max],n.limits=(e,t)=>Mt(n,e,t),n}function Mt(e,t=`equal`,n=7){h(e)==`array`&&(e=jt(e));let{min:r,max:i}=e,a=e.values.sort((e,t)=>e-t);if(n===1)return[r,i];let o=[];if(t.substr(0,1)===`c`&&(o.push(r),o.push(i)),t.substr(0,1)===`e`){o.push(r);for(let e=1;e 0`);let e=Math.LOG10E*Dt(r),t=Math.LOG10E*Dt(i);o.push(r);for(let r=1;r200&&(l=!1)}let f={};for(let e=0;ee-t),o.push(p[0]);for(let e=1;e{e=new O(e),t=new O(t);let n=e.luminance(),r=t.luminance();return n>r?(n+.05)/(r+.05):(r+.05)/(n+.05)},Pt=.027,Ft=5e-4,It=.1,Lt=1.14,Rt=.022,zt=1.414,Bt=(e,t)=>{e=new O(e),t=new O(t),e.alpha()<1&&(e=F(t,e,e.alpha(),`rgb`));let n=Vt(...e.rgb()),r=Vt(...t.rgb()),i=n>=Rt?n:n+(Rt-n)**+zt,a=r>=Rt?r:r+(Rt-r)**+zt,o=a**.56-i**.57,s=a**.65-i**.62,c=Math.abs(a-i)0?c-Pt:c+Pt)*100};function Vt(e,t,n){return .2126729*(e/255)**2.4+.7151522*(t/255)**2.4+.072175*(n/255)**2.4}var{sqrt:z,pow:B,min:Ht,max:Ut,atan2:Wt,abs:Gt,cos:Kt,sin:qt,exp:Jt,PI:Yt}=Math;function Xt(e,t,n=1,r=1,i=1){var a=function(e){return 360*e/(2*Yt)},o=function(e){return 2*Yt*e/360};e=new O(e),t=new O(t);let[s,c,l]=Array.from(e.lab()),[u,d,f]=Array.from(t.lab()),p=(s+u)/2,m=(z(B(c,2)+B(l,2))+z(B(d,2)+B(f,2)))/2,h=.5*(1-z(B(m,7)/(B(m,7)+B(25,7)))),g=c*(1+h),_=d*(1+h),v=z(B(g,2)+B(l,2)),y=z(B(_,2)+B(f,2)),b=(v+y)/2,x=a(Wt(l,g)),S=a(Wt(f,_)),C=x>=0?x:x+360,w=S>=0?S:S+360,T=Gt(C-w)>180?(C+w+360)/2:(C+w)/2,ee=1-.17*Kt(o(T-30))+.24*Kt(o(2*T))+.32*Kt(o(3*T+6))-.2*Kt(o(4*T-63)),E=w-C;E=Gt(E)<=180?E:w<=C?E+360:E-360,E=2*z(v*y)*qt(o(E)/2);let D=u-s,te=y-v,k=1+.015*B(p-50,2)/z(20+B(p-50,2)),A=1+.045*b,ne=1+.015*b*ee,re=30*Jt(-B((T-275)/25,2)),ie=-(2*z(B(b,7)/(B(b,7)+B(25,7))))*qt(2*o(re));return Ut(0,Ht(100,z(B(D/(n*k),2)+B(te/(r*A),2)+B(E/(i*ne),2)+ie*(te/(r*A))*(E/(i*ne)))))}function Zt(e,t,n=`lab`){e=new O(e),t=new O(t);let r=e.get(n),i=t.get(n),a=0;for(let e in r){let t=(r[e]||0)-(i[e]||0);a+=t*t}return Math.sqrt(a)}var Qt=(...e)=>{try{return new O(...e),!0}catch{return!1}},$t={cool(){return pt([k.hsl(180,1,.9),k.hsl(250,.7,.4)])},hot(){return pt([`#000`,`#f00`,`#ff0`,`#fff`],[0,.25,.75,1]).mode(`rgb`)}},en={OrRd:[`#fff7ec`,`#fee8c8`,`#fdd49e`,`#fdbb84`,`#fc8d59`,`#ef6548`,`#d7301f`,`#b30000`,`#7f0000`],PuBu:[`#fff7fb`,`#ece7f2`,`#d0d1e6`,`#a6bddb`,`#74a9cf`,`#3690c0`,`#0570b0`,`#045a8d`,`#023858`],BuPu:[`#f7fcfd`,`#e0ecf4`,`#bfd3e6`,`#9ebcda`,`#8c96c6`,`#8c6bb1`,`#88419d`,`#810f7c`,`#4d004b`],Oranges:[`#fff5eb`,`#fee6ce`,`#fdd0a2`,`#fdae6b`,`#fd8d3c`,`#f16913`,`#d94801`,`#a63603`,`#7f2704`],BuGn:[`#f7fcfd`,`#e5f5f9`,`#ccece6`,`#99d8c9`,`#66c2a4`,`#41ae76`,`#238b45`,`#006d2c`,`#00441b`],YlOrBr:[`#ffffe5`,`#fff7bc`,`#fee391`,`#fec44f`,`#fe9929`,`#ec7014`,`#cc4c02`,`#993404`,`#662506`],YlGn:[`#ffffe5`,`#f7fcb9`,`#d9f0a3`,`#addd8e`,`#78c679`,`#41ab5d`,`#238443`,`#006837`,`#004529`],Reds:[`#fff5f0`,`#fee0d2`,`#fcbba1`,`#fc9272`,`#fb6a4a`,`#ef3b2c`,`#cb181d`,`#a50f15`,`#67000d`],RdPu:[`#fff7f3`,`#fde0dd`,`#fcc5c0`,`#fa9fb5`,`#f768a1`,`#dd3497`,`#ae017e`,`#7a0177`,`#49006a`],Greens:[`#f7fcf5`,`#e5f5e0`,`#c7e9c0`,`#a1d99b`,`#74c476`,`#41ab5d`,`#238b45`,`#006d2c`,`#00441b`],YlGnBu:[`#ffffd9`,`#edf8b1`,`#c7e9b4`,`#7fcdbb`,`#41b6c4`,`#1d91c0`,`#225ea8`,`#253494`,`#081d58`],Purples:[`#fcfbfd`,`#efedf5`,`#dadaeb`,`#bcbddc`,`#9e9ac8`,`#807dba`,`#6a51a3`,`#54278f`,`#3f007d`],GnBu:[`#f7fcf0`,`#e0f3db`,`#ccebc5`,`#a8ddb5`,`#7bccc4`,`#4eb3d3`,`#2b8cbe`,`#0868ac`,`#084081`],Greys:[`#ffffff`,`#f0f0f0`,`#d9d9d9`,`#bdbdbd`,`#969696`,`#737373`,`#525252`,`#252525`,`#000000`],YlOrRd:[`#ffffcc`,`#ffeda0`,`#fed976`,`#feb24c`,`#fd8d3c`,`#fc4e2a`,`#e31a1c`,`#bd0026`,`#800026`],PuRd:[`#f7f4f9`,`#e7e1ef`,`#d4b9da`,`#c994c7`,`#df65b0`,`#e7298a`,`#ce1256`,`#980043`,`#67001f`],Blues:[`#f7fbff`,`#deebf7`,`#c6dbef`,`#9ecae1`,`#6baed6`,`#4292c6`,`#2171b5`,`#08519c`,`#08306b`],PuBuGn:[`#fff7fb`,`#ece2f0`,`#d0d1e6`,`#a6bddb`,`#67a9cf`,`#3690c0`,`#02818a`,`#016c59`,`#014636`],Viridis:[`#440154`,`#482777`,`#3f4a8a`,`#31678e`,`#26838f`,`#1f9d8a`,`#6cce5a`,`#b6de2b`,`#fee825`],Spectral:[`#9e0142`,`#d53e4f`,`#f46d43`,`#fdae61`,`#fee08b`,`#ffffbf`,`#e6f598`,`#abdda4`,`#66c2a5`,`#3288bd`,`#5e4fa2`],RdYlGn:[`#a50026`,`#d73027`,`#f46d43`,`#fdae61`,`#fee08b`,`#ffffbf`,`#d9ef8b`,`#a6d96a`,`#66bd63`,`#1a9850`,`#006837`],RdBu:[`#67001f`,`#b2182b`,`#d6604d`,`#f4a582`,`#fddbc7`,`#f7f7f7`,`#d1e5f0`,`#92c5de`,`#4393c3`,`#2166ac`,`#053061`],PiYG:[`#8e0152`,`#c51b7d`,`#de77ae`,`#f1b6da`,`#fde0ef`,`#f7f7f7`,`#e6f5d0`,`#b8e186`,`#7fbc41`,`#4d9221`,`#276419`],PRGn:[`#40004b`,`#762a83`,`#9970ab`,`#c2a5cf`,`#e7d4e8`,`#f7f7f7`,`#d9f0d3`,`#a6dba0`,`#5aae61`,`#1b7837`,`#00441b`],RdYlBu:[`#a50026`,`#d73027`,`#f46d43`,`#fdae61`,`#fee090`,`#ffffbf`,`#e0f3f8`,`#abd9e9`,`#74add1`,`#4575b4`,`#313695`],BrBG:[`#543005`,`#8c510a`,`#bf812d`,`#dfc27d`,`#f6e8c3`,`#f5f5f5`,`#c7eae5`,`#80cdc1`,`#35978f`,`#01665e`,`#003c30`],RdGy:[`#67001f`,`#b2182b`,`#d6604d`,`#f4a582`,`#fddbc7`,`#ffffff`,`#e0e0e0`,`#bababa`,`#878787`,`#4d4d4d`,`#1a1a1a`],PuOr:[`#7f3b08`,`#b35806`,`#e08214`,`#fdb863`,`#fee0b6`,`#f7f7f7`,`#d8daeb`,`#b2abd2`,`#8073ac`,`#542788`,`#2d004b`],Set2:[`#66c2a5`,`#fc8d62`,`#8da0cb`,`#e78ac3`,`#a6d854`,`#ffd92f`,`#e5c494`,`#b3b3b3`],Accent:[`#7fc97f`,`#beaed4`,`#fdc086`,`#ffff99`,`#386cb0`,`#f0027f`,`#bf5b17`,`#666666`],Set1:[`#e41a1c`,`#377eb8`,`#4daf4a`,`#984ea3`,`#ff7f00`,`#ffff33`,`#a65628`,`#f781bf`,`#999999`],Set3:[`#8dd3c7`,`#ffffb3`,`#bebada`,`#fb8072`,`#80b1d3`,`#fdb462`,`#b3de69`,`#fccde5`,`#d9d9d9`,`#bc80bd`,`#ccebc5`,`#ffed6f`],Dark2:[`#1b9e77`,`#d95f02`,`#7570b3`,`#e7298a`,`#66a61e`,`#e6ab02`,`#a6761d`,`#666666`],Paired:[`#a6cee3`,`#1f78b4`,`#b2df8a`,`#33a02c`,`#fb9a99`,`#e31a1c`,`#fdbf6f`,`#ff7f00`,`#cab2d6`,`#6a3d9a`,`#ffff99`,`#b15928`],Pastel2:[`#b3e2cd`,`#fdcdac`,`#cbd5e8`,`#f4cae4`,`#e6f5c9`,`#fff2ae`,`#f1e2cc`,`#cccccc`],Pastel1:[`#fbb4ae`,`#b3cde3`,`#ccebc5`,`#decbe4`,`#fed9a6`,`#ffffcc`,`#e5d8bd`,`#fddaec`,`#f2f2f2`]},tn=Object.keys(en),nn=new Map(tn.map(e=>[e.toLowerCase(),e])),rn=typeof Proxy==`function`?new Proxy(en,{get(e,t){let n=t.toLowerCase();if(nn.has(n))return e[nn.get(n)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(tn)}}):en,an=(...e)=>{e=g(e,`cmyk`);let[t,n,r,i]=e,a=e.length>4?e[4]:1;return i===1?[0,0,0,a]:[t>=1?0:255*(1-t)*(1-i),n>=1?0:255*(1-n)*(1-i),r>=1?0:255*(1-r)*(1-i),a]},{max:on}=Math,sn=(...e)=>{let[t,n,r]=g(e,`rgb`);t/=255,n/=255,r/=255;let i=1-on(t,on(n,r)),a=i<1?1/(1-i):0;return[(1-t-i)*a,(1-n-i)*a,(1-r-i)*a,i]};O.prototype.cmyk=function(){return sn(this._rgb)},Object.assign(k,{cmyk:(...e)=>new O(...e,`cmyk`)}),D.format.cmyk=an,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`cmyk`),h(e)===`array`&&e.length===4)return`cmyk`}});var cn=(...e)=>{let t=g(e,`hsla`),n=_(e)||`lsa`;return t[0]=x(t[0]||0)+`deg`,t[1]=x(t[1]*100)+`%`,t[2]=x(t[2]*100)+`%`,n===`hsla`||t.length>3&&t[3]<1?(t[3]=`/ `+(t.length>3?t[3]:1),n=`hsla`):t.length=3,`${n.substr(0,3)}(${t.join(` `)})`},ln=(...e)=>{let t=g(e,`lab`),n=_(e)||`lab`;return t[0]=x(t[0])+`%`,t[1]=x(t[1]),t[2]=x(t[2]),n===`laba`||t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`lab(${t.join(` `)})`},un=(...e)=>{let t=g(e,`lch`),n=_(e)||`lab`;return t[0]=x(t[0])+`%`,t[1]=x(t[1]),t[2]=isNaN(t[2])?`none`:x(t[2])+`deg`,n===`lcha`||t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`lch(${t.join(` `)})`},dn=(...e)=>{let t=g(e,`lab`);return t[0]=x(t[0]*100)+`%`,t[1]=S(t[1]),t[2]=S(t[2]),t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`oklab(${t.join(` `)})`},fn=(...e)=>{let[t,n,r,...i]=g(e,`rgb`),[a,o,s]=nt(t,n,r),[c,l,u]=ke(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]},pn=(...e)=>{let t=g(e,`lch`);return t[0]=x(t[0]*100)+`%`,t[1]=S(t[1]),t[2]=isNaN(t[2])?`none`:x(t[2])+`deg`,t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`oklch(${t.join(` `)})`},{round:mn}=Math,hn=(...e)=>{let t=g(e,`rgba`),n=_(e)||`rgb`;if(n.substr(0,3)===`hsl`)return cn(qe(t),n);if(n.substr(0,3)===`lab`){let e=ce();M(`d50`);let r=ln(fe(t),n);return M(e),r}if(n.substr(0,3)===`lch`){let e=ce();M(`d50`);let r=un(Ae(t),n);return M(e),r}return n.substr(0,5)===`oklab`?dn(nt(t)):n.substr(0,5)===`oklch`?pn(fn(t)):(t[0]=mn(t[0]),t[1]=mn(t[1]),t[2]=mn(t[2]),(n===`rgba`||t.length>3&&t[3]<1)&&(t[3]=`/ `+(t.length>3?t[3]:1),n=`rgba`),`${n.substr(0,3)}(${t.slice(0,n===`rgb`?3:4).join(` `)})`)},gn=(...e)=>{e=g(e,`lch`);let[t,n,r,...i]=e,[a,o,s]=Ce(t,n,r),[c,l,u]=et(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]},V=`((?:-?\\d+)|(?:-?\\d+(?:\\.\\d+)?)%|none)`,H=`((?:-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)%?)|none)`,_n=`((?:-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)%)|none)`,U=`\\s*`,vn=`\\s+`,yn=`\\s*,\\s*`,bn=`((?:-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:deg)?)|none)`,xn=`\\s*(?:\\/\\s*((?:[01]|[01]?\\.\\d+)|\\d+(?:\\.\\d+)?%))?`,Sn=RegExp(`^rgba?\\(`+U+[V,V,V].join(vn)+xn+`\\)$`),Cn=RegExp(`^rgb\\(`+U+[V,V,V].join(yn)+U+`\\)$`),wn=RegExp(`^rgba\\(`+U+[V,V,V,H].join(yn)+U+`\\)$`),Tn=RegExp(`^hsla?\\(`+U+[bn,_n,_n].join(vn)+xn+`\\)$`),En=RegExp(`^hsl?\\(`+U+[bn,_n,_n].join(yn)+U+`\\)$`),Dn=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,On=RegExp(`^lab\\(`+U+[H,H,H].join(vn)+xn+`\\)$`),kn=RegExp(`^lch\\(`+U+[H,H,bn].join(vn)+xn+`\\)$`),An=RegExp(`^oklab\\(`+U+[H,H,H].join(vn)+xn+`\\)$`),jn=RegExp(`^oklch\\(`+U+[H,H,bn].join(vn)+xn+`\\)$`),{round:Mn}=Math,Nn=e=>e.map((e,t)=>t<=2?f(Mn(e),0,255):e),W=(e,t=0,n=100,r=!1)=>(typeof e==`string`&&e.endsWith(`%`)&&(e=parseFloat(e.substring(0,e.length-1))/100,e=r?t+(e+1)*.5*(n-t):t+e*(n-t)),+e),G=(e,t)=>e===`none`?t:e,Pn=e=>{if(e=e.toLowerCase().trim(),e===`transparent`)return[0,0,0,0];let t;if(D.format.named)try{return D.format.named(e)}catch{}if((t=e.match(Sn))||(t=e.match(Cn))){let e=t.slice(1,4);for(let t=0;t<3;t++)e[t]=+W(G(e[t],0),0,255);e=Nn(e);let n=t[4]===void 0?1:+W(t[4],0,1);return e[3]=n,e}if(t=e.match(wn)){let e=t.slice(1,5);for(let t=0;t<4;t++)e[t]=+W(e[t],0,255);return e}if((t=e.match(Tn))||(t=e.match(En))){let e=t.slice(1,4);e[0]=+G(e[0].replace(`deg`,``),0),e[1]=W(G(e[1],0),0,100)*.01,e[2]=W(G(e[2],0),0,100)*.01;let n=Nn(Ke(e));return n[3]=t[4]===void 0?1:+W(t[4],0,1),n}if(t=e.match(Dn)){let e=t.slice(1,4);e[1]*=.01,e[2]*=.01;let n=Ke(e);for(let e=0;e<3;e++)n[e]=Mn(n[e]);return n[3]=+t[4],n}if(t=e.match(On)){let e=t.slice(1,4);e[0]=W(G(e[0],0),0,100),e[1]=W(G(e[1],0),-125,125,!0),e[2]=W(G(e[2],0),-125,125,!0);let n=ce();M(`d50`);let r=Nn(N(e));return M(n),r[3]=t[4]===void 0?1:+W(t[4],0,1),r}if(t=e.match(kn)){let e=t.slice(1,4);e[0]=W(e[0],0,100),e[1]=W(G(e[1],0),0,150,!1),e[2]=+G(e[2].replace(`deg`,``),0);let n=ce();M(`d50`);let r=Nn(we(e));return M(n),r[3]=t[4]===void 0?1:+W(t[4],0,1),r}if(t=e.match(An)){let e=t.slice(1,4);e[0]=W(G(e[0],0),0,1),e[1]=W(G(e[1],0),-.4,.4,!0),e[2]=W(G(e[2],0),-.4,.4,!0);let n=Nn(et(e));return n[3]=t[4]===void 0?1:+W(t[4],0,1),n}if(t=e.match(jn)){let e=t.slice(1,4);e[0]=W(G(e[0],0),0,1),e[1]=W(G(e[1],0),0,.4,!1),e[2]=+G(e[2].replace(`deg`,``),0);let n=Nn(gn(e));return n[3]=t[4]===void 0?1:+W(t[4],0,1),n}};Pn.test=e=>Sn.test(e)||Tn.test(e)||On.test(e)||kn.test(e)||An.test(e)||jn.test(e)||Cn.test(e)||wn.test(e)||En.test(e)||Dn.test(e)||e===`transparent`,O.prototype.css=function(e){return hn(this._rgb,e)},k.css=(...e)=>new O(...e,`css`),D.format.css=Pn,D.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&h(e)===`string`&&Pn.test(e))return`css`}}),D.format.gl=(...e)=>{let t=g(e,`rgba`);return t[0]*=255,t[1]*=255,t[2]*=255,t},k.gl=(...e)=>new O(...e,`gl`),O.prototype.gl=function(){let e=this._rgb;return[e[0]/255,e[1]/255,e[2]/255,e[3]]},O.prototype.hex=function(e){return oe(this._rgb,e)},k.hex=(...e)=>new O(...e,`hex`),D.format.hex=ie,D.autodetect.push({p:4,test:(e,...t)=>{if(!t.length&&h(e)===`string`&&[3,4,5,6,7,8,9].indexOf(e.length)>=0)return`hex`}});var{log:Fn}=Math,In=e=>{let t=e/100,n,r,i;return t<66?(n=255,r=t<6?0:-155.25485562709179-.44596950469579133*(r=t-2)+104.49216199393888*Fn(r),i=t<20?0:-254.76935184120902+.8274096064007395*(i=t-10)+115.67994401066147*Fn(i)):(n=351.97690566805693+.114206453784165*(n=t-55)-40.25366309332127*Fn(n),r=325.4494125711974+.07943456536662342*(r=t-50)-28.0852963507957*Fn(r),i=255),[n,r,i,1]},{round:Ln}=Math,Rn=(...e)=>{let t=g(e,`rgb`),n=t[0],r=t[2],i=1e3,a=4e4,o;for(;a-i>.4;){o=(a+i)*.5;let e=In(o);e[2]/e[0]>=r/n?a=o:i=o}return Ln(o)};O.prototype.temp=O.prototype.kelvin=O.prototype.temperature=function(){return Rn(this._rgb)};var zn=(...e)=>new O(...e,`temp`);Object.assign(k,{temp:zn,kelvin:zn,temperature:zn}),D.format.temp=D.format.kelvin=D.format.temperature=In,O.prototype.oklch=function(){return fn(this._rgb)},Object.assign(k,{oklch:(...e)=>new O(...e,`oklch`)}),D.format.oklch=gn,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`oklch`),h(e)===`array`&&e.length===3)return`oklch`}}),Object.assign(k,{analyze:jt,average:ut,bezier:_t,blend:I,brewer:rn,Color:O,colors:A,contrast:Nt,contrastAPCA:Bt,cubehelix:St,deltaE:Xt,distance:Zt,input:D,interpolate:F,limits:Mt,mix:F,random:Et,scale:pt,scales:$t,valid:Qt});var K=k,q=class e{constructor(){this.hex=`#000000`,this.rgb_r=0,this.rgb_g=0,this.rgb_b=0,this.xyz_x=0,this.xyz_y=0,this.xyz_z=0,this.luv_l=0,this.luv_u=0,this.luv_v=0,this.lch_l=0,this.lch_c=0,this.lch_h=0,this.hsluv_h=0,this.hsluv_s=0,this.hsluv_l=0,this.hpluv_h=0,this.hpluv_p=0,this.hpluv_l=0,this.r0s=0,this.r0i=0,this.r1s=0,this.r1i=0,this.g0s=0,this.g0i=0,this.g1s=0,this.g1i=0,this.b0s=0,this.b0i=0,this.b1s=0,this.b1i=0}static fromLinear(e){return e<=.0031308?12.92*e:1.055*e**(1/2.4)-.055}static toLinear(e){return e>.04045?((e+.055)/1.055)**2.4:e/12.92}static yToL(t){return t<=e.epsilon?t/e.refY*e.kappa:116*(t/e.refY)**(1/3)-16}static lToY(t){return t<=8?e.refY*t/e.kappa:e.refY*((t+16)/116)**3}static rgbChannelToHex(t){let n=Math.round(t*255),r=n%16,i=(n-r)/16|0;return e.hexChars.charAt(i)+e.hexChars.charAt(r)}static hexToRgbChannel(t,n){let r=e.hexChars.indexOf(t.charAt(n)),i=e.hexChars.indexOf(t.charAt(n+1));return(r*16+i)/255}static distanceFromOriginAngle(e,t,n){let r=t/(Math.sin(n)-e*Math.cos(n));return r<0?1/0:r}static distanceFromOrigin(e,t){return Math.abs(t)/Math.sqrt(e**2+1)}static min6(e,t,n,r,i,a){return Math.min(e,Math.min(t,Math.min(n,Math.min(r,Math.min(i,a)))))}rgbToHex(){this.hex=`#`,this.hex+=e.rgbChannelToHex(this.rgb_r),this.hex+=e.rgbChannelToHex(this.rgb_g),this.hex+=e.rgbChannelToHex(this.rgb_b)}hexToRgb(){this.hex=this.hex.toLowerCase(),this.rgb_r=e.hexToRgbChannel(this.hex,1),this.rgb_g=e.hexToRgbChannel(this.hex,3),this.rgb_b=e.hexToRgbChannel(this.hex,5)}xyzToRgb(){this.rgb_r=e.fromLinear(e.m_r0*this.xyz_x+e.m_r1*this.xyz_y+e.m_r2*this.xyz_z),this.rgb_g=e.fromLinear(e.m_g0*this.xyz_x+e.m_g1*this.xyz_y+e.m_g2*this.xyz_z),this.rgb_b=e.fromLinear(e.m_b0*this.xyz_x+e.m_b1*this.xyz_y+e.m_b2*this.xyz_z)}rgbToXyz(){let t=e.toLinear(this.rgb_r),n=e.toLinear(this.rgb_g),r=e.toLinear(this.rgb_b);this.xyz_x=.41239079926595*t+.35758433938387*n+.18048078840183*r,this.xyz_y=.21263900587151*t+.71516867876775*n+.072192315360733*r,this.xyz_z=.019330818715591*t+.11919477979462*n+.95053215224966*r}xyzToLuv(){let t=this.xyz_x+15*this.xyz_y+3*this.xyz_z,n=4*this.xyz_x,r=9*this.xyz_y;t===0?(n=NaN,r=NaN):(n/=t,r/=t),this.luv_l=e.yToL(this.xyz_y),this.luv_l===0?(this.luv_u=0,this.luv_v=0):(this.luv_u=13*this.luv_l*(n-e.refU),this.luv_v=13*this.luv_l*(r-e.refV))}luvToXyz(){if(this.luv_l===0){this.xyz_x=0,this.xyz_y=0,this.xyz_z=0;return}let t=this.luv_u/(13*this.luv_l)+e.refU,n=this.luv_v/(13*this.luv_l)+e.refV;this.xyz_y=e.lToY(this.luv_l),this.xyz_x=0-9*this.xyz_y*t/((t-4)*n-t*n),this.xyz_z=(9*this.xyz_y-15*n*this.xyz_y-n*this.xyz_x)/(3*n)}luvToLch(){this.lch_l=this.luv_l,this.lch_c=Math.sqrt(this.luv_u*this.luv_u+this.luv_v*this.luv_v),this.lch_c<1e-8?this.lch_h=0:(this.lch_h=Math.atan2(this.luv_v,this.luv_u)*180/Math.PI,this.lch_h<0&&(this.lch_h=360+this.lch_h))}lchToLuv(){let e=this.lch_h/180*Math.PI;this.luv_l=this.lch_l,this.luv_u=Math.cos(e)*this.lch_c,this.luv_v=Math.sin(e)*this.lch_c}calculateBoundingLines(t){let n=(t+16)**3/1560896,r=n>e.epsilon?n:t/e.kappa,i=r*(284517*e.m_r0-94839*e.m_r2),a=r*(838422*e.m_r2+769860*e.m_r1+731718*e.m_r0),o=r*(632260*e.m_r2-126452*e.m_r1),s=r*(284517*e.m_g0-94839*e.m_g2),c=r*(838422*e.m_g2+769860*e.m_g1+731718*e.m_g0),l=r*(632260*e.m_g2-126452*e.m_g1),u=r*(284517*e.m_b0-94839*e.m_b2),d=r*(838422*e.m_b2+769860*e.m_b1+731718*e.m_b0),f=r*(632260*e.m_b2-126452*e.m_b1);this.r0s=i/o,this.r0i=a*t/o,this.r1s=i/(o+126452),this.r1i=(a-769860)*t/(o+126452),this.g0s=s/l,this.g0i=c*t/l,this.g1s=s/(l+126452),this.g1i=(c-769860)*t/(l+126452),this.b0s=u/f,this.b0i=d*t/f,this.b1s=u/(f+126452),this.b1i=(d-769860)*t/(f+126452)}calcMaxChromaHpluv(){let t=e.distanceFromOrigin(this.r0s,this.r0i),n=e.distanceFromOrigin(this.r1s,this.r1i),r=e.distanceFromOrigin(this.g0s,this.g0i),i=e.distanceFromOrigin(this.g1s,this.g1i),a=e.distanceFromOrigin(this.b0s,this.b0i),o=e.distanceFromOrigin(this.b1s,this.b1i);return e.min6(t,n,r,i,a,o)}calcMaxChromaHsluv(t){let n=t/360*Math.PI*2,r=e.distanceFromOriginAngle(this.r0s,this.r0i,n),i=e.distanceFromOriginAngle(this.r1s,this.r1i,n),a=e.distanceFromOriginAngle(this.g0s,this.g0i,n),o=e.distanceFromOriginAngle(this.g1s,this.g1i,n),s=e.distanceFromOriginAngle(this.b0s,this.b0i,n),c=e.distanceFromOriginAngle(this.b1s,this.b1i,n);return e.min6(r,i,a,o,s,c)}hsluvToLch(){this.hsluv_l>99.9999999?(this.lch_l=100,this.lch_c=0):this.hsluv_l<1e-8?(this.lch_l=0,this.lch_c=0):(this.lch_l=this.hsluv_l,this.calculateBoundingLines(this.hsluv_l),this.lch_c=this.calcMaxChromaHsluv(this.hsluv_h)/100*this.hsluv_s),this.lch_h=this.hsluv_h}lchToHsluv(){if(this.lch_l>99.9999999)this.hsluv_s=0,this.hsluv_l=100;else if(this.lch_l<1e-8)this.hsluv_s=0,this.hsluv_l=0;else{this.calculateBoundingLines(this.lch_l);let e=this.calcMaxChromaHsluv(this.lch_h);this.hsluv_s=this.lch_c/e*100,this.hsluv_l=this.lch_l}this.hsluv_h=this.lch_h}hpluvToLch(){this.hpluv_l>99.9999999?(this.lch_l=100,this.lch_c=0):this.hpluv_l<1e-8?(this.lch_l=0,this.lch_c=0):(this.lch_l=this.hpluv_l,this.calculateBoundingLines(this.hpluv_l),this.lch_c=this.calcMaxChromaHpluv()/100*this.hpluv_p),this.lch_h=this.hpluv_h}lchToHpluv(){if(this.lch_l>99.9999999)this.hpluv_p=0,this.hpluv_l=100;else if(this.lch_l<1e-8)this.hpluv_p=0,this.hpluv_l=0;else{this.calculateBoundingLines(this.lch_l);let e=this.calcMaxChromaHpluv();this.hpluv_p=this.lch_c/e*100,this.hpluv_l=this.lch_l}this.hpluv_h=this.lch_h}hsluvToRgb(){this.hsluvToLch(),this.lchToLuv(),this.luvToXyz(),this.xyzToRgb()}hpluvToRgb(){this.hpluvToLch(),this.lchToLuv(),this.luvToXyz(),this.xyzToRgb()}hsluvToHex(){this.hsluvToRgb(),this.rgbToHex()}hpluvToHex(){this.hpluvToRgb(),this.rgbToHex()}rgbToHsluv(){this.rgbToXyz(),this.xyzToLuv(),this.luvToLch(),this.lchToHpluv(),this.lchToHsluv()}rgbToHpluv(){this.rgbToXyz(),this.xyzToLuv(),this.luvToLch(),this.lchToHpluv(),this.lchToHpluv()}hexToHsluv(){this.hexToRgb(),this.rgbToHsluv()}hexToHpluv(){this.hexToRgb(),this.rgbToHpluv()}};q.hexChars=`0123456789abcdef`,q.refY=1,q.refU=.19783000664283,q.refV=.46831999493879,q.kappa=903.2962962,q.epsilon=.0088564516,q.m_r0=3.240969941904521,q.m_r1=-1.537383177570093,q.m_r2=-.498610760293,q.m_g0=-.96924363628087,q.m_g1=1.87596750150772,q.m_g2=.041555057407175,q.m_b0=.055630079696993,q.m_b1=-.20397695888897,q.m_b2=1.056971514242878;var Bn=s(((e,t)=>{function n(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.exports=n})),Vn=s(((e,t)=>{var n=Bn(),r,i;function a(){for(var e in i=[`toString`,`toLocaleString`,`valueOf`,`hasOwnProperty`,`isPrototypeOf`,`propertyIsEnumerable`,`constructor`],r=!0,{toString:null})r=!1}function o(e,t,o){var c,l=0;for(c in r??a(),e)if(s(t,e,c,o)===!1)break;if(r)for(var u=e.constructor,d=!!u&&e===u.prototype;(c=i[l++])&&!((c!==`constructor`||!d&&n(e,c))&&e[c]!==Object.prototype[c]&&s(t,e,c,o)===!1););}function s(e,t,n,r){return e.call(r,t[n],n,t)}t.exports=o})),Hn=s(((e,t)=>{var n=Vn();function r(e){var t=[];return n(e,function(e,n){typeof e==`function`&&t.push(n)}),t.sort()}t.exports=r})),Un=s(((e,t)=>{function n(e,t,n){var r=e.length;t=t==null?0:t<0?Math.max(r+t,0):Math.min(t,r),n=n==null?r:n<0?Math.max(r+n,0):Math.min(n,r);for(var i=[];t{var n=Un();function r(e,t,r){var i=n(arguments,2);return function(){return e.apply(t,i.concat(n(arguments)))}}t.exports=r})),Gn=s(((e,t)=>{function n(e,t,n){if(e!=null)for(var r=-1,i=e.length;++r{var n=Hn(),r=Wn(),i=Gn(),a=Un();function o(e,t){i(arguments.length>1?a(arguments,1):n(e),function(t){e[t]=r(e[t],e)})}t.exports=o})),J=s(((e,t)=>{var n=Bn(),r=Vn();function i(e,t,i){r(e,function(r,a){if(n(e,a))return t.call(i,e[a],a,e)})}t.exports=i})),qn=s(((e,t)=>{function n(e){return e}t.exports=n})),Jn=s(((e,t)=>{function n(e){return function(t){return t[e]}}t.exports=n})),Yn=s(((e,t)=>{var n=/^\[object (.*)\]$/,r=Object.prototype.toString,i;function a(e){return e===null?`Null`:e===i?`Undefined`:n.exec(r.call(e))[1]}t.exports=a})),Xn=s(((e,t)=>{var n=Yn();function r(e,t){return n(e)===t}t.exports=r})),Zn=s(((e,t)=>{var n=Xn();t.exports=Array.isArray||function(e){return n(e,`Array`)}})),Qn=s(((e,t)=>{var n=J(),r=Zn();function i(e,t){for(var n=-1,r=e.length;++n{var n=qn(),r=Jn(),i=Qn();function a(e,t){if(e==null)return n;switch(typeof e){case`function`:return t===void 0?e:function(n,r,i){return e.call(t,n,r,i)};case`object`:return function(t){return i(t,e)};case`string`:case`number`:return r(e)}}t.exports=a})),$n=s(((e,t)=>{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a=!1;return n(e,function(n,r){if(t(n,r,e))return a=!0,!1}),a}t.exports=i})),er=s(((e,t)=>{var n=$n();function r(e,t){return n(e,function(e){return e===t})}t.exports=r})),tr=s(((e,t)=>{function n(e){return!!e&&typeof e==`object`&&e.constructor===Object}t.exports=n})),nr=s(((e,t)=>{var n=J(),r=tr();function i(e,t){for(var a=0,o=arguments.length,s;++a{var n=J(),r=tr();function i(e,t){for(var r=0,i=arguments.length,o;++r{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a=!0;return n(e,function(n,r){if(!t(n,r,e))return a=!1,!1}),a}t.exports=i})),ar=s(((e,t)=>{var n=Xn();function r(e){return n(e,`Object`)}t.exports=r})),or=s(((e,t)=>{function n(e,t){return e===t?e!==0||1/e==1/t:e!==e&&t!==t}t.exports=n})),sr=s(((e,t)=>{var n=Bn(),r=ir(),i=ar(),a=or();function o(e){return function(t,r){return n(this,r)&&e(t,this[r])}}function s(e,t){return n(this,t)}function c(e,t,n){return n||=a,!i(e)||!i(t)?n(e,t):r(e,o(n),t)&&r(t,s,e)}t.exports=c})),cr=s(((e,t)=>{var n=Gn(),r=Un(),i=J();function a(e,t){return n(r(arguments,1),function(t){i(t,function(t,n){e[n]??(e[n]=t)})}),e}t.exports=a})),lr=s(((e,t)=>{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a={};return n(e,function(e,n,r){t(e,n,r)&&(a[n]=e)}),a}t.exports=i})),ur=s(((e,t)=>{var n=$n(),r=Y();function i(e,t,i){t=r(t,i);var a;return n(e,function(e,n,r){if(t(e,n,r))return a=e,!0}),a}t.exports=i})),dr=s(((e,t)=>{var n=J(),r=tr();function i(e,t,a,o){return n(e,function(e,n){var s=a?a+`.`+n:n;o!==0&&r(e)?i(e,t,s,o-1):t[s]=e}),t}function a(e,t){return e==null?{}:(t??=-1,i(e,{},``,t))}t.exports=a})),fr=s(((e,t)=>{function n(e){switch(typeof e){case`string`:case`number`:case`boolean`:return!0}return e==null}t.exports=n})),pr=s(((e,t)=>{fr();function n(e,t){for(var n=t.split(`.`),r=n.pop();t=n.shift();)if(e=e[t],e==null)return;return e[r]}t.exports=n})),mr=s(((e,t)=>{var n=pr(),r;function i(e,t){return n(e,t)!==r}t.exports=i})),hr=s(((e,t)=>{var n=J();t.exports=Object.keys||function(e){var t=[];return n(e,function(e,n){t.push(n)}),t}})),gr=s(((e,t)=>{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a={};return n(e,function(e,n,r){a[n]=t(e,n,r)}),a}t.exports=i})),_r=s(((e,t)=>{var n=J();function r(e,t){var r=!0;return n(t,function(t,n){if(e[n]!==t)return r=!1}),r}t.exports=r})),vr=s(((e,t)=>{var n=Y();function r(e,t,r){if(e==null||!e.length)return 1/0;if(e.length&&!t)return Math.max.apply(Math,e);t=n(t,r);for(var i,a=-1/0,o,s,c=-1,l=e.length;++ca&&(a=s,i=o);return i}t.exports=r})),yr=s(((e,t)=>{var n=J();function r(e){var t=[];return n(e,function(e,n){t.push(e)}),t}t.exports=r})),br=s(((e,t)=>{var n=vr(),r=yr();function i(e,t){return n(r(e),t)}t.exports=i})),xr=s(((e,t)=>{var n=J();function r(e,t){for(var r=0,a=arguments.length,o;++r{var n=Yn(),r=tr(),i=xr();function a(e){switch(n(e)){case`Object`:return o(e);case`Array`:return l(e);case`RegExp`:return s(e);case`Date`:return c(e);default:return e}}function o(e){return r(e)?i({},e):e}function s(e){var t=``;return t+=e.multiline?`m`:``,t+=e.global?`g`:``,t+=e.ignoreCase?`i`:``,new RegExp(e.source,t)}function c(e){return new Date(+e)}function l(e){return e.slice()}t.exports=a})),Cr=s(((e,t)=>{var n=Sr(),r=J(),i=Yn(),a=tr();function o(e,t){switch(i(e)){case`Object`:return s(e,t);case`Array`:return c(e,t);default:return n(e)}}function s(e,t){if(a(e)){var n={};return r(e,function(e,n){this[n]=o(e,t)},n),n}else if(t)return t(e);else return e}function c(e,t){for(var n=[],r=-1,i=e.length;++r{var n=Bn(),r=Cr(),i=ar();function a(){for(var e=1,t,o,s,c=r(arguments[0]);s=arguments[e++];)for(t in s)n(s,t)&&(o=s[t],i(o)&&i(c[t])?c[t]=a(c[t],o):c[t]=r(o));return c}t.exports=a})),Tr=s(((e,t)=>{var n=Y();function r(e,t,r){if(e==null||!e.length)return-1/0;if(e.length&&!t)return Math.min.apply(Math,e);t=n(t,r);for(var i,a=1/0,o,s,c=-1,l=e.length;++c{var n=Tr(),r=yr();function i(e,t){return n(r(e),t)}t.exports=i})),Dr=s(((e,t)=>{var n=Gn();function r(e,t){return t&&n(t.split(`.`),function(t){e[t]||(e[t]={}),e=e[t]}),e}t.exports=r})),Or=s(((e,t)=>{function n(e,t,n){if(n||=0,e==null)return-1;for(var r=e.length,i=n<0?r+n:n;i{var n=Or();function r(e,t){return n(e,t)!==-1}t.exports=r})),Ar=s(((e,t)=>{var n=Un(),r=kr();function i(e,t){var i=typeof arguments[1]==`string`?n(arguments,1):arguments[1],a={};for(var o in e)e.hasOwnProperty(o)&&!r(i,o)&&(a[o]=e[o]);return a}t.exports=i})),jr=s(((e,t)=>{var n=Un();function r(e,t){for(var r=typeof arguments[1]==`string`?n(arguments,1):arguments[1],i={},a=0,o;o=r[a++];)i[o]=e[o];return i}t.exports=r})),Mr=s(((e,t)=>{var n=gr(),r=Jn();function i(e,t){return n(e,r(t))}t.exports=i})),Nr=s(((e,t)=>{var n=J();function r(e){var t=0;return n(e,function(){t++}),t}t.exports=r})),Pr=s(((e,t)=>{var n=J(),r=Nr();function i(e,t,i,a){var o=arguments.length>2;if(!r(e)&&!o)throw Error(`reduce of empty object with no initial value`);return n(e,function(e,n,r){o?i=t.call(a,i,e,n,r):(i=e,o=!0)}),i}t.exports=i})),Fr=s(((e,t)=>{var n=lr(),r=Y();function i(e,t,i){return t=r(t,i),n(e,function(e,n,r){return!t(e,n,r)},i)}t.exports=i})),Ir=s(((e,t)=>{var n=Xn();function r(e){return n(e,`Function`)}t.exports=r})),Lr=s(((e,t)=>{var n=Ir();function r(e,t){var r=e[t];if(r!==void 0)return n(r)?r.call(e):r}t.exports=r})),Rr=s(((e,t)=>{var n=Dr();function r(e,t,r){var i=/^(.+)\.(.+)$/.exec(t);i?n(e,i[1])[i[2]]=r:e[t]=r}t.exports=r})),zr=s(((e,t)=>{var n=mr();function r(e,t){if(n(e,t)){for(var r=t.split(`.`),i=r.pop();t=r.shift();)e=e[t];return delete e[i]}else return!0}t.exports=r})),Br=s(((e,t)=>{t.exports={bindAll:Kn(),contains:er(),deepFillIn:nr(),deepMatches:Qn(),deepMixIn:rr(),equals:sr(),every:ir(),fillIn:cr(),filter:lr(),find:ur(),flatten:dr(),forIn:Vn(),forOwn:J(),functions:Hn(),get:pr(),has:mr(),hasOwn:Bn(),keys:hr(),map:gr(),matches:_r(),max:br(),merge:wr(),min:Er(),mixIn:xr(),namespace:Dr(),omit:Ar(),pick:jr(),pluck:Mr(),reduce:Pr(),reject:Fr(),result:Lr(),set:Rr(),size:Nr(),some:$n(),unset:zr(),values:yr()}})),Vr=s(((e,t)=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.default=(0,Br().map)({A:{x:.44758,y:.40745},C:{x:.31006,y:.31616},D50:{x:.34567,y:.35851},D65:{x:.31272,y:.32903},D55:{x:.33243,y:.34744},D75:{x:.29903,y:.31488}},function(e){return[100*(e.x/e.y),100,100*(1-e.x-e.y)/e.y]}),t.exports=e.default})),Hr=s(((e,t)=>{Object.defineProperty(e,`__esModule`,{value:!0});var n=Math,r=n.pow,i=n.sign,a=n.abs,o={decode:function(e){return e<=.04045?e/12.92:r((e+.055)/1.055,2.4)},encode:function(e){return e<=.0031308?12.92*e:1.055*r(e,1/2.4)-.055}},s={encode:function(e){return e<.001953125?16*e:r(e,1/1.8)},decode:function(e){return e<16*.001953125?e/16:r(e,1.8)}};function c(e){return{decode:function(t){return i(t)*r(a(t),e)},encode:function(t){return i(t)*r(a(t),1/e)}}}e.default={sRGB:{r:{x:.64,y:.33},g:{x:.3,y:.6},b:{x:.15,y:.06},gamma:o},"Adobe RGB":{r:{x:.64,y:.33},g:{x:.21,y:.71},b:{x:.15,y:.06},gamma:c(2.2)},"Wide Gamut RGB":{r:{x:.7347,y:.2653},g:{x:.1152,y:.8264},b:{x:.1566,y:.0177},gamma:c(563/256)},"ProPhoto RGB":{r:{x:.7347,y:.2653},g:{x:.1596,y:.8404},b:{x:.0366,y:1e-4},gamma:s}},t.exports=e.default})),Ur=s((e=>{Object.defineProperty(e,`__esModule`,{value:!0});function t(e){return[[e[0][0],e[1][0],e[2][0]],[e[0][1],e[1][1],e[2][1]],[e[0][2],e[1][2],e[2][2]]]}function n(e){return e[0][0]*(e[2][2]*e[1][1]-e[2][1]*e[1][2])+e[1][0]*(e[2][1]*e[0][2]-e[2][2]*e[0][1])+e[2][0]*(e[1][2]*e[0][1]-e[1][1]*e[0][2])}function r(e){var t=1/n(e);return[[(e[2][2]*e[1][1]-e[2][1]*e[1][2])*t,(e[2][1]*e[0][2]-e[2][2]*e[0][1])*t,(e[1][2]*e[0][1]-e[1][1]*e[0][2])*t],[(e[2][0]*e[1][2]-e[2][2]*e[1][0])*t,(e[2][2]*e[0][0]-e[2][0]*e[0][2])*t,(e[1][0]*e[0][2]-e[1][2]*e[0][0])*t],[(e[2][1]*e[1][0]-e[2][0]*e[1][1])*t,(e[2][0]*e[0][1]-e[2][1]*e[0][0])*t,(e[1][1]*e[0][0]-e[1][0]*e[0][1])*t]]}function i(e,t){return[e[0][0]*t[0]+e[0][1]*t[1]+e[0][2]*t[2],e[1][0]*t[0]+e[1][1]*t[1]+e[1][2]*t[2],e[2][0]*t[0]+e[2][1]*t[1]+e[2][2]*t[2]]}function a(e,t){return[[e[0][0]*t[0],e[0][1]*t[1],e[0][2]*t[2]],[e[1][0]*t[0],e[1][1]*t[1],e[1][2]*t[2]],[e[2][0]*t[0],e[2][1]*t[1],e[2][2]*t[2]]]}function o(e,t){return[[e[0][0]*t[0][0]+e[0][1]*t[1][0]+e[0][2]*t[2][0],e[0][0]*t[0][1]+e[0][1]*t[1][1]+e[0][2]*t[2][1],e[0][0]*t[0][2]+e[0][1]*t[1][2]+e[0][2]*t[2][2]],[e[1][0]*t[0][0]+e[1][1]*t[1][0]+e[1][2]*t[2][0],e[1][0]*t[0][1]+e[1][1]*t[1][1]+e[1][2]*t[2][1],e[1][0]*t[0][2]+e[1][1]*t[1][2]+e[1][2]*t[2][2]],[e[2][0]*t[0][0]+e[2][1]*t[1][0]+e[2][2]*t[2][0],e[2][0]*t[0][1]+e[2][1]*t[1][1]+e[2][2]*t[2][1],e[2][0]*t[0][2]+e[2][1]*t[1][2]+e[2][2]*t[2][2]]]}e.transpose=t,e.determinant=n,e.inverse=r,e.multiply=i,e.scalar=a,e.product=o})),Wr=s((e=>{Object.defineProperty(e,`__esModule`,{value:!0});var t=Math.PI;function n(e){for(var n=e*180/t;n<0;)n+=360;for(;n>360;)n-=360;return n}function r(e){for(var n=t*e/180;n<0;)n+=2*t;for(;n>2*t;)n-=2*t;return n}e.fromRadian=n,e.toRadian=r})),Gr=s((e=>{Object.defineProperty(e,`__esModule`,{value:!0});var t=Math.round;function n(e){return e[0]==`#`&&(e=e.slice(1)),e.length<6&&(e=e.split(``).map(function(e){return e+e}).join(``)),e.match(/../g).map(function(e){return parseInt(e,16)/255})}function r(e){return`#`+e.map(function(e){return e=t(255*e).toString(16),e.length<2&&(e=`0`+e),e}).join(``)}e.fromHex=n,e.toHex=r})),Kr=s(((e,t)=>{Object.defineProperty(e,`__esModule`,{value:!0});var n=o(Ur()),r=a(Vr()),i=a(Hr());function a(e){return e&&e.__esModule?e:{default:e}}function o(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}function s(){var e=arguments.length<=0||arguments[0]===void 0?i.default.sRGB:arguments[0],t=arguments.length<=1||arguments[1]===void 0?r.default.D65:arguments[1],a=[e.r,e.g,e.b],o=n.transpose(a.map(function(e){return[e.x/e.y,1,(1-e.x-e.y)/e.y]})),s=e.gamma,c=n.multiply(n.inverse(o),t),l=n.scalar(o,c),u=n.inverse(l);return{fromRgb:function(e){return n.multiply(l,e.map(s.decode))},toRgb:function(e){return n.multiply(u,e).map(s.encode)}}}e.default=s,t.exports=e.default})),qr=s(((e,t)=>{t.exports={illuminant:Vr(),workspace:Hr(),matrix:Ur(),degree:Wr(),rgb:Gr(),xyz:Kr()}})),Jr=s((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.cfs=e.distance=e.lerp=e.corLerp=void 0;var t=Br();function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);ti/2&&(e>t?t+=i:e+=i),((1-n)*e+n*t)%(i||1/0)}function u(e,t,n){var r={};for(var i in e)r[i]=l(e[i],t[i],n,i);return r}function d(e,t){var n=0;for(var r in e)n+=o(e[r]-t[r],2);return s(n)}function f(e){return t.merge.apply(void 0,r(e.split(``).map(function(e){return n({},e,!0)})))}e.corLerp=l,e.lerp=u,e.distance=d,e.cfs=f})),Yr=s(((e,t)=>{var n=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o=e[Symbol.iterator](),s;!(r=(s=o.next()).done)&&(n.push(s.value),!(t&&n.length===t));r=!0);}catch(e){i=!0,a=e}finally{try{!r&&o.return&&o.return()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw TypeError(`Invalid attempt to destructure non-iterable instance`)}}();Object.defineProperty(e,`__esModule`,{value:!0});var r=qr(),i=Jr();function a(e,t){var a=arguments.length<=2||arguments[2]===void 0?1e-6:arguments[2],o=-a,s=1+a,c=Math,l=c.min,u=c.max,d=n([`000`,`fff`].map(function(n){return t.fromXyz(e.fromRgb(r.rgb.fromHex(n)))}),2),f=d[0],p=d[1];function m(n){var r=e.toRgb(t.toXyz(n));return[r.map(function(e){return e>=o&&e<=s}).reduce(function(e,t){return e&&t},!0),r]}function h(e,t){for(var r=arguments.length<=2||arguments[2]===void 0?.001:arguments[2];(0,i.distance)(e,t)>r;){var a=(0,i.lerp)(e,t,.5);n(m(a),1)[0]?e=a:t=a}return e}function g(e){return(0,i.lerp)(f,p,e)}function _(e){return e.map(function(e){return u(o,l(s,e))})}return{contains:m,limit:h,spine:g,crop:_}}e.default=a,t.exports=e.default})),Xr=s((e=>{var t=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o=e[Symbol.iterator](),s;!(r=(s=o.next()).done)&&(n.push(s.value),!(t&&n.length===t));r=!0);}catch(e){i=!0,a=e}finally{try{!r&&o.return&&o.return()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw TypeError(`Invalid attempt to destructure non-iterable instance`)}}();Object.defineProperty(e,`__esModule`,{value:!0}),e.toNotation=e.fromNotation=e.toHue=e.fromHue=void 0;var n=Jr(),r=Math.floor,i=[{s:`R`,h:20.14,e:.8,H:0},{s:`Y`,h:90,e:.7,H:100},{s:`G`,h:164.25,e:1,H:200},{s:`B`,h:237.53,e:1.2,H:300},{s:`R`,h:380.14,e:.8,H:400}],a=i.map(function(e){return e.s}).slice(0,-1).join(``);function o(e){e50){var o=[n,t];t=o[0],n=o[1],i=100-i}return i<1?a[t]:a[t]+i.toFixed()+a[n]}e.fromHue=o,e.toHue=s,e.fromNotation=l,e.toNotation=u})),Zr=s(((e,t)=>{var n=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o=e[Symbol.iterator](),s;!(r=(s=o.next()).done)&&(n.push(s.value),!(t&&n.length===t));r=!0);}catch(e){i=!0,a=e}finally{try{!r&&o.return&&o.return()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw TypeError(`Invalid attempt to destructure non-iterable instance`)}}();Object.defineProperty(e,`__esModule`,{value:!0});var r=qr(),i=s(Xr()),a=Jr(),o=Br();function s(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var c=Math,l=c.pow,u=c.sqrt,d=c.exp,f=c.abs,p=c.sign,m=Math,h=m.sin,g=m.cos,_=m.atan2,v={average:{F:1,c:.69,N_c:1},dim:{F:.9,c:.59,N_c:.9},dark:{F:.8,c:.535,N_c:.8}},y=[[.7328,.4296,-.1624],[-.7036,1.6975,.0061],[.003,.0136,.9834]],b=[[.38971,.68898,-.07868],[-.22981,1.1834,.04641],[0,0,1]],x=y,S=r.matrix.inverse(y),C=r.matrix.product(b,r.matrix.inverse(y)),w=r.matrix.product(y,r.matrix.inverse(b)),T={whitePoint:r.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:`average`,discounting:!1},ee=(0,a.cfs)(`QJMCshH`),E=(0,a.cfs)(`JCh`);function D(){var e=arguments.length<=0||arguments[0]===void 0?{}:arguments[0],t=arguments.length<=1||arguments[1]===void 0?ee:arguments[1];e=(0,o.merge)(T,e);var a=e.whitePoint,s=e.adaptingLuminance,c=e.backgroundLuminance,m=v[e.surroundType],b=m.F,D=m.c,O=m.N_c,te=a[1],k=1/(5*s+1),A=.2*l(k,4)*5*s+.1*l(1-l(k,4),2)*l(5*s,1/3),ne=c/te,re=.725*l(1/ne,.2),ie=re,ae=1.48+u(ne),oe=e.discounting?1:b*(1-1/3.6*d(-(s+42)/92)),j=n(r.matrix.multiply(y,a).map(function(e){return oe*te/e+1-oe}),3),se=j[0],M=j[1],ce=j[2],N=pe(de(le(a)));function le(e){var t=n(r.matrix.multiply(x,e),3),i=t[0],a=t[1],o=t[2];return[se*i,M*a,ce*o]}function ue(e){var t=n(e,3),i=t[0],a=t[1],o=t[2];return r.matrix.multiply(S,[i/se,a/M,o/ce])}function de(e){return r.matrix.multiply(C,e).map(function(e){var t=l(A*f(e)/100,.42);return p(e)*400*t/(27.13+t)+.1})}function fe(e){return r.matrix.multiply(w,e.map(function(e){var t=e-.1;return p(t)*100/A*l(27.13*f(t)/(400-f(t)),1/.42)}))}function pe(e){var t=n(e,3),r=t[0],i=t[1],a=t[2];return(r*2+i+a/20-.305)*re}function me(e){return 4/D*u(e/100)*(N+4)*l(A,.25)}function he(e){return 6.25*l(D*e/((N+4)*l(A,.25)),2)}function ge(e){return e*l(A,.25)}function _e(e,t){return l(e/100,2)*t/l(A,.25)}function ve(e){return e/l(A,.25)}function ye(e,t){return 100*u(e/t)}function be(e,t){var n=t.Q,r=t.J,a=t.M,o=t.C,s=t.s,c=t.h,l=t.H,u={};return e.J&&(u.J=isNaN(r)?he(n):r),e.C&&(isNaN(o)?isNaN(a)?(n=isNaN(n)?me(r):n,u.C=_e(s,n)):u.C=ve(a):u.C=t.C),e.h&&(u.h=isNaN(c)?i.toHue(l):c),e.Q&&(u.Q=isNaN(n)?me(r):n),e.M&&(u.M=isNaN(a)?ge(o):a),e.s&&(isNaN(s)?(n=isNaN(n)?me(r):n,a=isNaN(a)?ge(o):a,u.s=ye(a,n)):u.s=s),e.H&&(u.H=isNaN(l)?i.fromHue(c):l),u}function P(e){var i=de(le(e)),a=n(i,3),o=a[0],s=a[1],c=a[2],d=o-s*12/11+c/11,f=(o+s-2*c)/9,p=_(f,d),m=r.degree.fromRadian(p),h=1/4*(g(p+2)+3.8),v=100*l(pe(i)/N,D*ae);return be(t,{J:v,C:l(5e4/13*O*ie*h*u(d*d+f*f)/(o+s+21/20*c),.9)*u(v/100)*l(1.64-l(.29,ne),.73),h:m})}function F(e){var t=be(E,e),n=t.J,i=t.C,a=t.h,o=r.degree.toRadian(a),s=l(i/(u(n/100)*l(1.64-l(.29,ne),.73)),10/9),c=1/4*(g(o+2)+3.8),d=N*l(n/100,1/D/ae),p=5e4/13*O*ie*c/s,m=d/re+.305,_=m*61/20*460/1403,v=61/20*220/1403,y=21/20*6300/1403-27/1403,b=h(o),x=g(o),S,C;return s===0||isNaN(s)?S=C=0:f(b)>=f(x)?(C=_/(p/b+v*x/b+y),S=C*x/b):(S=_/(p/x+v+y*b/x),C=S*b/x),ue(fe([20/61*m+451/1403*S+288/1403*C,20/61*m-891/1403*S-261/1403*C,20/61*m-220/1403*S-6300/1403*C]))}return{fromXyz:P,toXyz:F,fillOut:be}}e.default=D,t.exports=e.default})),Qr=s(((e,t)=>{Object.defineProperty(e,`__esModule`,{value:!0});var n=qr(),r=Math,i=r.sqrt,a=r.pow,o=r.exp,s=r.log,c=r.cos,l=r.sin,u=r.atan2,d={LCD:{K_L:.77,c_1:.007,c_2:.0053},SCD:{K_L:1.24,c_1:.007,c_2:.0363},UCS:{K_L:1,c_1:.007,c_2:.0228}};function f(){var e=d[arguments.length<=0||arguments[0]===void 0?`UCS`:arguments[0]],t=e.K_L,r=e.c_1,f=e.c_2;function p(e){var t=e.J,i=e.M,a=e.h,o=n.degree.toRadian(a),u=(1+100*r)*t/(1+r*t),d=1/f*s(1+f*i);return{J_p:u,a_p:d*c(o),b_p:d*l(o)}}function m(e){var t=e.J_p,s=e.a_p,c=e.b_p,l=-t/(r*t-100*r-1),d=(o(f*i(a(s,2)+a(c,2)))-1)/f,p=u(c,s);return{J:l,M:d,h:n.degree.fromRadian(p)}}function h(e,n){return i(a((e.J_p-n.J_p)/t,2)+a(e.a_p-n.a_p,2)+a(e.b_p-n.b_p,2))}return{fromCam:p,toCam:m,distance:h}}e.default=f,t.exports=e.default})),$r=s(((e,t)=>{var n=Jr(),r=Yr(),i=Zr(),a=Qr(),o=Xr();t.exports={gamut:r,cfs:n.cfs,lerp:n.lerp,cam:i,ucs:a,hq:o}})),ei=l(qr(),1),ti=l($r(),1);function ni(e){let t=new q;return t.rgb_r=e[0],t.rgb_g=e[1],t.rgb_b=e[2],t.rgbToHsluv(),[t.hsluv_h,t.hsluv_s,t.hsluv_l]}function ri(e){let t=new q;return t.hsluv_h=e[0],t.hsluv_s=e[1],t.hsluv_l=e[2],t.hsluvToRgb(),[t.rgb_r,t.rgb_g,t.rgb_b]}var ii=ti.default.cam({whitePoint:ei.default.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:`average`,discounting:!1},ti.default.cfs(`JCh`)),ai=ei.default.xyz(ei.default.workspace.sRGB,ei.default.illuminant.D65),oi=e=>ai.toRgb(ii.toXyz({J:e[0],C:e[1],h:e[2]})),si=e=>{let t=ii.fromXyz(ai.fromRgb(e));return[t.J,t.C,t.h]},[ci,li]=(()=>{let e={k_l:1,c1:.007,c2:.0228},t=Math.PI,n=64/t/5,r=1/(5*n+1),i=.2*r**4*(5*n)+.1*(1-r**4)**2*(5*n)**(1/3);return[n=>{let[r,a,o]=n,s=a*i**.25,c=(1+100*e.c1)*r/(1+e.c1*r);c/=e.k_l;let l=1/e.c2*Math.log(1+e.c2*s),u=l*Math.cos(t/180*o),d=l*Math.sin(t/180*o);return[c,u,d]},n=>{let[r,a,o]=n,s=Math.sqrt(a*a+o*o),c=(Math.exp(s*e.c2)-1)/e.c2,l=(180/t*Math.atan2(o,a)+360)%360,u=c/i**.25;return[r/(1+e.c1*(100-r)),u,l]}]})(),ui=e=>oi(li(e)),di=e=>ci(si(e)),fi=console;fi.color=(e,t=``)=>{let n=K(e).luminance();fi.log(`%c${e} ${t}`,`background-color: ${e};padding: 5px; border-radius: 5px; color: ${n>.5?`#000`:`#fff`}`)},fi.ramp=(e,t=1)=>{fi.log(`%c `,`font-size: 1px;line-height: 16px;background: ${K.getCSSGradient(e,t)};padding: 0 0 0 200px; border-radius: 2px;`)};var pi=(e,t,n,r,i,a,o=.1)=>{if(e===n||t===r)return!0;let s=(r-t)/(n-e),c=(a+i/s-t+s*e)/(s+1/s),l=a+i/s-c/s;return(i-c)**2+(a-l)**2{let i=(t[0]+n[0])/2,a=e(i);return pi(...t,...n,i,a,r)?null:[i,a]},hi=(e,t,n,r=.1)=>{let i=(n-t)/10,a=[];for(let r=t;rMath.round(e*10**t)/10**t,_i=(e,t=1,n=90,r=.005)=>{let i=hi(t=>e(t).gl()[0],0,t,r),a=hi(t=>e(t).gl()[1],0,t,r),o=hi(t=>e(t).gl()[2],0,t,r);return`linear-gradient(${n}deg, ${Array.from(new Set([...i.map(e=>gi(e[0])),...a.map(e=>gi(e[0])),...o.map(e=>gi(e[0]))].sort((e,t)=>e-t))).map(t=>`${e(t).hex()} ${gi(t*100)}%`).join()});`},vi=e=>{e.Color.prototype.jch=function(){return si(this._rgb.slice(0,3).map(e=>e/255))},e.jch=(...t)=>new e.Color(...oi(t).map(e=>Math.floor(e*255)),`rgb`),e.Color.prototype.jab=function(){return di(this._rgb.slice(0,3).map(e=>e/255))},e.jab=(...t)=>new e.Color(...ui(t).map(e=>Math.floor(e*255)),`rgb`),e.Color.prototype.hsluv=function(){return ni(this._rgb.slice(0,3).map(e=>e/255))},e.hsluv=(...t)=>new e.Color(...ri(t).map(e=>Math.floor(e*255)),`rgb`);let t=e.interpolate,n={jch:si,jab:di,hsluv:ni},r=(e,t,n)=>(Math.abs(e-t)>360/2&&(e>t?t+=360:e+=360),((1-n)*e+n*t)%360);e.interpolate=(i,a,o=.5,s=`lrgb`)=>{if(n[s]){typeof i!=`object`&&(i=new e.Color(i)),typeof a!=`object`&&(a=new e.Color(a));let t=n[s](i.gl()),c=n[s](a.gl()),l=Number.isNaN(i.hsl()[0]),u=Number.isNaN(a.hsl()[0]),d,f,p;switch(s){case`hsluv`:t[1]<1e-10&&(t[0]=c[0]),t[1]===0&&(t[1]=c[1]),c[1]<1e-10&&(c[0]=t[0]),c[1]===0&&(c[1]=t[1]),d=r(t[0],c[0],o),f=t[1]+(c[1]-t[1])*o,p=t[2]+(c[2]-t[2])*o;break;case`jch`:l&&(t[2]=c[2]),u&&(c[2]=t[2]),d=t[0]+(c[0]-t[0])*o,f=t[1]+(c[1]-t[1])*o,p=r(t[2],c[2],o);break;default:d=t[0]+(c[0]-t[0])*o,f=t[1]+(c[1]-t[1])*o,p=t[2]+(c[2]-t[2])*o}return e[s](d,f,p).alpha(i.alpha()+o*(a.alpha()-i.alpha()))}return t(i,a,o,s)},e.getCSSGradient=_i},X={mainTRC:2.4,get mainTRCencode(){return 1/this.mainTRC},sRco:.2126729,sGco:.7151522,sBco:.072175,normBG:.56,normTXT:.57,revTXT:.62,revBG:.65,blkThrs:.022,blkClmp:1.414,scaleBoW:1.14,scaleWoB:1.14,loBoWoffset:.027,loWoBoffset:.027,deltaYmin:5e-4,loClip:.1,mFactor:1.9468554433171,get mFactInv(){return 1/this.mFactor},mOffsetIn:.0387393816571401,mExpAdj:.283343396420869,get mExp(){return this.mExpAdj/this.blkClmp},mOffsetOut:.312865795870758};function yi(e,t,n=-1){let r=[0,1.1];if(isNaN(e)||isNaN(t)||Math.min(e,t)r[1])return 0;let i=0,a=0,o=`BoW`;return e=e>X.blkThrs?e:e+(X.blkThrs-e)**+X.blkClmp,t=t>X.blkThrs?t:t+(X.blkThrs-t)**+X.blkClmp,Math.abs(t-e)e?(i=(t**+X.normBG-e**+X.normTXT)*X.scaleBoW,a=i-X.loClip?0:i+X.loWoBoffset),n<0?a*100:n==0?Math.round(Math.abs(a)*100)+``+o+``:Number.isInteger(n)?(a*100).toFixed(n):0)}function bi(e=[0,0,0]){function t(e){return(e/255)**X.mainTRC}return X.sRco*t(e[0])+X.sGco*t(e[1])+X.sBco*t(e[2])}var xi=(e,t,n,r,i,a,o,s,c)=>{let l=1-c,u=l*l,d=u*l,f=c*c*c;return{x:d*e+u*3*c*n+l*3*c*c*i+f*o,y:d*t+u*3*c*r+l*3*c*c*a+f*s}},Si=(e,t)=>{let n=[],r={x:+e[0],y:+e[1]};for(let i=0,a=e.length;a-2*!t>i;i+=2){let o=[{x:+e[i-2],y:+e[i-1]},{x:+e[i],y:+e[i+1]},{x:+e[i+2],y:+e[i+3]},{x:+e[i+4],y:+e[i+5]}];t?i?a-4===i?o[3]={x:+e[0],y:+e[1]}:a-2===i&&(o[2]={x:+e[0],y:+e[1]},o[3]={x:+e[2],y:+e[3]}):o[0]={x:+e[a-2],y:+e[a-1]}:a-4===i?o[3]=o[2]:i||(o[0]={x:+e[i],y:+e[i+1]}),n.push([r.x,r.y,(-o[0].x+6*o[1].x+o[2].x)/6,(-o[0].y+6*o[1].y+o[2].y)/6,(o[1].x+6*o[2].x-o[3].x)/6,(o[1].y+6*o[2].y-o[3].y)/6,o[2].x,o[2].y]),r=o[2]}return n},Ci=(e,t,n,r,i,a,o,s)=>{let c=e,l=t,u=0;for(let d=1;d<5;d++){let{x:f,y:p}=xi(e,t,n,r,i,a,o,s,d/5);u+=Math.hypot(f-c,p-l),c=f,l=p}return u+=Math.hypot(o-c,s-l),u},wi=(e,t,n,r,i,a,o,s)=>{let c=Math.floor(Ci(e,t,n,r,i,a,o,s)*.75),l=[],u=0;for(let d=0;d<=c;d++){let f=xi(e,t,n,r,i,a,o,s,d/c),p=Math.round(f.x);if(l[p]=f.y,p-u>1){let e=l[u],t=l[p];for(let n=u+1;nl[Math.round(e)]||null},Ti={CAM02:`jab`,CAM02p:`jch`,HEX:`hex`,HSL:`hsl`,HSLuv:`hsluv`,HSV:`hsv`,LAB:`lab`,LCH:`lch`,RGB:`rgb`,OKLAB:`oklab`,OKLCH:`oklch`};function Z(e,t=0){let n=10**t;return Math.round(e*n)/n}function Ei(e,t){let n;return n=e>1?(e-1)*t+1:e<-1?(e+1)*t-1:1,Z(n,2)}function Di(e){return K(String(e)).jch()}function Oi(e){return K(String(e)).hsluv()}function ki(e,t,n){let r=[[],[],[]];if(e.forEach((e,n)=>r.forEach((r,i)=>r.push(t[n],e[i]))),n===`hcl`){let e=r[1];for(let t=1;t{let t=[];for(let n=1;n{e[t]=e[n]}),t.length=0;break}if(t.length){let n=K(`#ccc`).jch()[2];t.forEach(t=>{e[t]=n})}t.length=0;for(let n=e.length-1;n>0;n-=2)if(Number.isNaN(e[n]))t.push(n);else{t.forEach(t=>{e[t]=e[n]});break}for(let t=1;tSi(e).map(e=>wi(...e)));return e=>{let t=i.map(t=>{for(let n=0;nr*t**e+i}function ji({swatches:e,colorKeys:t,colorspace:n,colorSpace:r=n??`LAB`,shift:i=1,fullScale:a=!0,smooth:o=!1,distributeLightness:s=`linear`,sortColor:c=!0,asFun:l=!1}={}){n!==void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead.");let u=Ti[r];if(!u)throw Error(`Colorspace “${r}” not supported`);if(!t)throw Error(`Colorkeys missing: returned “${t}”`);let d;if(a)d=t.map(t=>e-e*(K(t).jch()[0]/100)).sort((e,t)=>e-t).concat(e),d.unshift(0);else{let n=t.map(e=>K(e).jch()[0]/100),r=Math.min(...n),i=Math.max(...n);d=n.map(t=>t===0||isNaN((t-r)/(i-r))?0:e-(t-r)/(i-r)*e).sort((e,t)=>e-t)}let f=Ai(i,[1,e],[1,e]);if(f=d.map(e=>Math.max(0,f(e))),d=f,s===`polynomial`){let t=e=>Math.sqrt(Math.sqrt((e**2.25+e**4)/2));d=f.map(t=>t/e).map(n=>t(n)*e)}let p=t.map((e,t)=>({colorKeys:Di(e),index:t})).sort((e,t)=>t.colorKeys[0]-e.colorKeys[0]).map(e=>t[e.index]),m=[],h;if(a){let e=u===`lch`?K.lch(...K(`#fff`).lch()):`#ffffff`,t=u===`lch`?K.lch(...K(`#000`).lch()):`#000000`;m=[e,...p,t]}else m=c?p:t;let g;if(o){let t=m;if(m=m.map(e=>K(String(e))[u]()),u===`hcl`&&m.forEach(e=>{e[1]=Number.isNaN(e[1])?0:e[1]}),u===`jch`)for(let e=0;eh(t))}else h=K.scale(m.map(e=>typeof e==`object`&&e.constructor===K.Color?e:String(e))).domain(d).mode(u);return l?h:(!o||o===!1?h.colors(e):g).filter(e=>e!=null)}function Mi(e,t){let n=[],r={};return Object.keys(e).forEach(n=>{r[e[n][t]]=e[n]}),Object.keys(r).forEach(e=>n.push(r[e])),n}function Ni(e){return Number.isNaN(e)?0:e}function Pi(e,t,n=!1){if(!e)throw Error(`Cannot convert color value of “${e}”`);if(!Ti[t])throw Error(`Cannot convert to colorspace “${t}”`);let r=Ti[t],i=K(String(e))[r]();if(t===`HSL`&&i.pop(),t===`HEX`){if(n){let t=K(String(e)).rgb();return{r:t[0],g:t[1],b:t[2]}}return i}let a={},o=i.map(Ni);o=o.map((e,t)=>{let i=Z(e),o=t;r===`hsluv`&&(o+=2);let s=r.charAt(o);return r===`jch`&&s===`c`&&(s=`C`),a[s===`j`?`J`:s]=i,r in{lab:1,lch:1,jab:1,jch:1}?n||(s===`l`||s===`j`)&&(i+=`%`):r!==`hsluv`&&(s===`s`||s===`l`||s===`v`)&&(a[s]=Z(e,2),n||(i=Z(e*100),i+=`%`)),i});let s=`${r}(${o.join(`, `)})`;return n?a:s}function Fi(e,t,n){let r=[e,t,n].map(e=>(e/=255,e<=.03928?e/12.92:((e+.055)/1.055)**2.4));return r[0]*.2126+r[1]*.7152+r[2]*.0722}function Ii(e,t,n,r=`wcag2`){if(n===void 0){let e=K.rgb(...t).hsluv()[2];n=Z(e/100,2)}if(r===`wcag2`){let r=Fi(e[0],e[1],e[2]),i=Fi(t[0],t[1],t[2]),a=(r+.05)/(i+.05),o=(i+.05)/(r+.05);return n<.5?a>=1?a:-o:a<1?o:a===1?a:-a}else if(r===`wcag3`)return n<.5?yi(bi(e),bi(t))*-1:yi(bi(e),bi(t));else throw Error(`Contrast calculation method ${r} unsupported; use 'wcag2' or 'wcag3'`)}function Li(e,t){if(!e)throw Error(`Array undefined`);if(!Array.isArray(e))throw Error(`Passed object is not an array`);let n=t===`wcag2`?0:1;return Math.min(...e.filter(e=>e>=n))}function Ri(e,t){if(!e)throw Error(`Ratios undefined`);e=e.sort((e,t)=>e-t);let n=Li(e,t),r=e.indexOf(n),i=[],a=e.slice(0,r),o=e.slice(r,e.length);for(let e=0;ee-t),i}var zi=(e,t,n,r,i)=>{let a=3e3,o=ji({swatches:a,colorKeys:e._modifiedKeys,colorspace:e._colorspace,shift:1,smooth:e._smooth,asFun:!0}),s={},c=e=>{if(s[e])return s[e];let r=Ii(K(o(e)).rgb(),t,n,i);return s[e]=r,r},l=e=>{let t=c(0).01&&o;)o--,n/=2,iu.push(o(l(+e)))),u},Q=class{constructor({name:e,colorKeys:t,colorspace:n,colorSpace:r=n??`RGB`,ratios:i,smooth:a=!1,output:o=`HEX`,saturation:s=100}){if(n!==void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),this._name=e,this._colorKeys=t,this._modifiedKeys=t,this._colorspace=r,this._ratios=i,this._smooth=a,this._output=o,this._saturation=s,!this._name)throw Error(`Color missing name`);if(!this._colorKeys)throw Error(`Color Keys are undefined`);if(!Ti[this._colorspace])throw Error(`Colorspace “${r}” not supported`);if(!Ti[this._output])throw Error(`Output “${this._output}” not supported`);for(let e=0;e{let n=K(`${t}`).oklch(),r=n[1]*(this._saturation/100),i=K.oklch(n[0],r,n[2]),a=K.rgb(i).hex();e.push(a)}),this._modifiedKeys=e,this._generateColorScale()}_generateColorScale(){this._colorScale=ji({swatches:3e3,colorKeys:this._modifiedKeys,colorSpace:this._colorspace,shift:1,smooth:this._smooth,asFun:!0})}},Bi=class extends Q{get backgroundColorScale(){return this._backgroundColorScale||this._generateColorScale(),this._backgroundColorScale}_generateColorScale(){Q.prototype._generateColorScale.call(this);let e=ji({swatches:1e3,colorKeys:this._colorKeys,colorspace:this._colorspace,shift:1,smooth:this._smooth});e.push(...this.colorKeys);let t=Mi(e.map((e,t)=>({value:Math.round(Oi(e)[2]),index:t})),`value`).map(t=>e[t.index]);return t.length>=101&&(t.length=100,t.push(`#ffffff`)),this._backgroundColorScale=t.map(e=>Pi(e,this._output)),this._backgroundColorScale}},Vi=class{constructor({colors:e,backgroundColor:t,lightness:n,contrast:r=1,saturation:i=100,output:a=`HEX`,formula:o=`wcag2`}){if(this._output=a,this._colors=e,this._lightness=n,this._saturation=i,this._formula=o,this._setBackgroundColor(t),this._setBackgroundColorValue(),this._contrast=r,!this._colors)throw Error(`No colors are defined`);if(!this._backgroundColor)throw Error(`Background color is undefined`);if(e.forEach(e=>{if(!e.ratios)throw Error(`Color ${e.name}'s ratios are undefined`)}),!Ti[this._output])throw Error(`Output “${a}” not supported`);this._saturation<100&&this._updateColorSaturation(this._saturation),this._findContrastColors(),this._findContrastColorPairs(),this._findContrastColorValues()}set formula(e){this._formula=e,this._findContrastColors()}get formula(){return this._formula}set contrast(e){this._contrast=e,this._findContrastColors()}get contrast(){return this._contrast}set lightness(e){this._lightness=e,this._setBackgroundColor(this._backgroundColor),this._findContrastColors()}get lightness(){return this._lightness}set saturation(e){this._saturation=e,this._updateColorSaturation(e),this._findContrastColors()}get saturation(){return this._saturation}set backgroundColor(e){this._setBackgroundColor(e),this._findContrastColors()}get backgroundColorValue(){return this._backgroundColorValue}get backgroundColor(){return this._backgroundColor}set colors(e){this._colors=e,this._findContrastColors()}get colors(){return this._colors}set addColor(e){this._colors.push(e),this._findContrastColors()}set removeColor(e){this._colors=this._colors.filter(t=>t.name!==e.name),this._findContrastColors()}set updateColor(e){if(Array.isArray(e))for(let t=0;tn.name===e[t].color);n=n[0];let r=this._colors.indexOf(n),i=this._colors.filter(n=>n.name!==e[t].color);e[t].name&&(n.name=e[t].name),e[t].colorKeys&&(n.colorKeys=e[t].colorKeys),e[t].ratios&&(n.ratios=e[t].ratios),(e[t].colorSpace!==void 0||e[t].colorspace!==void 0)&&(e[t].colorspace!==void 0&&e[t].colorSpace===void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),n.colorSpace=e[t].colorSpace??e[t].colorspace),e[t].smooth&&(n.smooth=e[t].smooth),n._generateColorScale(),i.splice(r,0,n),this._colors=i}else{let t=this._colors.filter(t=>t.name===e.color);t=t[0];let n=this._colors.indexOf(t),r=this._colors.filter(t=>t.name!==e.color);e.name&&(t.name=e.name),e.colorKeys&&(t.colorKeys=e.colorKeys),e.ratios&&(t.ratios=e.ratios),(e.colorSpace!==void 0||e.colorspace!==void 0)&&(e.colorspace!==void 0&&e.colorSpace===void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),t.colorSpace=e.colorSpace??e.colorspace),e.smooth&&(t.smooth=e.smooth),t._generateColorScale(),r.splice(n,0,t),this._colors=r}this._findContrastColors()}set output(e){this._output=e,this._colors.forEach(e=>{e.output=this._output}),this._backgroundColor.output=this._output,this._findContrastColors()}get output(){return this._output}get contrastColors(){return this._contrastColors}get contrastColorPairs(){return this._contrastColorPairs}get contrastColorValues(){return this._contrastColorValues}_setBackgroundColor(e){if(typeof e==`string`){let t=new Bi({name:`background`,colorKeys:[e],output:`RGB`}),n=Z(K(String(e)).hsluv()[2]);this._backgroundColor=t,this._lightness=n,this._backgroundColorValue=t[this._lightness]}else{e.output=`RGB`;let t=e.backgroundColorScale[this._lightness];this._backgroundColor=e,this._backgroundColorValue=t}}_setBackgroundColorValue(){this._backgroundColorValue=this._backgroundColor.backgroundColorScale[this._lightness]}_updateColorSaturation(e){this._colors.map(t=>{t.saturation=e})}_findContrastColors(){let e=K(String(this._backgroundColorValue)).rgb(),t=this._lightness/100,n={background:Pi(this._backgroundColorValue,this._output)},r=[],i=[],a={...n};return r.push(n),this._colors.map(n=>{if(n.ratios!==void 0){let o,s=[],c={name:n.name,values:s},l;Array.isArray(n.ratios)?l=n.ratios:Array.isArray(n.ratios)||(o=Object.keys(n.ratios),l=Object.values(n.ratios)),l=l.map(e=>Ei(+e,this._contrast));let u=zi(n,e,t,l,this._formula).map(e=>Pi(e,this._output));for(let e=0;e{let t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return[Number.parseInt(t[1],16),Number.parseInt(t[2],16),Number.parseInt(t[3],16)]},Wi=(e,t,n)=>{let r=e/255,i=t/255,a=n/255,o=Math.min(r,i,a),s=Math.max(r,i,a),c=s-o,l=0,u=0,d=0;return l=c===0?0:s===r?(i-a)/c%6:s===i?(a-r)/c+2:(r-i)/c+4,l=Math.round(l*60),l<0&&(l+=360),d=(s+o)/2,u=c===0?0:c/(1-Math.abs(2*d-1)),u=+(u*100).toFixed(1),d=+(d*100).toFixed(1),[l,u,Math.round(d)]},Gi=(e,t,n,r)=>{let i=n/100,a=t*Math.min(i,1-i)/100,o=t=>{let n=(t+e/30)%12,r=i-a*Math.max(Math.min(n-3,9-n,1),-1);return Math.round(255*r).toString(16).padStart(2,`0`).toUpperCase()},s=o(0),c=o(8),l=o(4),u=((e,t,n)=>Math.min(Math.max(e,t),n))(r,0,1);return`#${s}${c}${l}${Math.round(u*255).toString(16).padStart(2,`0`).toUpperCase()}`},Ki=(e,t,n=1)=>{let r=Ui(e),i=Ui(t===`white`?`#FFFFFF`:t===`black`?`#000000`:t),a=r.map((e,t)=>[(e-i[t])/(255-i[t]),(e-i[t])/(0-i[t])]),o=Hi(Math.max(...a.flat().filter(e=>/^-?\d+\.?\d*$/.test(e)))),s=r.map((e,t)=>Math.round((e-i[t]+i[t]*o)/o));if(s.includes(NaN)){let e=Wi(r[0],r[1],r[2]);return{h:e[0],s:Math.round(e[1]*n),l:e[2],a:1}}let c=Wi(s[0],s[1],s[2]);return{h:c[0],s:Math.round(c[1]*n),l:c[2],a:o}},qi={backgroundColor:`gray`,colorSpace:`OKLCH`,colorSmoothing:!1,formula:`wcag2`,output:`HEX`,colors:{gray:[$(215,20,90),$(215,8,50),$(215,6,25)],red:[$(358,100,58),$(350,100,30)],orange:[$(32,100,48),$(12,100,30)],yellow:[$(50,100,50),$(25,100,20)],lime:[$(100,68,50),$(115,86,25)],green:[$(163,87,42),$(168,100,25)],cyan:[$(185,80,45),$(200,98,35)],blue:[$(212,98,46),$(222,95,25)],purple:[$(258,94,64),$(265,100,35)],fuchsia:[$(295,56,50),$(285,80,25)],pink:[$(334,90,50),$(330,91,25)]},themes:{light:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16.75],contrast:1,lightness:100,saturation:100},dark:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16],contrast:1,lightness:6,saturation:97},lightHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:100,saturation:100},darkHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:6,saturation:97}}};function $(e,t,n){return K.hsl(e,t/100,n/100).hex()}function Ji(e,t){let n=e.colorSpace,r=e.colorSmoothing,i=e.themes[t].ratios,a=new Bi({name:`gray`,colorKeys:e.colors.gray,colorspace:n,ratios:i,smooth:r}),o=new Q({name:`blue`,colorKeys:e.colors.blue,colorspace:n,ratios:i,smooth:r}),s=new Q({name:`cyan`,colorKeys:e.colors.cyan,colorspace:n,ratios:i,smooth:r}),c=new Q({name:`fuchsia`,colorKeys:e.colors.fuchsia,colorspace:n,ratios:i,smooth:r}),l=new Q({name:`green`,colorKeys:e.colors.green,colorspace:n,ratios:i,smooth:r}),u=new Q({name:`lime`,colorKeys:e.colors.lime,colorspace:n,ratios:i,smooth:r}),d=new Q({name:`orange`,colorKeys:e.colors.orange,colorspace:n,ratios:i,smooth:r}),f=new Q({name:`pink`,colorKeys:e.colors.pink,colorspace:n,ratios:i,smooth:r}),p=new Q({name:`purple`,colorKeys:e.colors.purple,colorspace:n,ratios:i,smooth:r}),m={gray:a,red:new Q({name:`red`,colorKeys:e.colors.red,colorspace:n,ratios:i,smooth:r}),orange:d,yellow:new Q({name:`yellow`,colorKeys:e.colors.yellow,colorspace:n,ratios:i,smooth:r}),lime:u,green:l,cyan:s,blue:o,purple:p,fuchsia:c,pink:f};return e.colors.custom&&(m.custom=new Q({name:`custom`,colorKeys:e.colors.custom,colorspace:n,ratios:i,smooth:r})),new Vi({colors:Object.values(m),backgroundColor:m[e.backgroundColor],contrast:e.themes[t].contrast,lightness:e.themes[t].lightness,saturation:e.themes[t].saturation,output:e.output,formula:e.formula}).contrastColors}function Yi(e){let t={};for(let n of Object.keys(e.themes))t[n]=Ji(e,n);return t}function Xi(e){qi.colors.custom=[e];let t=Yi(qi);return Object.fromEntries(Object.entries(t).map(([e,t])=>{let n=t.find(e=>e&&e.name===`custom`),r=Object.fromEntries(n.values.map(({name:e,value:t})=>[e,t]));for(let[e,n]of Object.entries(r)){let i=Ki(n,t[0].background);r[`alpha${e.charAt(0).toUpperCase()+e.slice(1)}`]=Gi(i.h,i.s,i.l,i.a)}return[e,r]}))}return e.generateCustomColors=Xi,e.generateThemesJson=Yi,e.hslToHex=$,e.leonardoConfig=qi,e})({}); \ No newline at end of file +var CompoundTheme=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),c=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;lt[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},l=(e,r,i)=>(i=e==null?{}:t(a(e)),c(r||!e||!e.__esModule?n(i,`default`,{value:e,enumerable:!0}):i,e)),{min:u,max:d}=Math,f=(e,t=0,n=1)=>u(d(t,e),n),p=e=>{e._clipped=!1,e._unclipped=e.slice(0);for(let t=0;t<=3;t++)t<3?((e[t]<0||e[t]>255)&&(e._clipped=!0),e[t]=f(e[t],0,255)):t===3&&(e[t]=f(e[t],0,1));return e},m={};for(let e of[`Boolean`,`Number`,`String`,`Function`,`Array`,`Date`,`RegExp`,`Undefined`,`Null`])m[`[object ${e}]`]=e.toLowerCase();function h(e){return m[Object.prototype.toString.call(e)]||`object`}var g=(e,t=null)=>e.length>=3?Array.prototype.slice.call(e):h(e[0])==`object`&&t?t.split(``).filter(t=>e[0][t]!==void 0).map(t=>e[0][t]):e[0].slice(0),_=e=>{if(e.length<2)return null;let t=e.length-1;return h(e[t])==`string`?e[t].toLowerCase():null},{PI:v,min:y,max:b}=Math,x=e=>Math.round(e*100)/100,S=e=>Math.round(e*100)/100,C=v*2,w=v/3,T=v/180,ee=180/v;function E(e){return[...e.slice(0,3).reverse(),...e.slice(3)]}var D={format:{},autodetect:[]},O=class{constructor(...e){let t=this;if(h(e[0])===`object`&&e[0].constructor&&e[0].constructor===this.constructor)return e[0];let n=_(e),r=!1;if(!n){r=!0,D.sorted||=(D.autodetect=D.autodetect.sort((e,t)=>t.p-e.p),!0);for(let t of D.autodetect)if(n=t.test(...e),n)break}if(D.format[n])t._rgb=p(D.format[n].apply(null,r?e:e.slice(0,-1)));else throw Error(`unknown format: `+e);t._rgb.length===3&&t._rgb.push(1)}toString(){return h(this.hex)==`function`?this.hex():`[${this._rgb.join(`,`)}]`}},te=`3.2.0`,k=(...e)=>new O(...e);k.version=te;var A={aliceblue:`#f0f8ff`,antiquewhite:`#faebd7`,aqua:`#00ffff`,aquamarine:`#7fffd4`,azure:`#f0ffff`,beige:`#f5f5dc`,bisque:`#ffe4c4`,black:`#000000`,blanchedalmond:`#ffebcd`,blue:`#0000ff`,blueviolet:`#8a2be2`,brown:`#a52a2a`,burlywood:`#deb887`,cadetblue:`#5f9ea0`,chartreuse:`#7fff00`,chocolate:`#d2691e`,coral:`#ff7f50`,cornflowerblue:`#6495ed`,cornsilk:`#fff8dc`,crimson:`#dc143c`,cyan:`#00ffff`,darkblue:`#00008b`,darkcyan:`#008b8b`,darkgoldenrod:`#b8860b`,darkgray:`#a9a9a9`,darkgreen:`#006400`,darkgrey:`#a9a9a9`,darkkhaki:`#bdb76b`,darkmagenta:`#8b008b`,darkolivegreen:`#556b2f`,darkorange:`#ff8c00`,darkorchid:`#9932cc`,darkred:`#8b0000`,darksalmon:`#e9967a`,darkseagreen:`#8fbc8f`,darkslateblue:`#483d8b`,darkslategray:`#2f4f4f`,darkslategrey:`#2f4f4f`,darkturquoise:`#00ced1`,darkviolet:`#9400d3`,deeppink:`#ff1493`,deepskyblue:`#00bfff`,dimgray:`#696969`,dimgrey:`#696969`,dodgerblue:`#1e90ff`,firebrick:`#b22222`,floralwhite:`#fffaf0`,forestgreen:`#228b22`,fuchsia:`#ff00ff`,gainsboro:`#dcdcdc`,ghostwhite:`#f8f8ff`,gold:`#ffd700`,goldenrod:`#daa520`,gray:`#808080`,green:`#008000`,greenyellow:`#adff2f`,grey:`#808080`,honeydew:`#f0fff0`,hotpink:`#ff69b4`,indianred:`#cd5c5c`,indigo:`#4b0082`,ivory:`#fffff0`,khaki:`#f0e68c`,laserlemon:`#ffff54`,lavender:`#e6e6fa`,lavenderblush:`#fff0f5`,lawngreen:`#7cfc00`,lemonchiffon:`#fffacd`,lightblue:`#add8e6`,lightcoral:`#f08080`,lightcyan:`#e0ffff`,lightgoldenrod:`#fafad2`,lightgoldenrodyellow:`#fafad2`,lightgray:`#d3d3d3`,lightgreen:`#90ee90`,lightgrey:`#d3d3d3`,lightpink:`#ffb6c1`,lightsalmon:`#ffa07a`,lightseagreen:`#20b2aa`,lightskyblue:`#87cefa`,lightslategray:`#778899`,lightslategrey:`#778899`,lightsteelblue:`#b0c4de`,lightyellow:`#ffffe0`,lime:`#00ff00`,limegreen:`#32cd32`,linen:`#faf0e6`,magenta:`#ff00ff`,maroon:`#800000`,maroon2:`#7f0000`,maroon3:`#b03060`,mediumaquamarine:`#66cdaa`,mediumblue:`#0000cd`,mediumorchid:`#ba55d3`,mediumpurple:`#9370db`,mediumseagreen:`#3cb371`,mediumslateblue:`#7b68ee`,mediumspringgreen:`#00fa9a`,mediumturquoise:`#48d1cc`,mediumvioletred:`#c71585`,midnightblue:`#191970`,mintcream:`#f5fffa`,mistyrose:`#ffe4e1`,moccasin:`#ffe4b5`,navajowhite:`#ffdead`,navy:`#000080`,oldlace:`#fdf5e6`,olive:`#808000`,olivedrab:`#6b8e23`,orange:`#ffa500`,orangered:`#ff4500`,orchid:`#da70d6`,palegoldenrod:`#eee8aa`,palegreen:`#98fb98`,paleturquoise:`#afeeee`,palevioletred:`#db7093`,papayawhip:`#ffefd5`,peachpuff:`#ffdab9`,peru:`#cd853f`,pink:`#ffc0cb`,plum:`#dda0dd`,powderblue:`#b0e0e6`,purple:`#800080`,purple2:`#7f007f`,purple3:`#a020f0`,rebeccapurple:`#663399`,red:`#ff0000`,rosybrown:`#bc8f8f`,royalblue:`#4169e1`,saddlebrown:`#8b4513`,salmon:`#fa8072`,sandybrown:`#f4a460`,seagreen:`#2e8b57`,seashell:`#fff5ee`,sienna:`#a0522d`,silver:`#c0c0c0`,skyblue:`#87ceeb`,slateblue:`#6a5acd`,slategray:`#708090`,slategrey:`#708090`,snow:`#fffafa`,springgreen:`#00ff7f`,steelblue:`#4682b4`,tan:`#d2b48c`,teal:`#008080`,thistle:`#d8bfd8`,tomato:`#ff6347`,turquoise:`#40e0d0`,violet:`#ee82ee`,wheat:`#f5deb3`,white:`#ffffff`,whitesmoke:`#f5f5f5`,yellow:`#ffff00`,yellowgreen:`#9acd32`},ne=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,re=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,ie=e=>{if(e.match(ne)){(e.length===4||e.length===7)&&(e=e.substr(1)),e.length===3&&(e=e.split(``),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);let t=parseInt(e,16);return[t>>16,t>>8&255,t&255,1]}if(e.match(re)){(e.length===5||e.length===9)&&(e=e.substr(1)),e.length===4&&(e=e.split(``),e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]);let t=parseInt(e,16);return[t>>24&255,t>>16&255,t>>8&255,Math.round((t&255)/255*100)/100]}throw Error(`unknown hex color: ${e}`)},{round:ae}=Math,oe=(...e)=>{let[t,n,r,i]=g(e,`rgba`),a=_(e)||`auto`;i===void 0&&(i=1),a===`auto`&&(a=i<1?`rgba`:`rgb`),t=ae(t),n=ae(n),r=ae(r);let o=`000000`+(t<<16|n<<8|r).toString(16);o=o.substr(o.length-6);let s=`0`+ae(i*255).toString(16);switch(s=s.substr(s.length-2),a.toLowerCase()){case`rgba`:return`#${o}${s}`;case`argb`:return`#${s}${o}`;default:return`#${o}`}};O.prototype.name=function(){let e=oe(this._rgb,`rgb`);for(let t of Object.keys(A))if(A[t]===e)return t.toLowerCase();return e},D.format.named=e=>{if(e=e.toLowerCase(),A[e])return ie(A[e]);throw Error(`unknown color name: `+e)},D.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&h(e)===`string`&&A[e.toLowerCase()])return`named`}}),O.prototype.alpha=function(e,t=!1){return e!==void 0&&h(e)===`number`?t?(this._rgb[3]=e,this):new O([this._rgb[0],this._rgb[1],this._rgb[2],e],`rgb`):this._rgb[3]},O.prototype.clipped=function(){return this._rgb._clipped||!1};var j={Kn:18,labWhitePoint:`d65`,Xn:.95047,Yn:1,Zn:1.08883,t0:.137931034,t1:.206896552,t2:.12841855,t3:.008856452,kE:216/24389,kKE:8,kK:24389/27,RefWhiteRGB:{X:.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:.4124564390896922,m01:.21267285140562253,m02:.0193338955823293,m10:.357576077643909,m11:.715152155287818,m12:.11919202588130297,m20:.18043748326639894,m21:.07217499330655958,m22:.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-.9692660305051868,m02:.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-.2040259135167538,m20:-.498531409556016,m21:.041556017530349834,m22:1.0572251882231791},As:.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:.8951,m01:-.7502,m02:.0389,m10:.2664,m11:1.7135,m12:-.0685,m20:-.1614,m21:.0367,m22:1.0296},MtxAdaptMaI:{m00:.9869929054667123,m01:.43230526972339456,m02:-.008528664575177328,m10:-.14705425642099013,m11:.5183602715367776,m12:.04004282165408487,m20:.15996265166373125,m21:.0492912282128556,m22:.9684866957875502}},se=new Map([[`a`,[1.0985,.35585]],[`b`,[1.0985,.35585]],[`c`,[.98074,1.18232]],[`d50`,[.96422,.82521]],[`d55`,[.95682,.92149]],[`d65`,[.95047,1.08883]],[`e`,[1,1,1]],[`f2`,[.99186,.67393]],[`f7`,[.95041,1.08747]],[`f11`,[1.00962,.6435]],[`icc`,[.96422,.82521]]]);function M(e){let t=se.get(String(e).toLowerCase());if(!t)throw Error(`unknown Lab illuminant `+e);j.labWhitePoint=e,j.Xn=t[0],j.Zn=t[1]}function ce(){return j.labWhitePoint}var N=(...e)=>{e=g(e,`lab`);let[t,n,r]=e,[i,a,o]=le(t,n,r),[s,c,l]=de(i,a,o);return[s,c,l,e.length>3?e[3]:1]},le=(e,t,n)=>{let{kE:r,kK:i,kKE:a,Xn:o,Yn:s,Zn:c}=j,l=(e+16)/116,u=.002*t+l,d=l-.005*n,f=u*u*u,p=d*d*d,m=f>r?f:(116*u-16)/i,h=e>a?((e+16)/116)**3:e/i,g=p>r?p:(116*d-16)/i;return[m*o,h*s,g*c]},ue=e=>{let t=Math.sign(e);return e=Math.abs(e),(e<=.0031308?e*12.92:1.055*e**(1/2.4)-.055)*t},de=(e,t,n)=>{let{MtxAdaptMa:r,MtxAdaptMaI:i,MtxXYZ2RGB:a,RefWhiteRGB:o,Xn:s,Yn:c,Zn:l}=j,u=s*r.m00+c*r.m10+l*r.m20,d=s*r.m01+c*r.m11+l*r.m21,f=s*r.m02+c*r.m12+l*r.m22,p=o.X*r.m00+o.Y*r.m10+o.Z*r.m20,m=o.X*r.m01+o.Y*r.m11+o.Z*r.m21,h=o.X*r.m02+o.Y*r.m12+o.Z*r.m22,g=(e*r.m00+t*r.m10+n*r.m20)*(p/u),_=(e*r.m01+t*r.m11+n*r.m21)*(m/d),v=(e*r.m02+t*r.m12+n*r.m22)*(h/f),y=g*i.m00+_*i.m10+v*i.m20,b=g*i.m01+_*i.m11+v*i.m21,x=g*i.m02+_*i.m12+v*i.m22,S=ue(y*a.m00+b*a.m10+x*a.m20),C=ue(y*a.m01+b*a.m11+x*a.m21),w=ue(y*a.m02+b*a.m12+x*a.m22);return[S*255,C*255,w*255]},fe=(...e)=>{let[t,n,r,...i]=g(e,`rgb`),[a,o,s]=he(t,n,r),[c,l,u]=pe(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]};function pe(e,t,n){let{Xn:r,Yn:i,Zn:a,kE:o,kK:s}=j,c=e/r,l=t/i,u=n/a,d=c>o?c**(1/3):(s*c+16)/116,f=l>o?l**(1/3):(s*l+16)/116,p=u>o?u**(1/3):(s*u+16)/116;return[116*f-16,500*(d-f),200*(f-p)]}function me(e){let t=Math.sign(e);return e=Math.abs(e),(e<=.04045?e/12.92:((e+.055)/1.055)**2.4)*t}var he=(e,t,n)=>{e=me(e/255),t=me(t/255),n=me(n/255);let{MtxRGB2XYZ:r,MtxAdaptMa:i,MtxAdaptMaI:a,Xn:o,Yn:s,Zn:c,As:l,Bs:u,Cs:d}=j,f=e*r.m00+t*r.m10+n*r.m20,p=e*r.m01+t*r.m11+n*r.m21,m=e*r.m02+t*r.m12+n*r.m22,h=o*i.m00+s*i.m10+c*i.m20,g=o*i.m01+s*i.m11+c*i.m21,_=o*i.m02+s*i.m12+c*i.m22,v=f*i.m00+p*i.m10+m*i.m20,y=f*i.m01+p*i.m11+m*i.m21,b=f*i.m02+p*i.m12+m*i.m22;return v*=h/l,y*=g/u,b*=_/d,f=v*a.m00+y*a.m10+b*a.m20,p=v*a.m01+y*a.m11+b*a.m21,m=v*a.m02+y*a.m12+b*a.m22,[f,p,m]};O.prototype.lab=function(){return fe(this._rgb)},Object.assign(k,{lab:(...e)=>new O(...e,`lab`),getLabWhitePoint:ce,setLabWhitePoint:M}),D.format.lab=N,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`lab`),h(e)===`array`&&e.length===3)return`lab`}}),O.prototype.darken=function(e=1){let t=this,n=t.lab();return n[0]-=j.Kn*e,new O(n,`lab`).alpha(t.alpha(),!0)},O.prototype.brighten=function(e=1){return this.darken(-e)},O.prototype.darker=O.prototype.darken,O.prototype.brighter=O.prototype.brighten,O.prototype.get=function(e){let[t,n]=e.split(`.`),r=this[t]();if(n){let e=t.indexOf(n)-(t.substr(0,2)===`ok`?2:0);if(e>-1)return r[e];throw Error(`unknown channel ${n} in mode ${t}`)}else return r};var{pow:ge}=Math,_e=1e-7,ve=20;O.prototype.luminance=function(e,t=`rgb`){if(e!==void 0&&h(e)===`number`){if(e===0)return new O([0,0,0,this._rgb[3]],`rgb`);if(e===1)return new O([255,255,255,this._rgb[3]],`rgb`);let n=this.luminance(),r=ve,i=(n,a)=>{let o=n.interpolate(a,.5,t),s=o.luminance();return Math.abs(e-s)<_e||!r--?o:s>e?i(n,o):i(o,a)};return new O([...(n>e?i(new O([0,0,0]),this):i(this,new O([255,255,255]))).rgb(),this._rgb[3]])}return ye(...this._rgb.slice(0,3))};var ye=(e,t,n)=>(e=be(e),t=be(t),n=be(n),.2126*e+.7152*t+.0722*n),be=e=>(e/=255,e<=.03928?e/12.92:ge((e+.055)/1.055,2.4)),P={},F=(e,t,n=.5,...r)=>{let i=r[0]||`lrgb`;if(!P[i]&&!r.length&&(i=Object.keys(P)[0]),!P[i])throw Error(`interpolation mode ${i} is not defined`);return h(e)!==`object`&&(e=new O(e)),h(t)!==`object`&&(t=new O(t)),P[i](e,t,n).alpha(e.alpha()+n*(t.alpha()-e.alpha()))};O.prototype.mix=O.prototype.interpolate=function(e,t=.5,...n){return F(this,e,t,...n)},O.prototype.premultiply=function(e=!1){let t=this._rgb,n=t[3];return e?(this._rgb=[t[0]*n,t[1]*n,t[2]*n,n],this):new O([t[0]*n,t[1]*n,t[2]*n,n],`rgb`)};var{sin:xe,cos:Se}=Math,Ce=(...e)=>{let[t,n,r]=g(e,`lch`);return isNaN(r)&&(r=0),r*=T,[t,Se(r)*n,xe(r)*n]},we=(...e)=>{e=g(e,`lch`);let[t,n,r]=e,[i,a,o]=Ce(t,n,r),[s,c,l]=N(i,a,o);return[s,c,l,e.length>3?e[3]:1]},Te=(...e)=>we(...E(g(e,`hcl`))),{sqrt:Ee,atan2:De,round:Oe}=Math,ke=(...e)=>{let[t,n,r]=g(e,`lab`),i=Ee(n*n+r*r),a=(De(r,n)*ee+360)%360;return Oe(i*1e4)===0&&(a=NaN),[t,i,a]},Ae=(...e)=>{let[t,n,r,...i]=g(e,`rgb`),[a,o,s]=fe(t,n,r),[c,l,u]=ke(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]};O.prototype.lch=function(){return Ae(this._rgb)},O.prototype.hcl=function(){return E(Ae(this._rgb))},Object.assign(k,{lch:(...e)=>new O(...e,`lch`),hcl:(...e)=>new O(...e,`hcl`)}),D.format.lch=we,D.format.hcl=Te,[`lch`,`hcl`].forEach(e=>D.autodetect.push({p:2,test:(...t)=>{if(t=g(t,e),h(t)===`array`&&t.length===3)return e}})),O.prototype.saturate=function(e=1){let t=this,n=t.lch();return n[1]+=j.Kn*e,n[1]<0&&(n[1]=0),new O(n,`lch`).alpha(t.alpha(),!0)},O.prototype.desaturate=function(e=1){return this.saturate(-e)},O.prototype.set=function(e,t,n=!1){let[r,i]=e.split(`.`),a=this[r]();if(i){let e=r.indexOf(i)-(r.substr(0,2)===`ok`?2:0);if(e>-1){if(h(t)==`string`)switch(t.charAt(0)){case`+`:a[e]+=+t;break;case`-`:a[e]+=+t;break;case`*`:a[e]*=+t.substr(1);break;case`/`:a[e]/=+t.substr(1);break;default:a[e]=+t}else if(h(t)===`number`)a[e]=t;else throw Error(`unsupported value for Color.set`);let i=new O(a,r);return n?(this._rgb=i._rgb,this):i}throw Error(`unknown channel ${i} in mode ${r}`)}else return a},O.prototype.tint=function(e=.5,...t){return F(this,`white`,e,...t)},O.prototype.shade=function(e=.5,...t){return F(this,`black`,e,...t)},P.rgb=(e,t,n)=>{let r=e._rgb,i=t._rgb;return new O(r[0]+n*(i[0]-r[0]),r[1]+n*(i[1]-r[1]),r[2]+n*(i[2]-r[2]),`rgb`)};var{sqrt:je,pow:Me}=Math;P.lrgb=(e,t,n)=>{let[r,i,a]=e._rgb,[o,s,c]=t._rgb;return new O(je(Me(r,2)*(1-n)+Me(o,2)*n),je(Me(i,2)*(1-n)+Me(s,2)*n),je(Me(a,2)*(1-n)+Me(c,2)*n),`rgb`)},P.lab=(e,t,n)=>{let r=e.lab(),i=t.lab();return new O(r[0]+n*(i[0]-r[0]),r[1]+n*(i[1]-r[1]),r[2]+n*(i[2]-r[2]),`lab`)};var Ne=(e,t,n,r)=>{let i,a;r===`hsl`?(i=e.hsl(),a=t.hsl()):r===`hsv`?(i=e.hsv(),a=t.hsv()):r===`hcg`?(i=e.hcg(),a=t.hcg()):r===`hsi`?(i=e.hsi(),a=t.hsi()):r===`lch`||r===`hcl`?(r=`hcl`,i=e.hcl(),a=t.hcl()):r===`oklch`&&(i=e.oklch().reverse(),a=t.oklch().reverse());let o,s,c,l,u,d;(r.substr(0,1)===`h`||r===`oklch`)&&([o,c,u]=i,[s,l,d]=a);let f,p,m,h;return!isNaN(o)&&!isNaN(s)?(h=s>o&&s-o>180?s-(o+360):s180?s+360-o:s-o,p=o+n*h):isNaN(o)?isNaN(s)?p=NaN:(p=s,(u==1||u==0)&&r!=`hsv`&&(f=l)):(p=o,(d==1||d==0)&&r!=`hsv`&&(f=c)),f===void 0&&(f=c+n*(l-c)),m=u+n*(d-u),r===`oklch`?new O([m,f,p],r):new O([p,f,m],r)},Pe=(e,t,n)=>Ne(e,t,n,`lch`);P.lch=Pe,P.hcl=Pe;var Fe=e=>{if(h(e)==`number`&&e>=0&&e<=16777215)return[e>>16,e>>8&255,e&255,1];throw Error(`unknown num color: `+e)},Ie=(...e)=>{let[t,n,r]=g(e,`rgb`);return(t<<16)+(n<<8)+r};O.prototype.num=function(){return Ie(this._rgb)},Object.assign(k,{num:(...e)=>new O(...e,`num`)}),D.format.num=Fe,D.autodetect.push({p:5,test:(...e)=>{if(e.length===1&&h(e[0])===`number`&&e[0]>=0&&e[0]<=16777215)return`num`}}),P.num=(e,t,n)=>{let r=e.num();return new O(r+n*(t.num()-r),`num`)};var{floor:Le}=Math,Re=(...e)=>{e=g(e,`hcg`);let[t,n,r]=e,i,a,o;r*=255;let s=n*255;if(n===0)i=a=o=r;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;let e=Le(t),c=t-e,l=r*(1-n),u=l+s*(1-c),d=l+s*c,f=l+s;switch(e){case 0:[i,a,o]=[f,d,l];break;case 1:[i,a,o]=[u,f,l];break;case 2:[i,a,o]=[l,f,d];break;case 3:[i,a,o]=[l,u,f];break;case 4:[i,a,o]=[d,l,f];break;case 5:[i,a,o]=[f,l,u];break}}return[i,a,o,e.length>3?e[3]:1]},ze=(...e)=>{let[t,n,r]=g(e,`rgb`),i=y(t,n,r),a=b(t,n,r),o=a-i,s=o*100/255,c=i/(255-o)*100,l;return o===0?l=NaN:(t===a&&(l=(n-r)/o),n===a&&(l=2+(r-t)/o),r===a&&(l=4+(t-n)/o),l*=60,l<0&&(l+=360)),[l,s,c]};O.prototype.hcg=function(){return ze(this._rgb)},k.hcg=(...e)=>new O(...e,`hcg`),D.format.hcg=Re,D.autodetect.push({p:1,test:(...e)=>{if(e=g(e,`hcg`),h(e)===`array`&&e.length===3)return`hcg`}}),P.hcg=(e,t,n)=>Ne(e,t,n,`hcg`);var{cos:Be}=Math,Ve=(...e)=>{e=g(e,`hsi`);let[t,n,r]=e,i,a,o;return isNaN(t)&&(t=0),isNaN(n)&&(n=0),t>360&&(t-=360),t<0&&(t+=360),t/=360,t<1/3?(o=(1-n)/3,i=(1+n*Be(C*t)/Be(w-C*t))/3,a=1-(o+i)):t<2/3?(t-=1/3,i=(1-n)/3,a=(1+n*Be(C*t)/Be(w-C*t))/3,o=1-(i+a)):(t-=2/3,a=(1-n)/3,o=(1+n*Be(C*t)/Be(w-C*t))/3,i=1-(a+o)),i=f(r*i*3),a=f(r*a*3),o=f(r*o*3),[i*255,a*255,o*255,e.length>3?e[3]:1]},{min:He,sqrt:Ue,acos:We}=Math,Ge=(...e)=>{let[t,n,r]=g(e,`rgb`);t/=255,n/=255,r/=255;let i,a=He(t,n,r),o=(t+n+r)/3,s=o>0?1-a/o:0;return s===0?i=NaN:(i=(t-n+(t-r))/2,i/=Ue((t-n)*(t-n)+(t-r)*(n-r)),i=We(i),r>n&&(i=C-i),i/=C),[i*360,s,o]};O.prototype.hsi=function(){return Ge(this._rgb)},k.hsi=(...e)=>new O(...e,`hsi`),D.format.hsi=Ve,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`hsi`),h(e)===`array`&&e.length===3)return`hsi`}}),P.hsi=(e,t,n)=>Ne(e,t,n,`hsi`);var Ke=(...e)=>{e=g(e,`hsl`);let[t,n,r]=e,i,a,o;if(n===0)i=a=o=r*255;else{let e=[0,0,0],s=[0,0,0],c=r<.5?r*(1+n):r+n-r*n,l=2*r-c,u=t/360;e[0]=u+1/3,e[1]=u,e[2]=u-1/3;for(let t=0;t<3;t++)e[t]<0&&(e[t]+=1),e[t]>1&&--e[t],6*e[t]<1?s[t]=l+(c-l)*6*e[t]:2*e[t]<1?s[t]=c:3*e[t]<2?s[t]=l+(c-l)*(2/3-e[t])*6:s[t]=l;[i,a,o]=[s[0]*255,s[1]*255,s[2]*255]}return e.length>3?[i,a,o,e[3]]:[i,a,o,1]},qe=(...e)=>{e=g(e,`rgba`);let[t,n,r]=e;t/=255,n/=255,r/=255;let i=y(t,n,r),a=b(t,n,r),o=(a+i)/2,s,c;return a===i?(s=0,c=NaN):s=o<.5?(a-i)/(a+i):(a-i)/(2-a-i),t==a?c=(n-r)/(a-i):n==a?c=2+(r-t)/(a-i):r==a&&(c=4+(t-n)/(a-i)),c*=60,c<0&&(c+=360),e.length>3&&e[3]!==void 0?[c,s,o,e[3]]:[c,s,o]};O.prototype.hsl=function(){return qe(this._rgb)},k.hsl=(...e)=>new O(...e,`hsl`),D.format.hsl=Ke,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`hsl`),h(e)===`array`&&e.length===3)return`hsl`}}),P.hsl=(e,t,n)=>Ne(e,t,n,`hsl`);var{floor:Je}=Math,Ye=(...e)=>{e=g(e,`hsv`);let[t,n,r]=e,i,a,o;if(r*=255,n===0)i=a=o=r;else{t===360&&(t=0),t>360&&(t-=360),t<0&&(t+=360),t/=60;let e=Je(t),s=t-e,c=r*(1-n),l=r*(1-n*s),u=r*(1-n*(1-s));switch(e){case 0:[i,a,o]=[r,u,c];break;case 1:[i,a,o]=[l,r,c];break;case 2:[i,a,o]=[c,r,u];break;case 3:[i,a,o]=[c,l,r];break;case 4:[i,a,o]=[u,c,r];break;case 5:[i,a,o]=[r,c,l];break}}return[i,a,o,e.length>3?e[3]:1]},{min:Xe,max:Ze}=Math,Qe=(...e)=>{e=g(e,`rgb`);let[t,n,r]=e,i=Xe(t,n,r),a=Ze(t,n,r),o=a-i,s,c,l;return l=a/255,a===0?(s=NaN,c=0):(c=o/a,t===a&&(s=(n-r)/o),n===a&&(s=2+(r-t)/o),r===a&&(s=4+(t-n)/o),s*=60,s<0&&(s+=360)),[s,c,l]};O.prototype.hsv=function(){return Qe(this._rgb)},k.hsv=(...e)=>new O(...e,`hsv`),D.format.hsv=Ye,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`hsv`),h(e)===`array`&&e.length===3)return`hsv`}}),P.hsv=(e,t,n)=>Ne(e,t,n,`hsv`);function $e(e,t){let n=e.length;Array.isArray(e[0])||(e=[e]),Array.isArray(t[0])||(t=t.map(e=>[e]));let r=t[0].length,i=t[0].map((e,n)=>t.map(e=>e[n])),a=e.map(e=>i.map(t=>Array.isArray(e)?e.reduce((e,n,r)=>e+n*(t[r]||0),0):t.reduce((t,n)=>t+n*e,0)));return n===1&&(a=a[0]),r===1?a.map(e=>e[0]):a}var et=(...e)=>{e=g(e,`lab`);let[t,n,r,...i]=e,[a,o,s]=tt([t,n,r]),[c,l,u]=de(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]};function tt(e){return $e([[1.2268798758459243,-.5578149944602171,.2813910456659647],[-.0405757452148008,1.112286803280317,-.0717110580655164],[-.0763729366746601,-.4214933324022432,1.5869240198367816]],$e([[1,.3963377773761749,.2158037573099136],[1,-.1055613458156586,-.0638541728258133],[1,-.0894841775298119,-1.2914855480194092]],e).map(e=>e**3))}var nt=(...e)=>{let[t,n,r,...i]=g(e,`rgb`);return[...rt(he(t,n,r)),...i.length>0&&i[0]<1?[i[0]]:[]]};function rt(e){return $e([[.210454268309314,.7936177747023054,-.0040720430116193],[1.9779985324311684,-2.42859224204858,.450593709617411],[.0259040424655478,.7827717124575296,-.8086757549230774]],$e([[.819022437996703,.3619062600528904,-.1288737815209879],[.0329836539323885,.9292868615863434,.0361446663506424],[.0481771893596242,.2642395317527308,.6335478284694309]],e).map(e=>Math.cbrt(e)))}O.prototype.oklab=function(){return nt(this._rgb)},Object.assign(k,{oklab:(...e)=>new O(...e,`oklab`)}),D.format.oklab=et,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`oklab`),h(e)===`array`&&e.length===3)return`oklab`}}),P.oklab=(e,t,n)=>{let r=e.oklab(),i=t.oklab();return new O(r[0]+n*(i[0]-r[0]),r[1]+n*(i[1]-r[1]),r[2]+n*(i[2]-r[2]),`oklab`)},P.oklch=(e,t,n)=>Ne(e,t,n,`oklch`);var{pow:it,sqrt:at,PI:ot,cos:st,sin:ct,atan2:lt}=Math,ut=(e,t=`lrgb`,n=null)=>{let r=e.length;n||=Array.from(Array(r)).map(()=>1);let i=r/n.reduce(function(e,t){return e+t});if(n.forEach((e,t)=>{n[t]*=i}),e=e.map(e=>new O(e)),t===`lrgb`)return dt(e,n);let a=e.shift(),o=a.get(t),s=[],c=0,l=0;for(let e=0;e{let i=e.get(t);u+=e.alpha()*n[r+1];for(let e=0;e=360;)t-=360;o[e]=t}else o[e]=o[e]/s[e];return u/=r,new O(o,t).alpha(u>.99999?1:u,!0)},dt=(e,t)=>{let n=e.length,r=[0,0,0,0];for(let i=0;i.9999999&&(r[3]=1),new O(p(r))},{pow:ft}=Math;function pt(e){let t=`rgb`,n=k(`#ccc`),r=0,i=[0,1],a=[0,1],o=[],s=[0,0],c=!1,l=[],u=!1,d=0,p=1,m=!1,g={},_=!0,v=1,y=function(e){if(e||=[`#fff`,`#000`],e&&h(e)===`string`&&k.brewer&&k.brewer[e.toLowerCase()]&&(e=k.brewer[e.toLowerCase()]),h(e)===`array`){e.length===1&&(e=[e[0],e[0]]),e=e.slice(0);for(let t=0;t=c[n];)n++;return n-1}return 0},x=e=>e,S=e=>e,C=function(e,r){let i,a;if(r??=!1,isNaN(e)||e===null)return n;a=r?e:c&&c.length>2?b(e)/(c.length-2):p===d?1:(e-d)/(p-d),a=S(a),r||(a=x(a)),v!==1&&(a=ft(a,v)),a=s[0]+a*(1-s[0]-s[1]),a=f(a,0,1);let u=Math.floor(a*1e4);if(_&&g[u])i=g[u];else{if(h(l)===`array`)for(let e=0;e=n&&e===o.length-1){i=l[e];break}if(a>n&&ag={};y(e);let T=function(e){let t=k(C(e));return u&&t[u]?t[u]():t};return T.classes=function(e){if(e!=null){if(h(e)===`array`)c=e,i=[e[0],e[e.length-1]];else{let t=k.analyze(i);c=e===0?[t.min,t.max]:k.limits(t,`e`,e)}return T}return c},T.domain=function(e){if(!arguments.length)return a;a=e.slice(0),d=e[0],p=e[e.length-1],o=[];let t=l.length;if(e.length===t&&d!==p)for(let t of Array.from(e))o.push((t-d)/(p-d));else{for(let e=0;e2){let t=e.map((t,n)=>n/(e.length-1)),n=e.map(e=>(e-d)/(p-d));n.every((e,n)=>t[n]===e)||(S=e=>{if(e<=0||e>=1)return e;let r=0;for(;e>=n[r+1];)r++;let i=(e-n[r])/(n[r+1]-n[r]);return t[r]+i*(t[r+1]-t[r])})}}return i=[d,p],T},T.mode=function(e){return arguments.length?(t=e,w(),T):t},T.range=function(e,t){return y(e,t),T},T.out=function(e){return u=e,T},T.spread=function(e){return arguments.length?(r=e,T):r},T.correctLightness=function(e){return e??=!0,m=e,w(),x=m?function(e){let t=C(0,!0).lab()[0],n=C(1,!0).lab()[0],r=t>n,i=C(e,!0).lab()[0],a=t+(n-t)*e,o=i-a,s=0,c=1,l=20;for(;Math.abs(o)>.01&&l-- >0;)(function(){return r&&(o*=-1),o<0?(s=e,e+=(c-e)*.5):(c=e,e+=(s-e)*.5),i=C(e,!0).lab()[0],o=i-a})();return e}:e=>e,T},T.padding=function(e){return e==null?s:(h(e)===`number`&&(e=[e,e]),s=e,T)},T.colors=function(t,n){arguments.length<2&&(n=`hex`);let r=[];if(arguments.length===0)r=l.slice(0);else if(t===1)r=[T(.5)];else if(t>1){let e=i[0],n=i[1]-e;r=mt(0,t,!1).map(r=>T(e+r/(t-1)*n))}else{e=[];let t=[];if(c&&c.length>2)for(let e=1,n=c.length,r=1<=n;r?en;r?e++:e--)t.push((c[e-1]+c[e])*.5);else t=i;r=t.map(e=>T(e))}return k[n]&&(r=r.map(e=>e[n]())),r},T.cache=function(e){return e==null?_:(_=e,T)},T.gamma=function(e){return e==null?v:(v=e,T)},T.nodata=function(e){return e==null?n:(n=k(e),T)},T}function mt(e,t,n){let r=[],i=ea;i?t++:t--)r.push(t);return r}var ht=function(e){let t=[1,1];for(let n=1;nnew O(e)),e.length===2)[n,r]=e.map(e=>e.lab()),t=function(e){return new O([0,1,2].map(t=>n[t]+e*(r[t]-n[t])),`lab`)};else if(e.length===3)[n,r,i]=e.map(e=>e.lab()),t=function(e){return new O([0,1,2].map(t=>(1-e)*(1-e)*n[t]+2*(1-e)*e*r[t]+e*e*i[t]),`lab`)};else if(e.length===4){let a;[n,r,i,a]=e.map(e=>e.lab()),t=function(e){return new O([0,1,2].map(t=>(1-e)*(1-e)*(1-e)*n[t]+3*(1-e)*(1-e)*e*r[t]+3*(1-e)*e*e*i[t]+e*e*e*a[t]),`lab`)}}else if(e.length>=5){let n,r,i;n=e.map(e=>e.lab()),i=e.length-1,r=ht(i),t=function(e){let t=1-e;return new O([0,1,2].map(a=>n.reduce((n,o,s)=>n+r[s]*t**(i-s)*e**s*o[a],0)),`lab`)}}else throw RangeError(`No point in running bezier with only one color.`);return t},_t=e=>{let t=gt(e);return t.scale=()=>pt(t),t},{round:vt}=Math;O.prototype.rgb=function(e=!0){return e===!1?this._rgb.slice(0,3):this._rgb.slice(0,3).map(vt)},O.prototype.rgba=function(e=!0){return this._rgb.slice(0,4).map((t,n)=>n<3?e===!1?t:vt(t):t)},Object.assign(k,{rgb:(...e)=>new O(...e,`rgb`)}),D.format.rgb=(...e)=>{let t=g(e,`rgba`);return t[3]===void 0&&(t[3]=1),t},D.autodetect.push({p:3,test:(...e)=>{if(e=g(e,`rgba`),h(e)===`array`&&(e.length===3||e.length===4&&h(e[3])==`number`&&e[3]>=0&&e[3]<=1))return`rgb`}});var I=(e,t,n)=>{if(!I[n])throw Error(`unknown blend mode `+n);return I[n](e,t)},L=e=>(t,n)=>{let r=k(n).rgb(),i=k(t).rgb();return k.rgb(e(r,i))},R=e=>(t,n)=>{let r=[];return r[0]=e(t[0],n[0]),r[1]=e(t[1],n[1]),r[2]=e(t[2],n[2]),r};I.normal=L(R(e=>e)),I.multiply=L(R((e,t)=>e*t/255)),I.screen=L(R((e,t)=>255*(1-(1-e/255)*(1-t/255)))),I.overlay=L(R((e,t)=>t<128?2*e*t/255:255*(1-2*(1-e/255)*(1-t/255)))),I.darken=L(R((e,t)=>e>t?t:e)),I.lighten=L(R((e,t)=>e>t?e:t)),I.dodge=L(R((e,t)=>e===255?255:(e=t/255*255/(1-e/255),e>255?255:e))),I.burn=L(R((e,t)=>255*(1-(1-t/255)/(e/255))));var{pow:yt,sin:bt,cos:xt}=Math;function St(e=300,t=-1.5,n=1,r=1,i=[0,1]){let a=0,o;h(i)===`array`?o=i[1]-i[0]:(o=0,i=[i,i]);let s=function(s){let c=C*((e+120)/360+t*s),l=yt(i[0]+o*s,r),u=(a===0?n:n[0]+s*a)*l*(1-l)/2,d=xt(c),f=bt(c),m=l+u*(-.14861*d+1.78277*f),h=l+u*(-.29227*d-.90649*f),g=l+1.97294*d*u;return k(p([m*255,h*255,g*255,1]))};return s.start=function(t){return t==null?e:(e=t,s)},s.rotations=function(e){return e==null?t:(t=e,s)},s.gamma=function(e){return e==null?r:(r=e,s)},s.hue=function(e){return e==null?n:(n=e,h(n)===`array`?(a=n[1]-n[0],a===0&&(n=n[1])):a=0,s)},s.lightness=function(e){return e==null?i:(h(e)===`array`?(i=e,o=e[1]-e[0]):(i=[e,e],o=0),s)},s.scale=()=>k.scale(s),s.hue(n),s}var Ct=`0123456789abcdef`,{floor:wt,random:Tt}=Math,Et=(e=Tt)=>{let t=`#`;for(let n=0;n<6;n++)t+=Ct.charAt(wt(e()*16));return new O(t,`hex`)},{log:Dt,pow:Ot,floor:kt,abs:At}=Math;function jt(e,t=null){let n={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};return h(e)===`object`&&(e=Object.values(e)),e.forEach(e=>{t&&h(e)===`object`&&(e=e[t]),e!=null&&!isNaN(e)&&(n.values.push(e),n.sum+=e,en.max&&(n.max=e),n.count+=1)}),n.domain=[n.min,n.max],n.limits=(e,t)=>Mt(n,e,t),n}function Mt(e,t=`equal`,n=7){h(e)==`array`&&(e=jt(e));let{min:r,max:i}=e,a=e.values.sort((e,t)=>e-t);if(n===1)return[r,i];let o=[];if(t.substr(0,1)===`c`&&(o.push(r),o.push(i)),t.substr(0,1)===`e`){o.push(r);for(let e=1;e 0`);let e=Math.LOG10E*Dt(r),t=Math.LOG10E*Dt(i);o.push(r);for(let r=1;r200&&(l=!1)}let f={};for(let e=0;ee-t),o.push(p[0]);for(let e=1;e{e=new O(e),t=new O(t);let n=e.luminance(),r=t.luminance();return n>r?(n+.05)/(r+.05):(r+.05)/(n+.05)},Pt=.027,Ft=5e-4,It=.1,Lt=1.14,Rt=.022,zt=1.414,Bt=(e,t)=>{e=new O(e),t=new O(t),e.alpha()<1&&(e=F(t,e,e.alpha(),`rgb`));let n=Vt(...e.rgb()),r=Vt(...t.rgb()),i=n>=Rt?n:n+(Rt-n)**+zt,a=r>=Rt?r:r+(Rt-r)**+zt,o=a**.56-i**.57,s=a**.65-i**.62,c=Math.abs(a-i)0?c-Pt:c+Pt)*100};function Vt(e,t,n){return .2126729*(e/255)**2.4+.7151522*(t/255)**2.4+.072175*(n/255)**2.4}var{sqrt:z,pow:B,min:Ht,max:Ut,atan2:Wt,abs:Gt,cos:Kt,sin:qt,exp:Jt,PI:Yt}=Math;function Xt(e,t,n=1,r=1,i=1){var a=function(e){return 360*e/(2*Yt)},o=function(e){return 2*Yt*e/360};e=new O(e),t=new O(t);let[s,c,l]=Array.from(e.lab()),[u,d,f]=Array.from(t.lab()),p=(s+u)/2,m=(z(B(c,2)+B(l,2))+z(B(d,2)+B(f,2)))/2,h=.5*(1-z(B(m,7)/(B(m,7)+B(25,7)))),g=c*(1+h),_=d*(1+h),v=z(B(g,2)+B(l,2)),y=z(B(_,2)+B(f,2)),b=(v+y)/2,x=a(Wt(l,g)),S=a(Wt(f,_)),C=x>=0?x:x+360,w=S>=0?S:S+360,T=Gt(C-w)>180?(C+w+360)/2:(C+w)/2,ee=1-.17*Kt(o(T-30))+.24*Kt(o(2*T))+.32*Kt(o(3*T+6))-.2*Kt(o(4*T-63)),E=w-C;E=Gt(E)<=180?E:w<=C?E+360:E-360,E=2*z(v*y)*qt(o(E)/2);let D=u-s,te=y-v,k=1+.015*B(p-50,2)/z(20+B(p-50,2)),A=1+.045*b,ne=1+.015*b*ee,re=30*Jt(-B((T-275)/25,2)),ie=-(2*z(B(b,7)/(B(b,7)+B(25,7))))*qt(2*o(re));return Ut(0,Ht(100,z(B(D/(n*k),2)+B(te/(r*A),2)+B(E/(i*ne),2)+ie*(te/(r*A))*(E/(i*ne)))))}function Zt(e,t,n=`lab`){e=new O(e),t=new O(t);let r=e.get(n),i=t.get(n),a=0;for(let e in r){let t=(r[e]||0)-(i[e]||0);a+=t*t}return Math.sqrt(a)}var Qt=(...e)=>{try{return new O(...e),!0}catch{return!1}},$t={cool(){return pt([k.hsl(180,1,.9),k.hsl(250,.7,.4)])},hot(){return pt([`#000`,`#f00`,`#ff0`,`#fff`],[0,.25,.75,1]).mode(`rgb`)}},en={OrRd:[`#fff7ec`,`#fee8c8`,`#fdd49e`,`#fdbb84`,`#fc8d59`,`#ef6548`,`#d7301f`,`#b30000`,`#7f0000`],PuBu:[`#fff7fb`,`#ece7f2`,`#d0d1e6`,`#a6bddb`,`#74a9cf`,`#3690c0`,`#0570b0`,`#045a8d`,`#023858`],BuPu:[`#f7fcfd`,`#e0ecf4`,`#bfd3e6`,`#9ebcda`,`#8c96c6`,`#8c6bb1`,`#88419d`,`#810f7c`,`#4d004b`],Oranges:[`#fff5eb`,`#fee6ce`,`#fdd0a2`,`#fdae6b`,`#fd8d3c`,`#f16913`,`#d94801`,`#a63603`,`#7f2704`],BuGn:[`#f7fcfd`,`#e5f5f9`,`#ccece6`,`#99d8c9`,`#66c2a4`,`#41ae76`,`#238b45`,`#006d2c`,`#00441b`],YlOrBr:[`#ffffe5`,`#fff7bc`,`#fee391`,`#fec44f`,`#fe9929`,`#ec7014`,`#cc4c02`,`#993404`,`#662506`],YlGn:[`#ffffe5`,`#f7fcb9`,`#d9f0a3`,`#addd8e`,`#78c679`,`#41ab5d`,`#238443`,`#006837`,`#004529`],Reds:[`#fff5f0`,`#fee0d2`,`#fcbba1`,`#fc9272`,`#fb6a4a`,`#ef3b2c`,`#cb181d`,`#a50f15`,`#67000d`],RdPu:[`#fff7f3`,`#fde0dd`,`#fcc5c0`,`#fa9fb5`,`#f768a1`,`#dd3497`,`#ae017e`,`#7a0177`,`#49006a`],Greens:[`#f7fcf5`,`#e5f5e0`,`#c7e9c0`,`#a1d99b`,`#74c476`,`#41ab5d`,`#238b45`,`#006d2c`,`#00441b`],YlGnBu:[`#ffffd9`,`#edf8b1`,`#c7e9b4`,`#7fcdbb`,`#41b6c4`,`#1d91c0`,`#225ea8`,`#253494`,`#081d58`],Purples:[`#fcfbfd`,`#efedf5`,`#dadaeb`,`#bcbddc`,`#9e9ac8`,`#807dba`,`#6a51a3`,`#54278f`,`#3f007d`],GnBu:[`#f7fcf0`,`#e0f3db`,`#ccebc5`,`#a8ddb5`,`#7bccc4`,`#4eb3d3`,`#2b8cbe`,`#0868ac`,`#084081`],Greys:[`#ffffff`,`#f0f0f0`,`#d9d9d9`,`#bdbdbd`,`#969696`,`#737373`,`#525252`,`#252525`,`#000000`],YlOrRd:[`#ffffcc`,`#ffeda0`,`#fed976`,`#feb24c`,`#fd8d3c`,`#fc4e2a`,`#e31a1c`,`#bd0026`,`#800026`],PuRd:[`#f7f4f9`,`#e7e1ef`,`#d4b9da`,`#c994c7`,`#df65b0`,`#e7298a`,`#ce1256`,`#980043`,`#67001f`],Blues:[`#f7fbff`,`#deebf7`,`#c6dbef`,`#9ecae1`,`#6baed6`,`#4292c6`,`#2171b5`,`#08519c`,`#08306b`],PuBuGn:[`#fff7fb`,`#ece2f0`,`#d0d1e6`,`#a6bddb`,`#67a9cf`,`#3690c0`,`#02818a`,`#016c59`,`#014636`],Viridis:[`#440154`,`#482777`,`#3f4a8a`,`#31678e`,`#26838f`,`#1f9d8a`,`#6cce5a`,`#b6de2b`,`#fee825`],Spectral:[`#9e0142`,`#d53e4f`,`#f46d43`,`#fdae61`,`#fee08b`,`#ffffbf`,`#e6f598`,`#abdda4`,`#66c2a5`,`#3288bd`,`#5e4fa2`],RdYlGn:[`#a50026`,`#d73027`,`#f46d43`,`#fdae61`,`#fee08b`,`#ffffbf`,`#d9ef8b`,`#a6d96a`,`#66bd63`,`#1a9850`,`#006837`],RdBu:[`#67001f`,`#b2182b`,`#d6604d`,`#f4a582`,`#fddbc7`,`#f7f7f7`,`#d1e5f0`,`#92c5de`,`#4393c3`,`#2166ac`,`#053061`],PiYG:[`#8e0152`,`#c51b7d`,`#de77ae`,`#f1b6da`,`#fde0ef`,`#f7f7f7`,`#e6f5d0`,`#b8e186`,`#7fbc41`,`#4d9221`,`#276419`],PRGn:[`#40004b`,`#762a83`,`#9970ab`,`#c2a5cf`,`#e7d4e8`,`#f7f7f7`,`#d9f0d3`,`#a6dba0`,`#5aae61`,`#1b7837`,`#00441b`],RdYlBu:[`#a50026`,`#d73027`,`#f46d43`,`#fdae61`,`#fee090`,`#ffffbf`,`#e0f3f8`,`#abd9e9`,`#74add1`,`#4575b4`,`#313695`],BrBG:[`#543005`,`#8c510a`,`#bf812d`,`#dfc27d`,`#f6e8c3`,`#f5f5f5`,`#c7eae5`,`#80cdc1`,`#35978f`,`#01665e`,`#003c30`],RdGy:[`#67001f`,`#b2182b`,`#d6604d`,`#f4a582`,`#fddbc7`,`#ffffff`,`#e0e0e0`,`#bababa`,`#878787`,`#4d4d4d`,`#1a1a1a`],PuOr:[`#7f3b08`,`#b35806`,`#e08214`,`#fdb863`,`#fee0b6`,`#f7f7f7`,`#d8daeb`,`#b2abd2`,`#8073ac`,`#542788`,`#2d004b`],Set2:[`#66c2a5`,`#fc8d62`,`#8da0cb`,`#e78ac3`,`#a6d854`,`#ffd92f`,`#e5c494`,`#b3b3b3`],Accent:[`#7fc97f`,`#beaed4`,`#fdc086`,`#ffff99`,`#386cb0`,`#f0027f`,`#bf5b17`,`#666666`],Set1:[`#e41a1c`,`#377eb8`,`#4daf4a`,`#984ea3`,`#ff7f00`,`#ffff33`,`#a65628`,`#f781bf`,`#999999`],Set3:[`#8dd3c7`,`#ffffb3`,`#bebada`,`#fb8072`,`#80b1d3`,`#fdb462`,`#b3de69`,`#fccde5`,`#d9d9d9`,`#bc80bd`,`#ccebc5`,`#ffed6f`],Dark2:[`#1b9e77`,`#d95f02`,`#7570b3`,`#e7298a`,`#66a61e`,`#e6ab02`,`#a6761d`,`#666666`],Paired:[`#a6cee3`,`#1f78b4`,`#b2df8a`,`#33a02c`,`#fb9a99`,`#e31a1c`,`#fdbf6f`,`#ff7f00`,`#cab2d6`,`#6a3d9a`,`#ffff99`,`#b15928`],Pastel2:[`#b3e2cd`,`#fdcdac`,`#cbd5e8`,`#f4cae4`,`#e6f5c9`,`#fff2ae`,`#f1e2cc`,`#cccccc`],Pastel1:[`#fbb4ae`,`#b3cde3`,`#ccebc5`,`#decbe4`,`#fed9a6`,`#ffffcc`,`#e5d8bd`,`#fddaec`,`#f2f2f2`]},tn=Object.keys(en),nn=new Map(tn.map(e=>[e.toLowerCase(),e])),rn=typeof Proxy==`function`?new Proxy(en,{get(e,t){let n=t.toLowerCase();if(nn.has(n))return e[nn.get(n)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(tn)}}):en,an=(...e)=>{e=g(e,`cmyk`);let[t,n,r,i]=e,a=e.length>4?e[4]:1;return i===1?[0,0,0,a]:[t>=1?0:255*(1-t)*(1-i),n>=1?0:255*(1-n)*(1-i),r>=1?0:255*(1-r)*(1-i),a]},{max:on}=Math,sn=(...e)=>{let[t,n,r]=g(e,`rgb`);t/=255,n/=255,r/=255;let i=1-on(t,on(n,r)),a=i<1?1/(1-i):0;return[(1-t-i)*a,(1-n-i)*a,(1-r-i)*a,i]};O.prototype.cmyk=function(){return sn(this._rgb)},Object.assign(k,{cmyk:(...e)=>new O(...e,`cmyk`)}),D.format.cmyk=an,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`cmyk`),h(e)===`array`&&e.length===4)return`cmyk`}});var cn=(...e)=>{let t=g(e,`hsla`),n=_(e)||`lsa`;return t[0]=x(t[0]||0)+`deg`,t[1]=x(t[1]*100)+`%`,t[2]=x(t[2]*100)+`%`,n===`hsla`||t.length>3&&t[3]<1?(t[3]=`/ `+(t.length>3?t[3]:1),n=`hsla`):t.length=3,`${n.substr(0,3)}(${t.join(` `)})`},ln=(...e)=>{let t=g(e,`lab`),n=_(e)||`lab`;return t[0]=x(t[0])+`%`,t[1]=x(t[1]),t[2]=x(t[2]),n===`laba`||t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`lab(${t.join(` `)})`},un=(...e)=>{let t=g(e,`lch`),n=_(e)||`lab`;return t[0]=x(t[0])+`%`,t[1]=x(t[1]),t[2]=isNaN(t[2])?`none`:x(t[2])+`deg`,n===`lcha`||t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`lch(${t.join(` `)})`},dn=(...e)=>{let t=g(e,`lab`);return t[0]=x(t[0]*100)+`%`,t[1]=S(t[1]),t[2]=S(t[2]),t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`oklab(${t.join(` `)})`},fn=(...e)=>{let[t,n,r,...i]=g(e,`rgb`),[a,o,s]=nt(t,n,r),[c,l,u]=ke(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]},pn=(...e)=>{let t=g(e,`lch`);return t[0]=x(t[0]*100)+`%`,t[1]=S(t[1]),t[2]=isNaN(t[2])?`none`:x(t[2])+`deg`,t.length>3&&t[3]<1?t[3]=`/ `+(t.length>3?t[3]:1):t.length=3,`oklch(${t.join(` `)})`},{round:mn}=Math,hn=(...e)=>{let t=g(e,`rgba`),n=_(e)||`rgb`;if(n.substr(0,3)===`hsl`)return cn(qe(t),n);if(n.substr(0,3)===`lab`){let e=ce();M(`d50`);let r=ln(fe(t),n);return M(e),r}if(n.substr(0,3)===`lch`){let e=ce();M(`d50`);let r=un(Ae(t),n);return M(e),r}return n.substr(0,5)===`oklab`?dn(nt(t)):n.substr(0,5)===`oklch`?pn(fn(t)):(t[0]=mn(t[0]),t[1]=mn(t[1]),t[2]=mn(t[2]),(n===`rgba`||t.length>3&&t[3]<1)&&(t[3]=`/ `+(t.length>3?t[3]:1),n=`rgba`),`${n.substr(0,3)}(${t.slice(0,n===`rgb`?3:4).join(` `)})`)},gn=(...e)=>{e=g(e,`lch`);let[t,n,r,...i]=e,[a,o,s]=Ce(t,n,r),[c,l,u]=et(a,o,s);return[c,l,u,...i.length>0&&i[0]<1?[i[0]]:[]]},V=`((?:-?\\d+)|(?:-?\\d+(?:\\.\\d+)?)%|none)`,H=`((?:-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)%?)|none)`,_n=`((?:-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)%)|none)`,U=`\\s*`,vn=`\\s+`,yn=`\\s*,\\s*`,bn=`((?:-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:deg)?)|none)`,xn=`\\s*(?:\\/\\s*((?:[01]|[01]?\\.\\d+)|\\d+(?:\\.\\d+)?%))?`,Sn=RegExp(`^rgba?\\(`+U+[V,V,V].join(vn)+xn+`\\)$`),Cn=RegExp(`^rgb\\(`+U+[V,V,V].join(yn)+U+`\\)$`),wn=RegExp(`^rgba\\(`+U+[V,V,V,H].join(yn)+U+`\\)$`),Tn=RegExp(`^hsla?\\(`+U+[bn,_n,_n].join(vn)+xn+`\\)$`),En=RegExp(`^hsl?\\(`+U+[bn,_n,_n].join(yn)+U+`\\)$`),Dn=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,On=RegExp(`^lab\\(`+U+[H,H,H].join(vn)+xn+`\\)$`),kn=RegExp(`^lch\\(`+U+[H,H,bn].join(vn)+xn+`\\)$`),An=RegExp(`^oklab\\(`+U+[H,H,H].join(vn)+xn+`\\)$`),jn=RegExp(`^oklch\\(`+U+[H,H,bn].join(vn)+xn+`\\)$`),{round:Mn}=Math,Nn=e=>e.map((e,t)=>t<=2?f(Mn(e),0,255):e),W=(e,t=0,n=100,r=!1)=>(typeof e==`string`&&e.endsWith(`%`)&&(e=parseFloat(e.substring(0,e.length-1))/100,e=r?t+(e+1)*.5*(n-t):t+e*(n-t)),+e),G=(e,t)=>e===`none`?t:e,Pn=e=>{if(e=e.toLowerCase().trim(),e===`transparent`)return[0,0,0,0];let t;if(D.format.named)try{return D.format.named(e)}catch{}if((t=e.match(Sn))||(t=e.match(Cn))){let e=t.slice(1,4);for(let t=0;t<3;t++)e[t]=+W(G(e[t],0),0,255);e=Nn(e);let n=t[4]===void 0?1:+W(t[4],0,1);return e[3]=n,e}if(t=e.match(wn)){let e=t.slice(1,5);for(let t=0;t<4;t++)e[t]=+W(e[t],0,255);return e}if((t=e.match(Tn))||(t=e.match(En))){let e=t.slice(1,4);e[0]=+G(e[0].replace(`deg`,``),0),e[1]=W(G(e[1],0),0,100)*.01,e[2]=W(G(e[2],0),0,100)*.01;let n=Nn(Ke(e));return n[3]=t[4]===void 0?1:+W(t[4],0,1),n}if(t=e.match(Dn)){let e=t.slice(1,4);e[1]*=.01,e[2]*=.01;let n=Ke(e);for(let e=0;e<3;e++)n[e]=Mn(n[e]);return n[3]=+t[4],n}if(t=e.match(On)){let e=t.slice(1,4);e[0]=W(G(e[0],0),0,100),e[1]=W(G(e[1],0),-125,125,!0),e[2]=W(G(e[2],0),-125,125,!0);let n=ce();M(`d50`);let r=Nn(N(e));return M(n),r[3]=t[4]===void 0?1:+W(t[4],0,1),r}if(t=e.match(kn)){let e=t.slice(1,4);e[0]=W(e[0],0,100),e[1]=W(G(e[1],0),0,150,!1),e[2]=+G(e[2].replace(`deg`,``),0);let n=ce();M(`d50`);let r=Nn(we(e));return M(n),r[3]=t[4]===void 0?1:+W(t[4],0,1),r}if(t=e.match(An)){let e=t.slice(1,4);e[0]=W(G(e[0],0),0,1),e[1]=W(G(e[1],0),-.4,.4,!0),e[2]=W(G(e[2],0),-.4,.4,!0);let n=Nn(et(e));return n[3]=t[4]===void 0?1:+W(t[4],0,1),n}if(t=e.match(jn)){let e=t.slice(1,4);e[0]=W(G(e[0],0),0,1),e[1]=W(G(e[1],0),0,.4,!1),e[2]=+G(e[2].replace(`deg`,``),0);let n=Nn(gn(e));return n[3]=t[4]===void 0?1:+W(t[4],0,1),n}};Pn.test=e=>Sn.test(e)||Tn.test(e)||On.test(e)||kn.test(e)||An.test(e)||jn.test(e)||Cn.test(e)||wn.test(e)||En.test(e)||Dn.test(e)||e===`transparent`,O.prototype.css=function(e){return hn(this._rgb,e)},k.css=(...e)=>new O(...e,`css`),D.format.css=Pn,D.autodetect.push({p:5,test:(e,...t)=>{if(!t.length&&h(e)===`string`&&Pn.test(e))return`css`}}),D.format.gl=(...e)=>{let t=g(e,`rgba`);return t[0]*=255,t[1]*=255,t[2]*=255,t},k.gl=(...e)=>new O(...e,`gl`),O.prototype.gl=function(){let e=this._rgb;return[e[0]/255,e[1]/255,e[2]/255,e[3]]},O.prototype.hex=function(e){return oe(this._rgb,e)},k.hex=(...e)=>new O(...e,`hex`),D.format.hex=ie,D.autodetect.push({p:4,test:(e,...t)=>{if(!t.length&&h(e)===`string`&&[3,4,5,6,7,8,9].indexOf(e.length)>=0)return`hex`}});var{log:Fn}=Math,In=e=>{let t=e/100,n,r,i;return t<66?(n=255,r=t<6?0:-155.25485562709179-.44596950469579133*(r=t-2)+104.49216199393888*Fn(r),i=t<20?0:-254.76935184120902+.8274096064007395*(i=t-10)+115.67994401066147*Fn(i)):(n=351.97690566805693+.114206453784165*(n=t-55)-40.25366309332127*Fn(n),r=325.4494125711974+.07943456536662342*(r=t-50)-28.0852963507957*Fn(r),i=255),[n,r,i,1]},{round:Ln}=Math,Rn=(...e)=>{let t=g(e,`rgb`),n=t[0],r=t[2],i=1e3,a=4e4,o;for(;a-i>.4;){o=(a+i)*.5;let e=In(o);e[2]/e[0]>=r/n?a=o:i=o}return Ln(o)};O.prototype.temp=O.prototype.kelvin=O.prototype.temperature=function(){return Rn(this._rgb)};var zn=(...e)=>new O(...e,`temp`);Object.assign(k,{temp:zn,kelvin:zn,temperature:zn}),D.format.temp=D.format.kelvin=D.format.temperature=In,O.prototype.oklch=function(){return fn(this._rgb)},Object.assign(k,{oklch:(...e)=>new O(...e,`oklch`)}),D.format.oklch=gn,D.autodetect.push({p:2,test:(...e)=>{if(e=g(e,`oklch`),h(e)===`array`&&e.length===3)return`oklch`}}),Object.assign(k,{analyze:jt,average:ut,bezier:_t,blend:I,brewer:rn,Color:O,colors:A,contrast:Nt,contrastAPCA:Bt,cubehelix:St,deltaE:Xt,distance:Zt,input:D,interpolate:F,limits:Mt,mix:F,random:Et,scale:pt,scales:$t,valid:Qt});var K=k,q=class e{constructor(){this.hex=`#000000`,this.rgb_r=0,this.rgb_g=0,this.rgb_b=0,this.xyz_x=0,this.xyz_y=0,this.xyz_z=0,this.luv_l=0,this.luv_u=0,this.luv_v=0,this.lch_l=0,this.lch_c=0,this.lch_h=0,this.hsluv_h=0,this.hsluv_s=0,this.hsluv_l=0,this.hpluv_h=0,this.hpluv_p=0,this.hpluv_l=0,this.r0s=0,this.r0i=0,this.r1s=0,this.r1i=0,this.g0s=0,this.g0i=0,this.g1s=0,this.g1i=0,this.b0s=0,this.b0i=0,this.b1s=0,this.b1i=0}static fromLinear(e){return e<=.0031308?12.92*e:1.055*e**(1/2.4)-.055}static toLinear(e){return e>.04045?((e+.055)/1.055)**2.4:e/12.92}static yToL(t){return t<=e.epsilon?t/e.refY*e.kappa:116*(t/e.refY)**(1/3)-16}static lToY(t){return t<=8?e.refY*t/e.kappa:e.refY*((t+16)/116)**3}static rgbChannelToHex(t){let n=Math.round(t*255),r=n%16,i=(n-r)/16|0;return e.hexChars.charAt(i)+e.hexChars.charAt(r)}static hexToRgbChannel(t,n){let r=e.hexChars.indexOf(t.charAt(n)),i=e.hexChars.indexOf(t.charAt(n+1));return(r*16+i)/255}static distanceFromOriginAngle(e,t,n){let r=t/(Math.sin(n)-e*Math.cos(n));return r<0?1/0:r}static distanceFromOrigin(e,t){return Math.abs(t)/Math.sqrt(e**2+1)}static min6(e,t,n,r,i,a){return Math.min(e,Math.min(t,Math.min(n,Math.min(r,Math.min(i,a)))))}rgbToHex(){this.hex=`#`,this.hex+=e.rgbChannelToHex(this.rgb_r),this.hex+=e.rgbChannelToHex(this.rgb_g),this.hex+=e.rgbChannelToHex(this.rgb_b)}hexToRgb(){this.hex=this.hex.toLowerCase(),this.rgb_r=e.hexToRgbChannel(this.hex,1),this.rgb_g=e.hexToRgbChannel(this.hex,3),this.rgb_b=e.hexToRgbChannel(this.hex,5)}xyzToRgb(){this.rgb_r=e.fromLinear(e.m_r0*this.xyz_x+e.m_r1*this.xyz_y+e.m_r2*this.xyz_z),this.rgb_g=e.fromLinear(e.m_g0*this.xyz_x+e.m_g1*this.xyz_y+e.m_g2*this.xyz_z),this.rgb_b=e.fromLinear(e.m_b0*this.xyz_x+e.m_b1*this.xyz_y+e.m_b2*this.xyz_z)}rgbToXyz(){let t=e.toLinear(this.rgb_r),n=e.toLinear(this.rgb_g),r=e.toLinear(this.rgb_b);this.xyz_x=.41239079926595*t+.35758433938387*n+.18048078840183*r,this.xyz_y=.21263900587151*t+.71516867876775*n+.072192315360733*r,this.xyz_z=.019330818715591*t+.11919477979462*n+.95053215224966*r}xyzToLuv(){let t=this.xyz_x+15*this.xyz_y+3*this.xyz_z,n=4*this.xyz_x,r=9*this.xyz_y;t===0?(n=NaN,r=NaN):(n/=t,r/=t),this.luv_l=e.yToL(this.xyz_y),this.luv_l===0?(this.luv_u=0,this.luv_v=0):(this.luv_u=13*this.luv_l*(n-e.refU),this.luv_v=13*this.luv_l*(r-e.refV))}luvToXyz(){if(this.luv_l===0){this.xyz_x=0,this.xyz_y=0,this.xyz_z=0;return}let t=this.luv_u/(13*this.luv_l)+e.refU,n=this.luv_v/(13*this.luv_l)+e.refV;this.xyz_y=e.lToY(this.luv_l),this.xyz_x=0-9*this.xyz_y*t/((t-4)*n-t*n),this.xyz_z=(9*this.xyz_y-15*n*this.xyz_y-n*this.xyz_x)/(3*n)}luvToLch(){if(this.lch_l=this.luv_l,this.lch_c=Math.sqrt(this.luv_u*this.luv_u+this.luv_v*this.luv_v),this.lch_c<1e-8)this.lch_h=0;else{let e=Math.atan2(this.luv_v,this.luv_u);this.lch_h=e*180/Math.PI,this.lch_h<0&&(this.lch_h=360+this.lch_h)}}lchToLuv(){let e=this.lch_h/180*Math.PI;this.luv_l=this.lch_l,this.luv_u=Math.cos(e)*this.lch_c,this.luv_v=Math.sin(e)*this.lch_c}calculateBoundingLines(t){let n=(t+16)**3/1560896,r=n>e.epsilon?n:t/e.kappa,i=r*(284517*e.m_r0-94839*e.m_r2),a=r*(838422*e.m_r2+769860*e.m_r1+731718*e.m_r0),o=r*(632260*e.m_r2-126452*e.m_r1),s=r*(284517*e.m_g0-94839*e.m_g2),c=r*(838422*e.m_g2+769860*e.m_g1+731718*e.m_g0),l=r*(632260*e.m_g2-126452*e.m_g1),u=r*(284517*e.m_b0-94839*e.m_b2),d=r*(838422*e.m_b2+769860*e.m_b1+731718*e.m_b0),f=r*(632260*e.m_b2-126452*e.m_b1);this.r0s=i/o,this.r0i=a*t/o,this.r1s=i/(o+126452),this.r1i=(a-769860)*t/(o+126452),this.g0s=s/l,this.g0i=c*t/l,this.g1s=s/(l+126452),this.g1i=(c-769860)*t/(l+126452),this.b0s=u/f,this.b0i=d*t/f,this.b1s=u/(f+126452),this.b1i=(d-769860)*t/(f+126452)}calcMaxChromaHpluv(){let t=e.distanceFromOrigin(this.r0s,this.r0i),n=e.distanceFromOrigin(this.r1s,this.r1i),r=e.distanceFromOrigin(this.g0s,this.g0i),i=e.distanceFromOrigin(this.g1s,this.g1i),a=e.distanceFromOrigin(this.b0s,this.b0i),o=e.distanceFromOrigin(this.b1s,this.b1i);return e.min6(t,n,r,i,a,o)}calcMaxChromaHsluv(t){let n=t/360*Math.PI*2,r=e.distanceFromOriginAngle(this.r0s,this.r0i,n),i=e.distanceFromOriginAngle(this.r1s,this.r1i,n),a=e.distanceFromOriginAngle(this.g0s,this.g0i,n),o=e.distanceFromOriginAngle(this.g1s,this.g1i,n),s=e.distanceFromOriginAngle(this.b0s,this.b0i,n),c=e.distanceFromOriginAngle(this.b1s,this.b1i,n);return e.min6(r,i,a,o,s,c)}hsluvToLch(){if(this.hsluv_l>99.9999999)this.lch_l=100,this.lch_c=0;else if(this.hsluv_l<1e-8)this.lch_l=0,this.lch_c=0;else{this.lch_l=this.hsluv_l,this.calculateBoundingLines(this.hsluv_l);let e=this.calcMaxChromaHsluv(this.hsluv_h);this.lch_c=e/100*this.hsluv_s}this.lch_h=this.hsluv_h}lchToHsluv(){if(this.lch_l>99.9999999)this.hsluv_s=0,this.hsluv_l=100;else if(this.lch_l<1e-8)this.hsluv_s=0,this.hsluv_l=0;else{this.calculateBoundingLines(this.lch_l);let e=this.calcMaxChromaHsluv(this.lch_h);this.hsluv_s=this.lch_c/e*100,this.hsluv_l=this.lch_l}this.hsluv_h=this.lch_h}hpluvToLch(){if(this.hpluv_l>99.9999999)this.lch_l=100,this.lch_c=0;else if(this.hpluv_l<1e-8)this.lch_l=0,this.lch_c=0;else{this.lch_l=this.hpluv_l,this.calculateBoundingLines(this.hpluv_l);let e=this.calcMaxChromaHpluv();this.lch_c=e/100*this.hpluv_p}this.lch_h=this.hpluv_h}lchToHpluv(){if(this.lch_l>99.9999999)this.hpluv_p=0,this.hpluv_l=100;else if(this.lch_l<1e-8)this.hpluv_p=0,this.hpluv_l=0;else{this.calculateBoundingLines(this.lch_l);let e=this.calcMaxChromaHpluv();this.hpluv_p=this.lch_c/e*100,this.hpluv_l=this.lch_l}this.hpluv_h=this.lch_h}hsluvToRgb(){this.hsluvToLch(),this.lchToLuv(),this.luvToXyz(),this.xyzToRgb()}hpluvToRgb(){this.hpluvToLch(),this.lchToLuv(),this.luvToXyz(),this.xyzToRgb()}hsluvToHex(){this.hsluvToRgb(),this.rgbToHex()}hpluvToHex(){this.hpluvToRgb(),this.rgbToHex()}rgbToHsluv(){this.rgbToXyz(),this.xyzToLuv(),this.luvToLch(),this.lchToHpluv(),this.lchToHsluv()}rgbToHpluv(){this.rgbToXyz(),this.xyzToLuv(),this.luvToLch(),this.lchToHpluv(),this.lchToHpluv()}hexToHsluv(){this.hexToRgb(),this.rgbToHsluv()}hexToHpluv(){this.hexToRgb(),this.rgbToHpluv()}};q.hexChars=`0123456789abcdef`,q.refY=1,q.refU=.19783000664283,q.refV=.46831999493879,q.kappa=903.2962962,q.epsilon=.0088564516,q.m_r0=3.240969941904521,q.m_r1=-1.537383177570093,q.m_r2=-.498610760293,q.m_g0=-.96924363628087,q.m_g1=1.87596750150772,q.m_g2=.041555057407175,q.m_b0=.055630079696993,q.m_b1=-.20397695888897,q.m_b2=1.056971514242878;var Bn=s(((e,t)=>{function n(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.exports=n})),Vn=s(((e,t)=>{var n=Bn(),r,i;function a(){for(var e in i=[`toString`,`toLocaleString`,`valueOf`,`hasOwnProperty`,`isPrototypeOf`,`propertyIsEnumerable`,`constructor`],r=!0,{toString:null})r=!1}function o(e,t,o){var c,l=0;for(c in r??a(),e)if(s(t,e,c,o)===!1)break;if(r)for(var u=e.constructor,d=!!u&&e===u.prototype;(c=i[l++])&&!((c!==`constructor`||!d&&n(e,c))&&e[c]!==Object.prototype[c]&&s(t,e,c,o)===!1););}function s(e,t,n,r){return e.call(r,t[n],n,t)}t.exports=o})),Hn=s(((e,t)=>{var n=Vn();function r(e){var t=[];return n(e,function(e,n){typeof e==`function`&&t.push(n)}),t.sort()}t.exports=r})),Un=s(((e,t)=>{function n(e,t,n){var r=e.length;t=t==null?0:t<0?Math.max(r+t,0):Math.min(t,r),n=n==null?r:n<0?Math.max(r+n,0):Math.min(n,r);for(var i=[];t{var n=Un();function r(e,t,r){var i=n(arguments,2);return function(){return e.apply(t,i.concat(n(arguments)))}}t.exports=r})),Gn=s(((e,t)=>{function n(e,t,n){if(e!=null)for(var r=-1,i=e.length;++r{var n=Hn(),r=Wn(),i=Gn(),a=Un();function o(e,t){i(arguments.length>1?a(arguments,1):n(e),function(t){e[t]=r(e[t],e)})}t.exports=o})),J=s(((e,t)=>{var n=Bn(),r=Vn();function i(e,t,i){r(e,function(r,a){if(n(e,a))return t.call(i,e[a],a,e)})}t.exports=i})),qn=s(((e,t)=>{function n(e){return e}t.exports=n})),Jn=s(((e,t)=>{function n(e){return function(t){return t[e]}}t.exports=n})),Yn=s(((e,t)=>{var n=/^\[object (.*)\]$/,r=Object.prototype.toString,i;function a(e){return e===null?`Null`:e===i?`Undefined`:n.exec(r.call(e))[1]}t.exports=a})),Xn=s(((e,t)=>{var n=Yn();function r(e,t){return n(e)===t}t.exports=r})),Zn=s(((e,t)=>{var n=Xn();t.exports=Array.isArray||function(e){return n(e,`Array`)}})),Qn=s(((e,t)=>{var n=J(),r=Zn();function i(e,t){for(var n=-1,r=e.length;++n{var n=qn(),r=Jn(),i=Qn();function a(e,t){if(e==null)return n;switch(typeof e){case`function`:return t===void 0?e:function(n,r,i){return e.call(t,n,r,i)};case`object`:return function(t){return i(t,e)};case`string`:case`number`:return r(e)}}t.exports=a})),$n=s(((e,t)=>{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a=!1;return n(e,function(n,r){if(t(n,r,e))return a=!0,!1}),a}t.exports=i})),er=s(((e,t)=>{var n=$n();function r(e,t){return n(e,function(e){return e===t})}t.exports=r})),tr=s(((e,t)=>{function n(e){return!!e&&typeof e==`object`&&e.constructor===Object}t.exports=n})),nr=s(((e,t)=>{var n=J(),r=tr();function i(e,t){for(var a=0,o=arguments.length,s;++a{var n=J(),r=tr();function i(e,t){for(var r=0,i=arguments.length,o;++r{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a=!0;return n(e,function(n,r){if(!t(n,r,e))return a=!1,!1}),a}t.exports=i})),ar=s(((e,t)=>{var n=Xn();function r(e){return n(e,`Object`)}t.exports=r})),or=s(((e,t)=>{function n(e,t){return e===t?e!==0||1/e==1/t:e!==e&&t!==t}t.exports=n})),sr=s(((e,t)=>{var n=Bn(),r=ir(),i=ar(),a=or();function o(e){return function(t,r){return n(this,r)&&e(t,this[r])}}function s(e,t){return n(this,t)}function c(e,t,n){return n||=a,!i(e)||!i(t)?n(e,t):r(e,o(n),t)&&r(t,s,e)}t.exports=c})),cr=s(((e,t)=>{var n=Gn(),r=Un(),i=J();function a(e,t){return n(r(arguments,1),function(t){i(t,function(t,n){e[n]??(e[n]=t)})}),e}t.exports=a})),lr=s(((e,t)=>{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a={};return n(e,function(e,n,r){t(e,n,r)&&(a[n]=e)}),a}t.exports=i})),ur=s(((e,t)=>{var n=$n(),r=Y();function i(e,t,i){t=r(t,i);var a;return n(e,function(e,n,r){if(t(e,n,r))return a=e,!0}),a}t.exports=i})),dr=s(((e,t)=>{var n=J(),r=tr();function i(e,t,a,o){return n(e,function(e,n){var s=a?a+`.`+n:n;o!==0&&r(e)?i(e,t,s,o-1):t[s]=e}),t}function a(e,t){return e==null?{}:(t??=-1,i(e,{},``,t))}t.exports=a})),fr=s(((e,t)=>{function n(e){switch(typeof e){case`string`:case`number`:case`boolean`:return!0}return e==null}t.exports=n})),pr=s(((e,t)=>{fr();function n(e,t){for(var n=t.split(`.`),r=n.pop();t=n.shift();)if(e=e[t],e==null)return;return e[r]}t.exports=n})),mr=s(((e,t)=>{var n=pr(),r;function i(e,t){return n(e,t)!==r}t.exports=i})),hr=s(((e,t)=>{var n=J();t.exports=Object.keys||function(e){var t=[];return n(e,function(e,n){t.push(n)}),t}})),gr=s(((e,t)=>{var n=J(),r=Y();function i(e,t,i){t=r(t,i);var a={};return n(e,function(e,n,r){a[n]=t(e,n,r)}),a}t.exports=i})),_r=s(((e,t)=>{var n=J();function r(e,t){var r=!0;return n(t,function(t,n){if(e[n]!==t)return r=!1}),r}t.exports=r})),vr=s(((e,t)=>{var n=Y();function r(e,t,r){if(e==null||!e.length)return 1/0;if(e.length&&!t)return Math.max.apply(Math,e);t=n(t,r);for(var i,a=-1/0,o,s,c=-1,l=e.length;++ca&&(a=s,i=o);return i}t.exports=r})),yr=s(((e,t)=>{var n=J();function r(e){var t=[];return n(e,function(e,n){t.push(e)}),t}t.exports=r})),br=s(((e,t)=>{var n=vr(),r=yr();function i(e,t){return n(r(e),t)}t.exports=i})),xr=s(((e,t)=>{var n=J();function r(e,t){for(var r=0,a=arguments.length,o;++r{var n=Yn(),r=tr(),i=xr();function a(e){switch(n(e)){case`Object`:return o(e);case`Array`:return l(e);case`RegExp`:return s(e);case`Date`:return c(e);default:return e}}function o(e){return r(e)?i({},e):e}function s(e){var t=``;return t+=e.multiline?`m`:``,t+=e.global?`g`:``,t+=e.ignoreCase?`i`:``,new RegExp(e.source,t)}function c(e){return new Date(+e)}function l(e){return e.slice()}t.exports=a})),Cr=s(((e,t)=>{var n=Sr(),r=J(),i=Yn(),a=tr();function o(e,t){switch(i(e)){case`Object`:return s(e,t);case`Array`:return c(e,t);default:return n(e)}}function s(e,t){if(a(e)){var n={};return r(e,function(e,n){this[n]=o(e,t)},n),n}else if(t)return t(e);else return e}function c(e,t){for(var n=[],r=-1,i=e.length;++r{var n=Bn(),r=Cr(),i=ar();function a(){for(var e=1,t,o,s,c=r(arguments[0]);s=arguments[e++];)for(t in s)n(s,t)&&(o=s[t],i(o)&&i(c[t])?c[t]=a(c[t],o):c[t]=r(o));return c}t.exports=a})),Tr=s(((e,t)=>{var n=Y();function r(e,t,r){if(e==null||!e.length)return-1/0;if(e.length&&!t)return Math.min.apply(Math,e);t=n(t,r);for(var i,a=1/0,o,s,c=-1,l=e.length;++c{var n=Tr(),r=yr();function i(e,t){return n(r(e),t)}t.exports=i})),Dr=s(((e,t)=>{var n=Gn();function r(e,t){return t&&n(t.split(`.`),function(t){e[t]||(e[t]={}),e=e[t]}),e}t.exports=r})),Or=s(((e,t)=>{function n(e,t,n){if(n||=0,e==null)return-1;for(var r=e.length,i=n<0?r+n:n;i{var n=Or();function r(e,t){return n(e,t)!==-1}t.exports=r})),Ar=s(((e,t)=>{var n=Un(),r=kr();function i(e,t){var i=typeof arguments[1]==`string`?n(arguments,1):arguments[1],a={};for(var o in e)e.hasOwnProperty(o)&&!r(i,o)&&(a[o]=e[o]);return a}t.exports=i})),jr=s(((e,t)=>{var n=Un();function r(e,t){for(var r=typeof arguments[1]==`string`?n(arguments,1):arguments[1],i={},a=0,o;o=r[a++];)i[o]=e[o];return i}t.exports=r})),Mr=s(((e,t)=>{var n=gr(),r=Jn();function i(e,t){return n(e,r(t))}t.exports=i})),Nr=s(((e,t)=>{var n=J();function r(e){var t=0;return n(e,function(){t++}),t}t.exports=r})),Pr=s(((e,t)=>{var n=J(),r=Nr();function i(e,t,i,a){var o=arguments.length>2;if(!r(e)&&!o)throw Error(`reduce of empty object with no initial value`);return n(e,function(e,n,r){o?i=t.call(a,i,e,n,r):(i=e,o=!0)}),i}t.exports=i})),Fr=s(((e,t)=>{var n=lr(),r=Y();function i(e,t,i){return t=r(t,i),n(e,function(e,n,r){return!t(e,n,r)},i)}t.exports=i})),Ir=s(((e,t)=>{var n=Xn();function r(e){return n(e,`Function`)}t.exports=r})),Lr=s(((e,t)=>{var n=Ir();function r(e,t){var r=e[t];if(r!==void 0)return n(r)?r.call(e):r}t.exports=r})),Rr=s(((e,t)=>{var n=Dr();function r(e,t,r){var i=/^(.+)\.(.+)$/.exec(t);i?n(e,i[1])[i[2]]=r:e[t]=r}t.exports=r})),zr=s(((e,t)=>{var n=mr();function r(e,t){if(n(e,t)){for(var r=t.split(`.`),i=r.pop();t=r.shift();)e=e[t];return delete e[i]}else return!0}t.exports=r})),Br=s(((e,t)=>{t.exports={bindAll:Kn(),contains:er(),deepFillIn:nr(),deepMatches:Qn(),deepMixIn:rr(),equals:sr(),every:ir(),fillIn:cr(),filter:lr(),find:ur(),flatten:dr(),forIn:Vn(),forOwn:J(),functions:Hn(),get:pr(),has:mr(),hasOwn:Bn(),keys:hr(),map:gr(),matches:_r(),max:br(),merge:wr(),min:Er(),mixIn:xr(),namespace:Dr(),omit:Ar(),pick:jr(),pluck:Mr(),reduce:Pr(),reject:Fr(),result:Lr(),set:Rr(),size:Nr(),some:$n(),unset:zr(),values:yr()}})),Vr=s(((e,t)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.default=(0,Br().map)({A:{x:.44758,y:.40745},C:{x:.31006,y:.31616},D50:{x:.34567,y:.35851},D65:{x:.31272,y:.32903},D55:{x:.33243,y:.34744},D75:{x:.29903,y:.31488}},function(e){return[100*(e.x/e.y),100,100*(1-e.x-e.y)/e.y]}),t.exports=e.default})),Hr=s(((e,t)=>{Object.defineProperty(e,"__esModule",{value:!0});var n=Math,r=n.pow,i=n.sign,a=n.abs,o={decode:function(e){return e<=.04045?e/12.92:r((e+.055)/1.055,2.4)},encode:function(e){return e<=.0031308?12.92*e:1.055*r(e,1/2.4)-.055}},s={encode:function(e){return e<.001953125?16*e:r(e,1/1.8)},decode:function(e){return e<16*.001953125?e/16:r(e,1.8)}};function c(e){return{decode:function(t){return i(t)*r(a(t),e)},encode:function(t){return i(t)*r(a(t),1/e)}}}e.default={sRGB:{r:{x:.64,y:.33},g:{x:.3,y:.6},b:{x:.15,y:.06},gamma:o},"Adobe RGB":{r:{x:.64,y:.33},g:{x:.21,y:.71},b:{x:.15,y:.06},gamma:c(2.2)},"Wide Gamut RGB":{r:{x:.7347,y:.2653},g:{x:.1152,y:.8264},b:{x:.1566,y:.0177},gamma:c(563/256)},"ProPhoto RGB":{r:{x:.7347,y:.2653},g:{x:.1596,y:.8404},b:{x:.0366,y:1e-4},gamma:s}},t.exports=e.default})),Ur=s((e=>{Object.defineProperty(e,"__esModule",{value:!0});function t(e){return[[e[0][0],e[1][0],e[2][0]],[e[0][1],e[1][1],e[2][1]],[e[0][2],e[1][2],e[2][2]]]}function n(e){return e[0][0]*(e[2][2]*e[1][1]-e[2][1]*e[1][2])+e[1][0]*(e[2][1]*e[0][2]-e[2][2]*e[0][1])+e[2][0]*(e[1][2]*e[0][1]-e[1][1]*e[0][2])}function r(e){var t=1/n(e);return[[(e[2][2]*e[1][1]-e[2][1]*e[1][2])*t,(e[2][1]*e[0][2]-e[2][2]*e[0][1])*t,(e[1][2]*e[0][1]-e[1][1]*e[0][2])*t],[(e[2][0]*e[1][2]-e[2][2]*e[1][0])*t,(e[2][2]*e[0][0]-e[2][0]*e[0][2])*t,(e[1][0]*e[0][2]-e[1][2]*e[0][0])*t],[(e[2][1]*e[1][0]-e[2][0]*e[1][1])*t,(e[2][0]*e[0][1]-e[2][1]*e[0][0])*t,(e[1][1]*e[0][0]-e[1][0]*e[0][1])*t]]}function i(e,t){return[e[0][0]*t[0]+e[0][1]*t[1]+e[0][2]*t[2],e[1][0]*t[0]+e[1][1]*t[1]+e[1][2]*t[2],e[2][0]*t[0]+e[2][1]*t[1]+e[2][2]*t[2]]}function a(e,t){return[[e[0][0]*t[0],e[0][1]*t[1],e[0][2]*t[2]],[e[1][0]*t[0],e[1][1]*t[1],e[1][2]*t[2]],[e[2][0]*t[0],e[2][1]*t[1],e[2][2]*t[2]]]}function o(e,t){return[[e[0][0]*t[0][0]+e[0][1]*t[1][0]+e[0][2]*t[2][0],e[0][0]*t[0][1]+e[0][1]*t[1][1]+e[0][2]*t[2][1],e[0][0]*t[0][2]+e[0][1]*t[1][2]+e[0][2]*t[2][2]],[e[1][0]*t[0][0]+e[1][1]*t[1][0]+e[1][2]*t[2][0],e[1][0]*t[0][1]+e[1][1]*t[1][1]+e[1][2]*t[2][1],e[1][0]*t[0][2]+e[1][1]*t[1][2]+e[1][2]*t[2][2]],[e[2][0]*t[0][0]+e[2][1]*t[1][0]+e[2][2]*t[2][0],e[2][0]*t[0][1]+e[2][1]*t[1][1]+e[2][2]*t[2][1],e[2][0]*t[0][2]+e[2][1]*t[1][2]+e[2][2]*t[2][2]]]}e.transpose=t,e.determinant=n,e.inverse=r,e.multiply=i,e.scalar=a,e.product=o})),Wr=s((e=>{Object.defineProperty(e,"__esModule",{value:!0});var t=Math.PI;function n(e){for(var n=e*180/t;n<0;)n+=360;for(;n>360;)n-=360;return n}function r(e){for(var n=t*e/180;n<0;)n+=2*t;for(;n>2*t;)n-=2*t;return n}e.fromRadian=n,e.toRadian=r})),Gr=s((e=>{Object.defineProperty(e,"__esModule",{value:!0});var t=Math.round;function n(e){return e[0]==`#`&&(e=e.slice(1)),e.length<6&&(e=e.split(``).map(function(e){return e+e}).join(``)),e.match(/../g).map(function(e){return parseInt(e,16)/255})}function r(e){return`#`+e.map(function(e){return e=t(255*e).toString(16),e.length<2&&(e=`0`+e),e}).join(``)}e.fromHex=n,e.toHex=r})),Kr=s(((e,t)=>{Object.defineProperty(e,"__esModule",{value:!0});var n=o(Ur()),r=a(Vr()),i=a(Hr());function a(e){return e&&e.__esModule?e:{default:e}}function o(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}function s(){var e=arguments.length<=0||arguments[0]===void 0?i.default.sRGB:arguments[0],t=arguments.length<=1||arguments[1]===void 0?r.default.D65:arguments[1],a=[e.r,e.g,e.b],o=n.transpose(a.map(function(e){return[e.x/e.y,1,(1-e.x-e.y)/e.y]})),s=e.gamma,c=n.multiply(n.inverse(o),t),l=n.scalar(o,c),u=n.inverse(l);return{fromRgb:function(e){return n.multiply(l,e.map(s.decode))},toRgb:function(e){return n.multiply(u,e).map(s.encode)}}}e.default=s,t.exports=e.default})),qr=s(((e,t)=>{t.exports={illuminant:Vr(),workspace:Hr(),matrix:Ur(),degree:Wr(),rgb:Gr(),xyz:Kr()}})),Jr=s((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.cfs=e.distance=e.lerp=e.corLerp=void 0;var t=Br();function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);ti/2&&(e>t?t+=i:e+=i),((1-n)*e+n*t)%(i||1/0)}function u(e,t,n){var r={};for(var i in e)r[i]=l(e[i],t[i],n,i);return r}function d(e,t){var n=0;for(var r in e)n+=o(e[r]-t[r],2);return s(n)}function f(e){return t.merge.apply(void 0,r(e.split(``).map(function(e){return n({},e,!0)})))}e.corLerp=l,e.lerp=u,e.distance=d,e.cfs=f})),Yr=s(((e,t)=>{var n=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o=e[Symbol.iterator](),s;!(r=(s=o.next()).done)&&(n.push(s.value),!(t&&n.length===t));r=!0);}catch(e){i=!0,a=e}finally{try{!r&&o.return&&o.return()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw TypeError(`Invalid attempt to destructure non-iterable instance`)}}();Object.defineProperty(e,"__esModule",{value:!0});var r=qr(),i=Jr();function a(e,t){var a=arguments.length<=2||arguments[2]===void 0?1e-6:arguments[2],o=-a,s=1+a,c=Math,l=c.min,u=c.max,d=n([`000`,`fff`].map(function(n){return t.fromXyz(e.fromRgb(r.rgb.fromHex(n)))}),2),f=d[0],p=d[1];function m(n){var r=e.toRgb(t.toXyz(n));return[r.map(function(e){return e>=o&&e<=s}).reduce(function(e,t){return e&&t},!0),r]}function h(e,t){for(var r=arguments.length<=2||arguments[2]===void 0?.001:arguments[2];(0,i.distance)(e,t)>r;){var a=(0,i.lerp)(e,t,.5);n(m(a),1)[0]?e=a:t=a}return e}function g(e){return(0,i.lerp)(f,p,e)}function _(e){return e.map(function(e){return u(o,l(s,e))})}return{contains:m,limit:h,spine:g,crop:_}}e.default=a,t.exports=e.default})),Xr=s((e=>{var t=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o=e[Symbol.iterator](),s;!(r=(s=o.next()).done)&&(n.push(s.value),!(t&&n.length===t));r=!0);}catch(e){i=!0,a=e}finally{try{!r&&o.return&&o.return()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw TypeError(`Invalid attempt to destructure non-iterable instance`)}}();Object.defineProperty(e,"__esModule",{value:!0}),e.toNotation=e.fromNotation=e.toHue=e.fromHue=void 0;var n=Jr(),r=Math.floor,i=[{s:`R`,h:20.14,e:.8,H:0},{s:`Y`,h:90,e:.7,H:100},{s:`G`,h:164.25,e:1,H:200},{s:`B`,h:237.53,e:1.2,H:300},{s:`R`,h:380.14,e:.8,H:400}],a=i.map(function(e){return e.s}).slice(0,-1).join(``);function o(e){e50){var o=[n,t];t=o[0],n=o[1],i=100-i}return i<1?a[t]:a[t]+i.toFixed()+a[n]}e.fromHue=o,e.toHue=s,e.fromNotation=l,e.toNotation=u})),Zr=s(((e,t)=>{var n=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o=e[Symbol.iterator](),s;!(r=(s=o.next()).done)&&(n.push(s.value),!(t&&n.length===t));r=!0);}catch(e){i=!0,a=e}finally{try{!r&&o.return&&o.return()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw TypeError(`Invalid attempt to destructure non-iterable instance`)}}();Object.defineProperty(e,"__esModule",{value:!0});var r=qr(),i=s(Xr()),a=Jr(),o=Br();function s(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var c=Math,l=c.pow,u=c.sqrt,d=c.exp,f=c.abs,p=c.sign,m=Math,h=m.sin,g=m.cos,_=m.atan2,v={average:{F:1,c:.69,N_c:1},dim:{F:.9,c:.59,N_c:.9},dark:{F:.8,c:.535,N_c:.8}},y=[[.7328,.4296,-.1624],[-.7036,1.6975,.0061],[.003,.0136,.9834]],b=[[.38971,.68898,-.07868],[-.22981,1.1834,.04641],[0,0,1]],x=y,S=r.matrix.inverse(y),C=r.matrix.product(b,r.matrix.inverse(y)),w=r.matrix.product(y,r.matrix.inverse(b)),T={whitePoint:r.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:`average`,discounting:!1},ee=(0,a.cfs)(`QJMCshH`),E=(0,a.cfs)(`JCh`);function D(){var e=arguments.length<=0||arguments[0]===void 0?{}:arguments[0],t=arguments.length<=1||arguments[1]===void 0?ee:arguments[1];e=(0,o.merge)(T,e);var a=e.whitePoint,s=e.adaptingLuminance,c=e.backgroundLuminance,m=v[e.surroundType],b=m.F,D=m.c,O=m.N_c,te=a[1],k=1/(5*s+1),A=.2*l(k,4)*5*s+.1*l(1-l(k,4),2)*l(5*s,1/3),ne=c/te,re=.725*l(1/ne,.2),ie=re,ae=1.48+u(ne),oe=e.discounting?1:b*(1-1/3.6*d(-(s+42)/92)),j=n(r.matrix.multiply(y,a).map(function(e){return oe*te/e+1-oe}),3),se=j[0],M=j[1],ce=j[2],N=pe(de(le(a)));function le(e){var t=n(r.matrix.multiply(x,e),3),i=t[0],a=t[1],o=t[2];return[se*i,M*a,ce*o]}function ue(e){var t=n(e,3),i=t[0],a=t[1],o=t[2];return r.matrix.multiply(S,[i/se,a/M,o/ce])}function de(e){return r.matrix.multiply(C,e).map(function(e){var t=l(A*f(e)/100,.42);return p(e)*400*t/(27.13+t)+.1})}function fe(e){return r.matrix.multiply(w,e.map(function(e){var t=e-.1;return p(t)*100/A*l(27.13*f(t)/(400-f(t)),1/.42)}))}function pe(e){var t=n(e,3),r=t[0],i=t[1],a=t[2];return(r*2+i+a/20-.305)*re}function me(e){return 4/D*u(e/100)*(N+4)*l(A,.25)}function he(e){return 6.25*l(D*e/((N+4)*l(A,.25)),2)}function ge(e){return e*l(A,.25)}function _e(e,t){return l(e/100,2)*t/l(A,.25)}function ve(e){return e/l(A,.25)}function ye(e,t){return 100*u(e/t)}function be(e,t){var n=t.Q,r=t.J,a=t.M,o=t.C,s=t.s,c=t.h,l=t.H,u={};return e.J&&(u.J=isNaN(r)?he(n):r),e.C&&(isNaN(o)?isNaN(a)?(n=isNaN(n)?me(r):n,u.C=_e(s,n)):u.C=ve(a):u.C=t.C),e.h&&(u.h=isNaN(c)?i.toHue(l):c),e.Q&&(u.Q=isNaN(n)?me(r):n),e.M&&(u.M=isNaN(a)?ge(o):a),e.s&&(isNaN(s)?(n=isNaN(n)?me(r):n,a=isNaN(a)?ge(o):a,u.s=ye(a,n)):u.s=s),e.H&&(u.H=isNaN(l)?i.fromHue(c):l),u}function P(e){var i=de(le(e)),a=n(i,3),o=a[0],s=a[1],c=a[2],d=o-s*12/11+c/11,f=(o+s-2*c)/9,p=_(f,d),m=r.degree.fromRadian(p),h=1/4*(g(p+2)+3.8),v=100*l(pe(i)/N,D*ae);return be(t,{J:v,C:l(5e4/13*O*ie*h*u(d*d+f*f)/(o+s+21/20*c),.9)*u(v/100)*l(1.64-l(.29,ne),.73),h:m})}function F(e){var t=be(E,e),n=t.J,i=t.C,a=t.h,o=r.degree.toRadian(a),s=l(i/(u(n/100)*l(1.64-l(.29,ne),.73)),10/9),c=1/4*(g(o+2)+3.8),d=N*l(n/100,1/D/ae),p=5e4/13*O*ie*c/s,m=d/re+.305,_=m*61/20*460/1403,v=61/20*220/1403,y=21/20*6300/1403-27/1403,b=h(o),x=g(o),S,C;return s===0||isNaN(s)?S=C=0:f(b)>=f(x)?(C=_/(p/b+v*x/b+y),S=C*x/b):(S=_/(p/x+v+y*b/x),C=S*b/x),ue(fe([20/61*m+451/1403*S+288/1403*C,20/61*m-891/1403*S-261/1403*C,20/61*m-220/1403*S-6300/1403*C]))}return{fromXyz:P,toXyz:F,fillOut:be}}e.default=D,t.exports=e.default})),Qr=s(((e,t)=>{Object.defineProperty(e,"__esModule",{value:!0});var n=qr(),r=Math,i=r.sqrt,a=r.pow,o=r.exp,s=r.log,c=r.cos,l=r.sin,u=r.atan2,d={LCD:{K_L:.77,c_1:.007,c_2:.0053},SCD:{K_L:1.24,c_1:.007,c_2:.0363},UCS:{K_L:1,c_1:.007,c_2:.0228}};function f(){var e=d[arguments.length<=0||arguments[0]===void 0?`UCS`:arguments[0]],t=e.K_L,r=e.c_1,f=e.c_2;function p(e){var t=e.J,i=e.M,a=e.h,o=n.degree.toRadian(a),u=(1+100*r)*t/(1+r*t),d=1/f*s(1+f*i);return{J_p:u,a_p:d*c(o),b_p:d*l(o)}}function m(e){var t=e.J_p,s=e.a_p,c=e.b_p,l=-t/(r*t-100*r-1),d=(o(f*i(a(s,2)+a(c,2)))-1)/f,p=u(c,s);return{J:l,M:d,h:n.degree.fromRadian(p)}}function h(e,n){return i(a((e.J_p-n.J_p)/t,2)+a(e.a_p-n.a_p,2)+a(e.b_p-n.b_p,2))}return{fromCam:p,toCam:m,distance:h}}e.default=f,t.exports=e.default})),$r=s(((e,t)=>{var n=Jr(),r=Yr(),i=Zr(),a=Qr(),o=Xr();t.exports={gamut:r,cfs:n.cfs,lerp:n.lerp,cam:i,ucs:a,hq:o}})),ei=l(qr(),1),ti=l($r(),1);function ni(e){let t=new q;return t.rgb_r=e[0],t.rgb_g=e[1],t.rgb_b=e[2],t.rgbToHsluv(),[t.hsluv_h,t.hsluv_s,t.hsluv_l]}function ri(e){let t=new q;return t.hsluv_h=e[0],t.hsluv_s=e[1],t.hsluv_l=e[2],t.hsluvToRgb(),[t.rgb_r,t.rgb_g,t.rgb_b]}var ii=ti.default.cam({whitePoint:ei.default.illuminant.D65,adaptingLuminance:40,backgroundLuminance:20,surroundType:`average`,discounting:!1},ti.default.cfs(`JCh`)),ai=ei.default.xyz(ei.default.workspace.sRGB,ei.default.illuminant.D65),oi=e=>ai.toRgb(ii.toXyz({J:e[0],C:e[1],h:e[2]})),si=e=>{let t=ii.fromXyz(ai.fromRgb(e));return[t.J,t.C,t.h]},[ci,li]=(()=>{let e={k_l:1,c1:.007,c2:.0228},t=Math.PI,n=64/t/5,r=1/(5*n+1),i=.2*r**4*(5*n)+.1*(1-r**4)**2*(5*n)**(1/3);return[n=>{let[r,a,o]=n,s=a*i**.25,c=(1+100*e.c1)*r/(1+e.c1*r);c/=e.k_l;let l=1/e.c2*Math.log(1+e.c2*s),u=l*Math.cos(t/180*o),d=l*Math.sin(t/180*o);return[c,u,d]},n=>{let[r,a,o]=n,s=Math.sqrt(a*a+o*o),c=(Math.exp(s*e.c2)-1)/e.c2,l=(180/t*Math.atan2(o,a)+360)%360,u=c/i**.25;return[r/(1+e.c1*(100-r)),u,l]}]})(),ui=e=>oi(li(e)),di=e=>ci(si(e)),fi=console;fi.color=(e,t=``)=>{let n=K(e).luminance();fi.log(`%c${e} ${t}`,`background-color: ${e};padding: 5px; border-radius: 5px; color: ${n>.5?`#000`:`#fff`}`)},fi.ramp=(e,t=1)=>{fi.log(`%c `,`font-size: 1px;line-height: 16px;background: ${K.getCSSGradient(e,t)};padding: 0 0 0 200px; border-radius: 2px;`)};var pi=(e,t,n,r,i,a,o=.1)=>{if(e===n||t===r)return!0;let s=(r-t)/(n-e),c=(a+i/s-t+s*e)/(s+1/s),l=a+i/s-c/s;return(i-c)**2+(a-l)**2{let i=(t[0]+n[0])/2,a=e(i);return pi(...t,...n,i,a,r)?null:[i,a]},hi=(e,t,n,r=.1)=>{let i=(n-t)/10,a=[];for(let r=t;rMath.round(e*10**t)/10**t,_i=(e,t=1,n=90,r=.005)=>{let i=hi(t=>e(t).gl()[0],0,t,r),a=hi(t=>e(t).gl()[1],0,t,r),o=hi(t=>e(t).gl()[2],0,t,r);return`linear-gradient(${n}deg, ${Array.from(new Set([...i.map(e=>gi(e[0])),...a.map(e=>gi(e[0])),...o.map(e=>gi(e[0]))].sort((e,t)=>e-t))).map(t=>`${e(t).hex()} ${gi(t*100)}%`).join()});`},vi=e=>{e.Color.prototype.jch=function(){return si(this._rgb.slice(0,3).map(e=>e/255))},e.jch=(...t)=>new e.Color(...oi(t).map(e=>Math.floor(e*255)),`rgb`),e.Color.prototype.jab=function(){return di(this._rgb.slice(0,3).map(e=>e/255))},e.jab=(...t)=>new e.Color(...ui(t).map(e=>Math.floor(e*255)),`rgb`),e.Color.prototype.hsluv=function(){return ni(this._rgb.slice(0,3).map(e=>e/255))},e.hsluv=(...t)=>new e.Color(...ri(t).map(e=>Math.floor(e*255)),`rgb`);let t=e.interpolate,n={jch:si,jab:di,hsluv:ni},r=(e,t,n)=>(Math.abs(e-t)>360/2&&(e>t?t+=360:e+=360),((1-n)*e+n*t)%360);e.interpolate=(i,a,o=.5,s=`lrgb`)=>{if(n[s]){typeof i!=`object`&&(i=new e.Color(i)),typeof a!=`object`&&(a=new e.Color(a));let t=n[s](i.gl()),c=n[s](a.gl()),l=Number.isNaN(i.hsl()[0]),u=Number.isNaN(a.hsl()[0]),d,f,p;switch(s){case`hsluv`:t[1]<1e-10&&(t[0]=c[0]),t[1]===0&&(t[1]=c[1]),c[1]<1e-10&&(c[0]=t[0]),c[1]===0&&(c[1]=t[1]),d=r(t[0],c[0],o),f=t[1]+(c[1]-t[1])*o,p=t[2]+(c[2]-t[2])*o;break;case`jch`:l&&(t[2]=c[2]),u&&(c[2]=t[2]),d=t[0]+(c[0]-t[0])*o,f=t[1]+(c[1]-t[1])*o,p=r(t[2],c[2],o);break;default:d=t[0]+(c[0]-t[0])*o,f=t[1]+(c[1]-t[1])*o,p=t[2]+(c[2]-t[2])*o}return e[s](d,f,p).alpha(i.alpha()+o*(a.alpha()-i.alpha()))}return t(i,a,o,s)},e.getCSSGradient=_i},X={mainTRC:2.4,get mainTRCencode(){return 1/this.mainTRC},sRco:.2126729,sGco:.7151522,sBco:.072175,normBG:.56,normTXT:.57,revTXT:.62,revBG:.65,blkThrs:.022,blkClmp:1.414,scaleBoW:1.14,scaleWoB:1.14,loBoWoffset:.027,loWoBoffset:.027,deltaYmin:5e-4,loClip:.1,mFactor:1.9468554433171,get mFactInv(){return 1/this.mFactor},mOffsetIn:.0387393816571401,mExpAdj:.283343396420869,get mExp(){return this.mExpAdj/this.blkClmp},mOffsetOut:.312865795870758};function yi(e,t,n=-1){let r=[0,1.1];if(isNaN(e)||isNaN(t)||Math.min(e,t)r[1])return 0;let i=0,a=0,o=`BoW`;return e=e>X.blkThrs?e:e+(X.blkThrs-e)**+X.blkClmp,t=t>X.blkThrs?t:t+(X.blkThrs-t)**+X.blkClmp,Math.abs(t-e)e?(i=(t**+X.normBG-e**+X.normTXT)*X.scaleBoW,a=i-X.loClip?0:i+X.loWoBoffset),n<0?a*100:n==0?Math.round(Math.abs(a)*100)+``+o+``:Number.isInteger(n)?(a*100).toFixed(n):0)}function bi(e=[0,0,0]){function t(e){return(e/255)**X.mainTRC}return X.sRco*t(e[0])+X.sGco*t(e[1])+X.sBco*t(e[2])}var xi=(e,t,n,r,i,a,o,s,c)=>{let l=1-c,u=l*l,d=u*l,f=c*c*c;return{x:d*e+u*3*c*n+l*3*c*c*i+f*o,y:d*t+u*3*c*r+l*3*c*c*a+f*s}},Si=(e,t)=>{let n=[],r={x:+e[0],y:+e[1]};for(let i=0,a=e.length;a-2*!t>i;i+=2){let o=[{x:+e[i-2],y:+e[i-1]},{x:+e[i],y:+e[i+1]},{x:+e[i+2],y:+e[i+3]},{x:+e[i+4],y:+e[i+5]}];t?i?a-4===i?o[3]={x:+e[0],y:+e[1]}:a-2===i&&(o[2]={x:+e[0],y:+e[1]},o[3]={x:+e[2],y:+e[3]}):o[0]={x:+e[a-2],y:+e[a-1]}:a-4===i?o[3]=o[2]:i||(o[0]={x:+e[i],y:+e[i+1]}),n.push([r.x,r.y,(-o[0].x+6*o[1].x+o[2].x)/6,(-o[0].y+6*o[1].y+o[2].y)/6,(o[1].x+6*o[2].x-o[3].x)/6,(o[1].y+6*o[2].y-o[3].y)/6,o[2].x,o[2].y]),r=o[2]}return n},Ci=(e,t,n,r,i,a,o,s)=>{let c=e,l=t,u=0;for(let d=1;d<5;d++){let{x:f,y:p}=xi(e,t,n,r,i,a,o,s,d/5);u+=Math.hypot(f-c,p-l),c=f,l=p}return u+=Math.hypot(o-c,s-l),u},wi=(e,t,n,r,i,a,o,s)=>{let c=Math.floor(Ci(e,t,n,r,i,a,o,s)*.75),l=[],u=0;for(let d=0;d<=c;d++){let f=xi(e,t,n,r,i,a,o,s,d/c),p=Math.round(f.x);if(l[p]=f.y,p-u>1){let e=l[u],t=l[p];for(let n=u+1;nl[Math.round(e)]||null},Ti={CAM02:`jab`,CAM02p:`jch`,HEX:`hex`,HSL:`hsl`,HSLuv:`hsluv`,HSV:`hsv`,LAB:`lab`,LCH:`lch`,RGB:`rgb`,OKLAB:`oklab`,OKLCH:`oklch`};function Z(e,t=0){let n=10**t;return Math.round(e*n)/n}function Ei(e,t){let n;return n=e>1?(e-1)*t+1:e<-1?(e+1)*t-1:1,Z(n,2)}function Di(e){return K(String(e)).jch()}function Oi(e){return K(String(e)).hsluv()}function ki(e,t,n){let r=[[],[],[]];if(e.forEach((e,n)=>r.forEach((r,i)=>r.push(t[n],e[i]))),n===`hcl`){let e=r[1];for(let t=1;t{let t=[];for(let n=1;n{e[t]=e[n]}),t.length=0;break}if(t.length){let n=K(`#ccc`).jch()[2];t.forEach(t=>{e[t]=n})}t.length=0;for(let n=e.length-1;n>0;n-=2)if(Number.isNaN(e[n]))t.push(n);else{t.forEach(t=>{e[t]=e[n]});break}for(let t=1;tSi(e).map(e=>wi(...e)));return e=>{let t=i.map(t=>{for(let n=0;nr*t**e+i}function ji({swatches:e,colorKeys:t,colorspace:n,colorSpace:r=n??`LAB`,shift:i=1,fullScale:a=!0,smooth:o=!1,distributeLightness:s=`linear`,sortColor:c=!0,asFun:l=!1}={}){n!==void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead.");let u=Ti[r];if(!u)throw Error(`Colorspace “${r}” not supported`);if(!t)throw Error(`Colorkeys missing: returned “${t}”`);let d;if(a)d=t.map(t=>e-e*(K(t).jch()[0]/100)).sort((e,t)=>e-t).concat(e),d.unshift(0);else{let n=t.map(e=>K(e).jch()[0]/100),r=Math.min(...n),i=Math.max(...n);d=n.map(t=>t===0||isNaN((t-r)/(i-r))?0:e-(t-r)/(i-r)*e).sort((e,t)=>e-t)}let f=Ai(i,[1,e],[1,e]);if(f=d.map(e=>Math.max(0,f(e))),d=f,s===`polynomial`){let t=e=>Math.sqrt(Math.sqrt((e**2.25+e**4)/2));d=f.map(t=>t/e).map(n=>t(n)*e)}let p=t.map((e,t)=>({colorKeys:Di(e),index:t})).sort((e,t)=>t.colorKeys[0]-e.colorKeys[0]).map(e=>t[e.index]),m=[],h;if(a){let e=u===`lch`?K.lch(...K(`#fff`).lch()):`#ffffff`,t=u===`lch`?K.lch(...K(`#000`).lch()):`#000000`;m=[e,...p,t]}else m=c?p:t;let g;if(o){let t=m;if(m=m.map(e=>K(String(e))[u]()),u===`hcl`&&m.forEach(e=>{e[1]=Number.isNaN(e[1])?0:e[1]}),u===`jch`)for(let e=0;eh(t))}else h=K.scale(m.map(e=>typeof e==`object`&&e.constructor===K.Color?e:String(e))).domain(d).mode(u);return l?h:(!o||o===!1?h.colors(e):g).filter(e=>e!=null)}function Mi(e,t){let n=[],r={};return Object.keys(e).forEach(n=>{r[e[n][t]]=e[n]}),Object.keys(r).forEach(e=>n.push(r[e])),n}function Ni(e){return Number.isNaN(e)?0:e}function Pi(e,t,n=!1){if(!e)throw Error(`Cannot convert color value of “${e}”`);if(!Ti[t])throw Error(`Cannot convert to colorspace “${t}”`);let r=Ti[t],i=K(String(e))[r]();if(t===`HSL`&&i.pop(),t===`HEX`){if(n){let t=K(String(e)).rgb();return{r:t[0],g:t[1],b:t[2]}}return i}let a={},o=i.map(Ni);o=o.map((e,t)=>{let i=Z(e),o=t;r===`hsluv`&&(o+=2);let s=r.charAt(o);return r===`jch`&&s===`c`&&(s=`C`),a[s===`j`?`J`:s]=i,r in{lab:1,lch:1,jab:1,jch:1}?n||(s===`l`||s===`j`)&&(i+=`%`):r!==`hsluv`&&(s===`s`||s===`l`||s===`v`)&&(a[s]=Z(e,2),n||(i=Z(e*100),i+=`%`)),i});let s=`${r}(${o.join(`, `)})`;return n?a:s}function Fi(e,t,n){let r=[e,t,n].map(e=>(e/=255,e<=.03928?e/12.92:((e+.055)/1.055)**2.4));return r[0]*.2126+r[1]*.7152+r[2]*.0722}function Ii(e,t,n,r=`wcag2`){if(n===void 0){let e=K.rgb(...t).hsluv()[2];n=Z(e/100,2)}if(r===`wcag2`){let r=Fi(e[0],e[1],e[2]),i=Fi(t[0],t[1],t[2]),a=(r+.05)/(i+.05),o=(i+.05)/(r+.05);return n<.5?a>=1?a:-o:a<1?o:a===1?a:-a}else if(r===`wcag3`)return n<.5?yi(bi(e),bi(t))*-1:yi(bi(e),bi(t));else throw Error(`Contrast calculation method ${r} unsupported; use 'wcag2' or 'wcag3'`)}function Li(e,t){if(!e)throw Error(`Array undefined`);if(!Array.isArray(e))throw Error(`Passed object is not an array`);let n=t===`wcag2`?0:1;return Math.min(...e.filter(e=>e>=n))}function Ri(e,t){if(!e)throw Error(`Ratios undefined`);e=e.sort((e,t)=>e-t);let n=Li(e,t),r=e.indexOf(n),i=[],a=e.slice(0,r),o=e.slice(r,e.length);for(let e=0;ee-t),i}var zi=(e,t,n,r,i)=>{let a=3e3,o=ji({swatches:a,colorKeys:e._modifiedKeys,colorspace:e._colorspace,shift:1,smooth:e._smooth,asFun:!0}),s={},c=e=>{if(s[e])return s[e];let r=Ii(K(o(e)).rgb(),t,n,i);return s[e]=r,r},l=e=>{let t=c(0).01&&o;)o--,n/=2,iu.push(o(l(+e)))),u},Q=class{constructor({name:e,colorKeys:t,colorspace:n,colorSpace:r=n??`RGB`,ratios:i,smooth:a=!1,output:o=`HEX`,saturation:s=100}){if(n!==void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),this._name=e,this._colorKeys=t,this._modifiedKeys=t,this._colorspace=r,this._ratios=i,this._smooth=a,this._output=o,this._saturation=s,!this._name)throw Error(`Color missing name`);if(!this._colorKeys)throw Error(`Color Keys are undefined`);if(!Ti[this._colorspace])throw Error(`Colorspace “${r}” not supported`);if(!Ti[this._output])throw Error(`Output “${this._output}” not supported`);for(let e=0;e{let n=K(`${t}`).oklch(),r=n[1]*(this._saturation/100),i=K.oklch(n[0],r,n[2]),a=K.rgb(i).hex();e.push(a)}),this._modifiedKeys=e,this._generateColorScale()}_generateColorScale(){this._colorScale=ji({swatches:3e3,colorKeys:this._modifiedKeys,colorSpace:this._colorspace,shift:1,smooth:this._smooth,asFun:!0})}},Bi=class extends Q{get backgroundColorScale(){return this._backgroundColorScale||this._generateColorScale(),this._backgroundColorScale}_generateColorScale(){Q.prototype._generateColorScale.call(this);let e=ji({swatches:1e3,colorKeys:this._colorKeys,colorspace:this._colorspace,shift:1,smooth:this._smooth});e.push(...this.colorKeys);let t=Mi(e.map((e,t)=>({value:Math.round(Oi(e)[2]),index:t})),`value`).map(t=>e[t.index]);return t.length>=101&&(t.length=100,t.push(`#ffffff`)),this._backgroundColorScale=t.map(e=>Pi(e,this._output)),this._backgroundColorScale}},Vi=class{constructor({colors:e,backgroundColor:t,lightness:n,contrast:r=1,saturation:i=100,output:a=`HEX`,formula:o=`wcag2`}){if(this._output=a,this._colors=e,this._lightness=n,this._saturation=i,this._formula=o,this._setBackgroundColor(t),this._setBackgroundColorValue(),this._contrast=r,!this._colors)throw Error(`No colors are defined`);if(!this._backgroundColor)throw Error(`Background color is undefined`);if(e.forEach(e=>{if(!e.ratios)throw Error(`Color ${e.name}'s ratios are undefined`)}),!Ti[this._output])throw Error(`Output “${a}” not supported`);this._saturation<100&&this._updateColorSaturation(this._saturation),this._findContrastColors(),this._findContrastColorPairs(),this._findContrastColorValues()}set formula(e){this._formula=e,this._findContrastColors()}get formula(){return this._formula}set contrast(e){this._contrast=e,this._findContrastColors()}get contrast(){return this._contrast}set lightness(e){this._lightness=e,this._setBackgroundColor(this._backgroundColor),this._findContrastColors()}get lightness(){return this._lightness}set saturation(e){this._saturation=e,this._updateColorSaturation(e),this._findContrastColors()}get saturation(){return this._saturation}set backgroundColor(e){this._setBackgroundColor(e),this._findContrastColors()}get backgroundColorValue(){return this._backgroundColorValue}get backgroundColor(){return this._backgroundColor}set colors(e){this._colors=e,this._findContrastColors()}get colors(){return this._colors}set addColor(e){this._colors.push(e),this._findContrastColors()}set removeColor(e){let t=this._colors.filter(t=>t.name!==e.name);this._colors=t,this._findContrastColors()}set updateColor(e){if(Array.isArray(e))for(let t=0;tn.name===e[t].color);n=n[0];let r=this._colors.indexOf(n),i=this._colors.filter(n=>n.name!==e[t].color);e[t].name&&(n.name=e[t].name),e[t].colorKeys&&(n.colorKeys=e[t].colorKeys),e[t].ratios&&(n.ratios=e[t].ratios),(e[t].colorSpace!==void 0||e[t].colorspace!==void 0)&&(e[t].colorspace!==void 0&&e[t].colorSpace===void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),n.colorSpace=e[t].colorSpace??e[t].colorspace),e[t].smooth&&(n.smooth=e[t].smooth),n._generateColorScale(),i.splice(r,0,n),this._colors=i}else{let t=this._colors.filter(t=>t.name===e.color);t=t[0];let n=this._colors.indexOf(t),r=this._colors.filter(t=>t.name!==e.color);e.name&&(t.name=e.name),e.colorKeys&&(t.colorKeys=e.colorKeys),e.ratios&&(t.ratios=e.ratios),(e.colorSpace!==void 0||e.colorspace!==void 0)&&(e.colorspace!==void 0&&e.colorSpace===void 0&&console.warn("Leonardo: `colorspace` is deprecated. Use `colorSpace` instead."),t.colorSpace=e.colorSpace??e.colorspace),e.smooth&&(t.smooth=e.smooth),t._generateColorScale(),r.splice(n,0,t),this._colors=r}this._findContrastColors()}set output(e){this._output=e,this._colors.forEach(e=>{e.output=this._output}),this._backgroundColor.output=this._output,this._findContrastColors()}get output(){return this._output}get contrastColors(){return this._contrastColors}get contrastColorPairs(){return this._contrastColorPairs}get contrastColorValues(){return this._contrastColorValues}_setBackgroundColor(e){if(typeof e==`string`){let t=new Bi({name:`background`,colorKeys:[e],output:`RGB`}),n=Z(K(String(e)).hsluv()[2]);this._backgroundColor=t,this._lightness=n,this._backgroundColorValue=t[this._lightness]}else{e.output=`RGB`;let t=e.backgroundColorScale[this._lightness];this._backgroundColor=e,this._backgroundColorValue=t}}_setBackgroundColorValue(){this._backgroundColorValue=this._backgroundColor.backgroundColorScale[this._lightness]}_updateColorSaturation(e){this._colors.map(t=>{t.saturation=e})}_findContrastColors(){let e=K(String(this._backgroundColorValue)).rgb(),t=this._lightness/100,n={background:Pi(this._backgroundColorValue,this._output)},r=[],i=[],a={...n};return r.push(n),this._colors.map(n=>{if(n.ratios!==void 0){let o,s=[],c={name:n.name,values:s},l;Array.isArray(n.ratios)?l=n.ratios:Array.isArray(n.ratios)||(o=Object.keys(n.ratios),l=Object.values(n.ratios)),l=l.map(e=>Ei(+e,this._contrast));let u=zi(n,e,t,l,this._formula).map(e=>Pi(e,this._output));for(let e=0;e{let t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return[Number.parseInt(t[1],16),Number.parseInt(t[2],16),Number.parseInt(t[3],16)]},Wi=(e,t,n)=>{let r=e/255,i=t/255,a=n/255,o=Math.min(r,i,a),s=Math.max(r,i,a),c=s-o,l=0,u=0,d=0;return l=c===0?0:s===r?(i-a)/c%6:s===i?(a-r)/c+2:(r-i)/c+4,l=Math.round(l*60),l<0&&(l+=360),d=(s+o)/2,u=c===0?0:c/(1-Math.abs(2*d-1)),u=+(u*100).toFixed(1),d=+(d*100).toFixed(1),[l,u,Math.round(d)]},Gi=(e,t,n,r)=>{let i=n/100,a=t*Math.min(i,1-i)/100,o=t=>{let n=(t+e/30)%12,r=i-a*Math.max(Math.min(n-3,9-n,1),-1);return Math.round(255*r).toString(16).padStart(2,`0`).toUpperCase()},s=o(0),c=o(8),l=o(4),u=((e,t,n)=>Math.min(Math.max(e,t),n))(r,0,1);return`#${s}${c}${l}${Math.round(u*255).toString(16).padStart(2,`0`).toUpperCase()}`},Ki=(e,t,n=1)=>{let r=Ui(e),i=Ui(t===`white`?`#FFFFFF`:t===`black`?`#000000`:t),a=r.map((e,t)=>[(e-i[t])/(255-i[t]),(e-i[t])/(0-i[t])]),o=Hi(Math.max(...a.flat().filter(e=>/^-?\d+\.?\d*$/.test(e)))),s=r.map((e,t)=>Math.round((e-i[t]+i[t]*o)/o));if(s.includes(NaN)){let e=Wi(r[0],r[1],r[2]);return{h:e[0],s:Math.round(e[1]*n),l:e[2],a:1}}let c=Wi(s[0],s[1],s[2]);return{h:c[0],s:Math.round(c[1]*n),l:c[2],a:o}},qi={backgroundColor:`gray`,colorSpace:`OKLCH`,colorSmoothing:!1,formula:`wcag2`,output:`HEX`,colors:{gray:[$(215,20,90),$(215,8,50),$(215,6,25)],red:[$(358,100,58),$(350,100,30)],orange:[$(32,100,48),$(12,100,30)],yellow:[$(50,100,50),$(25,100,20)],lime:[$(100,68,50),$(115,86,25)],green:[$(163,87,42),$(168,100,25)],cyan:[$(185,80,45),$(200,98,35)],blue:[$(212,98,46),$(222,95,25)],purple:[$(258,94,64),$(265,100,35)],fuchsia:[$(295,56,50),$(285,80,25)],pink:[$(334,90,50),$(330,91,25)]},themes:{light:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16.75],contrast:1,lightness:100,saturation:100},dark:{ratios:[1.03,1.06,1.12,1.25,1.5,1.75,2.25,3.5,5.25,6.5,8,10.5,13.75,16],contrast:1,lightness:6,saturation:97},lightHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:100,saturation:100},darkHc:{ratios:[1.06,1.12,1.25,1.37,1.75,2.25,3.25,4.75,8.87,10,11.75,13.25,16,17],contrast:1,lightness:6,saturation:97}}};function $(e,t,n){return K.hsl(e,t/100,n/100).hex()}function Ji(e,t){let n=e.colorSpace,r=e.colorSmoothing,i=e.themes[t].ratios,a=new Bi({name:`gray`,colorKeys:e.colors.gray,colorspace:n,ratios:i,smooth:r}),o=new Q({name:`blue`,colorKeys:e.colors.blue,colorspace:n,ratios:i,smooth:r}),s=new Q({name:`cyan`,colorKeys:e.colors.cyan,colorspace:n,ratios:i,smooth:r}),c=new Q({name:`fuchsia`,colorKeys:e.colors.fuchsia,colorspace:n,ratios:i,smooth:r}),l=new Q({name:`green`,colorKeys:e.colors.green,colorspace:n,ratios:i,smooth:r}),u=new Q({name:`lime`,colorKeys:e.colors.lime,colorspace:n,ratios:i,smooth:r}),d=new Q({name:`orange`,colorKeys:e.colors.orange,colorspace:n,ratios:i,smooth:r}),f=new Q({name:`pink`,colorKeys:e.colors.pink,colorspace:n,ratios:i,smooth:r}),p=new Q({name:`purple`,colorKeys:e.colors.purple,colorspace:n,ratios:i,smooth:r}),m={gray:a,red:new Q({name:`red`,colorKeys:e.colors.red,colorspace:n,ratios:i,smooth:r}),orange:d,yellow:new Q({name:`yellow`,colorKeys:e.colors.yellow,colorspace:n,ratios:i,smooth:r}),lime:u,green:l,cyan:s,blue:o,purple:p,fuchsia:c,pink:f};return e.colors.custom&&(m.custom=new Q({name:`custom`,colorKeys:e.colors.custom,colorspace:n,ratios:i,smooth:r})),new Vi({colors:Object.values(m),backgroundColor:m[e.backgroundColor],contrast:e.themes[t].contrast,lightness:e.themes[t].lightness,saturation:e.themes[t].saturation,output:e.output,formula:e.formula}).contrastColors}function Yi(e){let t={};for(let n of Object.keys(e.themes))t[n]=Ji(e,n);return t}function Xi(e){qi.colors.custom=[e];let t=Yi(qi);return Object.fromEntries(Object.entries(t).map(([e,t])=>{let n=t.find(e=>e&&e.name===`custom`),r=Object.fromEntries(n.values.map(({name:e,value:t})=>[e,t]));for(let[e,n]of Object.entries(r)){let i=Ki(n,t[0].background);r[`alpha${e.charAt(0).toUpperCase()+e.slice(1)}`]=Gi(i.h,i.s,i.l,i.a)}return[e,r]}))}return e.generateCustomColors=Xi,e.generateThemesJson=Yi,e.hslToHex=$,e.leonardoConfig=qi,e})({}); \ No newline at end of file diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt index 5851a758f0..d8f81dbbbb 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/CompoundIcons.kt @@ -130,6 +130,9 @@ object CompoundIcons { @Composable fun Collapse(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_collapse) } + @Composable fun CollapseAll(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_collapse_all) + } @Composable fun Company(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_company) } @@ -142,6 +145,9 @@ object CompoundIcons { @Composable fun Copy(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_copy) } + @Composable fun Crop(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_crop) + } @Composable fun DarkMode(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_dark_mode) } @@ -202,6 +208,9 @@ object CompoundIcons { @Composable fun Expand(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_expand) } + @Composable fun ExpandAll(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_expand_all) + } @Composable fun Explore(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_explore) } @@ -229,6 +238,15 @@ object CompoundIcons { @Composable fun Filter(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_filter) } + @Composable fun FlipHorizontal(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_flip_horizontal) + } + @Composable fun FlipVertical(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_flip_vertical) + } + @Composable fun Folder(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_folder) + } @Composable fun Forward(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_forward) } @@ -496,6 +514,12 @@ object CompoundIcons { @Composable fun RotateRight(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_rotate_right) } + @Composable fun Save(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_save) + } + @Composable fun SaveSolid(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_save_solid) + } @Composable fun Search(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_search) } @@ -607,6 +631,9 @@ object CompoundIcons { @Composable fun Unpin(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_unpin) } + @Composable fun Unsave(): ImageVector { + return ImageVector.vectorResource(R.drawable.ic_compound_unsave) + } @Composable fun User(): ImageVector { return ImageVector.vectorResource(R.drawable.ic_compound_user) } @@ -735,10 +762,12 @@ object CompoundIcons { CloudSolid(), Code(), Collapse(), + CollapseAll(), Company(), Compose(), Computer(), Copy(), + Crop(), DarkMode(), Delete(), DevicePasskey(), @@ -759,6 +788,7 @@ object CompoundIcons { ErrorSolid(), ExitFullScreen(), Expand(), + ExpandAll(), Explore(), ExportArchive(), Extensions(), @@ -768,6 +798,9 @@ object CompoundIcons { FileError(), Files(), Filter(), + FlipHorizontal(), + FlipVertical(), + Folder(), Forward(), FullScreen(), Grid(), @@ -857,6 +890,8 @@ object CompoundIcons { Room(), RotateLeft(), RotateRight(), + Save(), + SaveSolid(), Search(), Section(), Send(), @@ -894,6 +929,7 @@ object CompoundIcons { Unknown(), UnknownSolid(), Unpin(), + Unsave(), User(), UserAdd(), UserAddSolid(), @@ -963,10 +999,12 @@ object CompoundIcons { R.drawable.ic_compound_cloud_solid, R.drawable.ic_compound_code, R.drawable.ic_compound_collapse, + R.drawable.ic_compound_collapse_all, R.drawable.ic_compound_company, R.drawable.ic_compound_compose, R.drawable.ic_compound_computer, R.drawable.ic_compound_copy, + R.drawable.ic_compound_crop, R.drawable.ic_compound_dark_mode, R.drawable.ic_compound_delete, R.drawable.ic_compound_device_passkey, @@ -987,6 +1025,7 @@ object CompoundIcons { R.drawable.ic_compound_error_solid, R.drawable.ic_compound_exit_full_screen, R.drawable.ic_compound_expand, + R.drawable.ic_compound_expand_all, R.drawable.ic_compound_explore, R.drawable.ic_compound_export_archive, R.drawable.ic_compound_extensions, @@ -996,6 +1035,9 @@ object CompoundIcons { R.drawable.ic_compound_file_error, R.drawable.ic_compound_files, R.drawable.ic_compound_filter, + R.drawable.ic_compound_flip_horizontal, + R.drawable.ic_compound_flip_vertical, + R.drawable.ic_compound_folder, R.drawable.ic_compound_forward, R.drawable.ic_compound_full_screen, R.drawable.ic_compound_grid, @@ -1085,6 +1127,8 @@ object CompoundIcons { R.drawable.ic_compound_room, R.drawable.ic_compound_rotate_left, R.drawable.ic_compound_rotate_right, + R.drawable.ic_compound_save, + R.drawable.ic_compound_save_solid, R.drawable.ic_compound_search, R.drawable.ic_compound_section, R.drawable.ic_compound_send, @@ -1122,6 +1166,7 @@ object CompoundIcons { R.drawable.ic_compound_unknown, R.drawable.ic_compound_unknown_solid, R.drawable.ic_compound_unpin, + R.drawable.ic_compound_unsave, R.drawable.ic_compound_user, R.drawable.ic_compound_user_add, R.drawable.ic_compound_user_add_solid, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt index f5a54bb7be..6bc6c89a63 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColors.kt @@ -175,6 +175,8 @@ data class SemanticColors( val iconTertiaryAlpha: Color, /** Used to separate core sections of the UI as well as containers */ val separatorPrimary: Color, + /** Secondary shade for separating sections of components or list items */ + val separatorSecondary: Color, /** Accent text colour for plain actions. */ val textActionAccent: Color, /** Default text colour for plain actions. */ diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt index 35a1234854..e9334de0e7 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDark.kt @@ -103,6 +103,7 @@ val compoundColorsDark = SemanticColors( iconTertiary = DarkColorTokens.colorGray800, iconTertiaryAlpha = DarkColorTokens.colorAlphaGray800, separatorPrimary = DarkColorTokens.colorGray400, + separatorSecondary = DarkColorTokens.colorGray300, textActionAccent = DarkColorTokens.colorGreen900, textActionPrimary = DarkColorTokens.colorGray1400, textBadgeAccent = DarkColorTokens.colorGreen1100, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt index 802e3d56b0..a3ef51cff1 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsDarkHc.kt @@ -103,6 +103,7 @@ val compoundColorsHcDark = SemanticColors( iconTertiary = DarkHcColorTokens.colorGray800, iconTertiaryAlpha = DarkHcColorTokens.colorAlphaGray800, separatorPrimary = DarkHcColorTokens.colorGray400, + separatorSecondary = DarkHcColorTokens.colorGray300, textActionAccent = DarkHcColorTokens.colorGreen900, textActionPrimary = DarkHcColorTokens.colorGray1400, textBadgeAccent = DarkHcColorTokens.colorGreen1100, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt index 166f9ddafc..75153cb66b 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLight.kt @@ -103,6 +103,7 @@ val compoundColorsLight = SemanticColors( iconTertiary = LightColorTokens.colorGray800, iconTertiaryAlpha = LightColorTokens.colorAlphaGray800, separatorPrimary = LightColorTokens.colorGray400, + separatorSecondary = LightColorTokens.colorGray300, textActionAccent = LightColorTokens.colorGreen900, textActionPrimary = LightColorTokens.colorGray1400, textBadgeAccent = LightColorTokens.colorGreen1100, diff --git a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt index 8914b41bfc..fa40a2e2ab 100644 --- a/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt +++ b/libraries/compound/src/main/kotlin/io/element/android/compound/tokens/generated/SemanticColorsLightHc.kt @@ -103,6 +103,7 @@ val compoundColorsHcLight = SemanticColors( iconTertiary = LightHcColorTokens.colorGray800, iconTertiaryAlpha = LightHcColorTokens.colorAlphaGray800, separatorPrimary = LightHcColorTokens.colorGray400, + separatorSecondary = LightHcColorTokens.colorGray300, textActionAccent = LightHcColorTokens.colorGreen900, textActionPrimary = LightHcColorTokens.colorGray1400, textBadgeAccent = LightHcColorTokens.colorGreen1100, diff --git a/libraries/compound/src/main/res/drawable/ic_compound_collapse_all.xml b/libraries/compound/src/main/res/drawable/ic_compound_collapse_all.xml new file mode 100644 index 0000000000..7257b7d2c3 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_collapse_all.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_crop.xml b/libraries/compound/src/main/res/drawable/ic_compound_crop.xml new file mode 100644 index 0000000000..c82f5cb686 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_crop.xml @@ -0,0 +1,13 @@ + + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_expand_all.xml b/libraries/compound/src/main/res/drawable/ic_compound_expand_all.xml new file mode 100644 index 0000000000..fcef02880b --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_expand_all.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_flip_horizontal.xml b/libraries/compound/src/main/res/drawable/ic_compound_flip_horizontal.xml new file mode 100644 index 0000000000..90a3a98f44 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_flip_horizontal.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_flip_vertical.xml b/libraries/compound/src/main/res/drawable/ic_compound_flip_vertical.xml new file mode 100644 index 0000000000..430e5eb3fa --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_flip_vertical.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_save.xml b/libraries/compound/src/main/res/drawable/ic_compound_save.xml new file mode 100644 index 0000000000..3bedcc272d --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_save.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_save_solid.xml b/libraries/compound/src/main/res/drawable/ic_compound_save_solid.xml new file mode 100644 index 0000000000..5d453834c7 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_save_solid.xml @@ -0,0 +1,9 @@ + + + diff --git a/libraries/compound/src/main/res/drawable/ic_compound_unsave.xml b/libraries/compound/src/main/res/drawable/ic_compound_unsave.xml new file mode 100644 index 0000000000..0dfddcfe46 --- /dev/null +++ b/libraries/compound/src/main/res/drawable/ic_compound_unsave.xml @@ -0,0 +1,13 @@ + + + + diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/AvatarColorsTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/AvatarColorsTest.kt index 01c3e787cf..895247f12f 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/AvatarColorsTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/AvatarColorsTest.kt @@ -8,19 +8,17 @@ package io.element.android.compound.screenshot -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.theme.AvatarColorsPreviewDark import io.element.android.compound.theme.AvatarColorsPreviewLight +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class AvatarColorsTest { +class AvatarColorsTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "xxhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundIconTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundIconTest.kt index 3e8ce06cdb..97926fc291 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundIconTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundIconTest.kt @@ -11,7 +11,6 @@ package io.element.android.compound.screenshot import androidx.compose.foundation.layout.ColumnScope import androidx.compose.material3.Icon import androidx.compose.runtime.Composable -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.previews.IconsCompoundPreviewDark import io.element.android.compound.previews.IconsCompoundPreviewLight @@ -21,15 +20,14 @@ import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.Theme import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.collections.immutable.toImmutableList import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class CompoundIconTest { +class CompoundIconTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "w1024dp-h2048dp") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundTypographyTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundTypographyTest.kt index c4822f680e..ec27acd836 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundTypographyTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/CompoundTypographyTest.kt @@ -8,18 +8,16 @@ package io.element.android.compound.screenshot -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.previews.CompoundTypographyPreview import io.element.android.compound.screenshot.utils.screenshotFile +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class CompoundTypographyTest { +class CompoundTypographyTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "h2048dp-xxhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/ForcedDarkElementThemeTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/ForcedDarkElementThemeTest.kt index 74e6f3010d..5f858b8622 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/ForcedDarkElementThemeTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/ForcedDarkElementThemeTest.kt @@ -18,20 +18,18 @@ import androidx.compose.material3.Text import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.colors.SemanticColorsLightDark import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ForcedDarkElementTheme +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class ForcedDarkElementThemeTest { +class ForcedDarkElementThemeTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "xxhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/LegacyColorsTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/LegacyColorsTest.kt index deb27c6519..c0c3d11555 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/LegacyColorsTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/LegacyColorsTest.kt @@ -18,7 +18,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.previews.ColorPreview import io.element.android.compound.screenshot.utils.screenshotFile @@ -26,14 +25,13 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.LinkColor import io.element.android.compound.theme.SnackBarLabelColorDark import io.element.android.compound.theme.SnackBarLabelColorLight +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class LegacyColorsTest { +class LegacyColorsTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "xxhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialColorSchemeTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialColorSchemeTest.kt index 282ca0e69a..2e1368ff54 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialColorSchemeTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialColorSchemeTest.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.theme.ColorsSchemeDarkHcPreview @@ -26,14 +25,13 @@ import io.element.android.compound.theme.ColorsSchemeDarkPreview import io.element.android.compound.theme.ColorsSchemeLightHcPreview import io.element.android.compound.theme.ColorsSchemeLightPreview import io.element.android.compound.theme.ElementTheme +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class MaterialColorSchemeTest { +class MaterialColorSchemeTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "h2048dp-xhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTextTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTextTest.kt index 2aaeed43a5..4d21e77aed 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTextTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTextTest.kt @@ -8,18 +8,16 @@ package io.element.android.compound.screenshot -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.theme.MaterialTextPreview +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class MaterialTextTest { +class MaterialTextTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "w480dp-h1200dp-xxhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTypographyTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTypographyTest.kt index 3d8256e2af..3c07ff48f5 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTypographyTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialTypographyTest.kt @@ -8,18 +8,16 @@ package io.element.android.compound.screenshot -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.previews.TypographyPreview import io.element.android.compound.screenshot.utils.screenshotFile +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class MaterialTypographyTest { +class MaterialTypographyTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "h2048dp-xxhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialYouThemeTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialYouThemeTest.kt index dcbbc9d4ac..2f1abc55f5 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialYouThemeTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/MaterialYouThemeTest.kt @@ -19,20 +19,18 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.previews.ColorsSchemePreview import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.Theme +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class MaterialYouThemeTest { +class MaterialYouThemeTest : RobolectricTest() { @Test @Config(sdk = [35], qualifiers = "h2048dp-xhdpi") fun screenshots() { diff --git a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/SemanticColorsTest.kt b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/SemanticColorsTest.kt index f36d0d2ee5..95e34fb3d9 100644 --- a/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/SemanticColorsTest.kt +++ b/libraries/compound/src/test/kotlin/io/element/android/compound/screenshot/SemanticColorsTest.kt @@ -8,21 +8,19 @@ package io.element.android.compound.screenshot -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.captureRoboImage import io.element.android.compound.previews.CompoundSemanticColorsDark import io.element.android.compound.previews.CompoundSemanticColorsDarkHc import io.element.android.compound.previews.CompoundSemanticColorsLight import io.element.android.compound.previews.CompoundSemanticColorsLightHc import io.element.android.compound.screenshot.utils.screenshotFile +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode -@RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) -class SemanticColorsTest { +class SemanticColorsTest : RobolectricTest() { @Config(sdk = [35], qualifiers = "h2000dp-xhdpi") @Test fun screenshots() { diff --git a/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterFrTest.kt b/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterFrTest.kt index b4800729d5..dfea6adc46 100644 --- a/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterFrTest.kt +++ b/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterFrTest.kt @@ -9,17 +9,15 @@ package io.element.android.libraries.dateformatter.impl import android.os.Build -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.libraries.dateformatter.api.DateFormatterMode +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import kotlin.time.Instant -@RunWith(AndroidJUnit4::class) @Config(qualifiers = "fr", sdk = [Build.VERSION_CODES.TIRAMISU]) -class DefaultDateFormatterFrTest { +class DefaultDateFormatterFrTest : RobolectricTest() { @Test fun `test null`() { val now = "1980-04-06T18:35:24.00Z" diff --git a/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterTest.kt b/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterTest.kt index 94b6fe983e..f761d833ab 100644 --- a/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterTest.kt +++ b/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDateFormatterTest.kt @@ -9,17 +9,15 @@ package io.element.android.libraries.dateformatter.impl import android.os.Build -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.libraries.dateformatter.api.DateFormatterMode +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import kotlin.time.Instant -@RunWith(AndroidJUnit4::class) @Config(qualifiers = "en", sdk = [Build.VERSION_CODES.TIRAMISU]) -class DefaultDateFormatterTest { +class DefaultDateFormatterTest : RobolectricTest() { @Test fun `test null`() { val now = "1980-04-06T18:35:24.00Z" diff --git a/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDurationFormatterTest.kt b/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDurationFormatterTest.kt index 3fee5dbb0d..6b6fbbb2c1 100644 --- a/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDurationFormatterTest.kt +++ b/libraries/dateformatter/impl/src/test/kotlin/io/element/android/libraries/dateformatter/impl/DefaultDurationFormatterTest.kt @@ -8,10 +8,9 @@ package io.element.android.libraries.dateformatter.impl import android.os.Build -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import java.util.Locale import kotlin.time.Duration.Companion.hours @@ -19,9 +18,8 @@ import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds -@RunWith(AndroidJUnit4::class) @Config(qualifiers = "en", sdk = [Build.VERSION_CODES.TIRAMISU]) -class DefaultDurationFormatterTest { +class DefaultDurationFormatterTest : RobolectricTest() { private fun createDurationFormatter(): DefaultDurationFormatter { return DefaultDurationFormatter( localeChangeObserver = {}, diff --git a/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt b/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt index 7f563ddd7f..a6502aabf1 100644 --- a/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt +++ b/libraries/deeplink/impl/src/test/kotlin/io/element/android/libraries/deeplink/impl/DefaultDeeplinkParserTest.kt @@ -21,12 +21,10 @@ 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.tests.testutils.assertThrowsInDebug +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultDeeplinkParserTest { +class DefaultDeeplinkParserTest : RobolectricTest() { companion object { const val A_URI = "elementx://open/@alice:server.org" diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt index a051fd4c80..3bbd3c12a7 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.unit.dp @@ -37,13 +38,18 @@ private const val MAX_COUNT_STRING = "+$MAX_COUNT" * @param count The number to display. If the number is greater than [MAX_COUNT], the counter will display [MAX_COUNT_STRING]. * If the number is less than 1, the counter will not be displayed. * @param modifier The modifier to apply to this layout. + * @param containerColor The background color of the counter. When null, uses [isCritical] to pick a default. + * @param contentColor The text color inside the counter. When null, uses [textOnSolidPrimary]. * @param textStyle The style to apply to the text inside the counter. * @param isCritical If true, the counter will use a critical color scheme, otherwise it will use an accent color scheme. + * Only used when [containerColor] is null. */ @Composable fun CounterAtom( count: Int, modifier: Modifier = Modifier, + containerColor: Color? = null, + contentColor: Color? = null, textStyle: TextStyle = CounterAtomDefaults.textStyle, isCritical: Boolean = false, ) { @@ -65,7 +71,7 @@ fun CounterAtom( .size(squareSize.toDp() + 1.dp) .clip(CircleShape) .background( - if (isCritical) { + containerColor ?: if (isCritical) { ElementTheme.colors.iconCriticalPrimary } else { ElementTheme.colors.iconAccentPrimary @@ -76,7 +82,7 @@ fun CounterAtom( modifier = Modifier.align(Alignment.Center), text = countAsText, style = textStyle, - color = ElementTheme.colors.textOnSolidPrimary, + color = contentColor ?: ElementTheme.colors.textOnSolidPrimary, ) } } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/UnreadIndicatorAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/UnreadIndicatorAtom.kt index d2db3aec8e..bdf039edb8 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/UnreadIndicatorAtom.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/UnreadIndicatorAtom.kt @@ -8,8 +8,11 @@ package io.element.android.libraries.designsystem.atomic.atoms +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable @@ -29,19 +32,36 @@ import io.element.android.libraries.designsystem.theme.unreadIndicator fun UnreadIndicatorAtom( modifier: Modifier = Modifier, size: Dp = 12.dp, + count: Long? = null, color: Color = ElementTheme.colors.unreadIndicator, isVisible: Boolean = true, contentDescription: String? = null, + border: BorderStroke? = null, ) { - Box( - modifier = modifier - .semantics { - contentDescription?.let { this.contentDescription = it } - } - .size(size) - .clip(CircleShape) - .background(if (isVisible) color else Color.Transparent) - ) + when { + !isVisible -> Spacer(modifier = modifier.size(size)) + count != null && count >= 1 -> CounterAtom( + count = count.toInt(), + modifier = modifier + .semantics { + contentDescription?.let { this.contentDescription = it } + } + .then(if (border != null) Modifier.border(border, CircleShape) else Modifier), + containerColor = color, + contentColor = ElementTheme.colors.bgCanvasDefault, + textStyle = ElementTheme.typography.fontBodySmMedium, + ) + else -> Box( + modifier = modifier + .semantics { + contentDescription?.let { this.contentDescription = it } + } + .size(size) + .clip(CircleShape) + .background(color) + .then(if (border != null) Modifier.border(border, CircleShape) else Modifier), + ) + } } @PreviewsDayNight diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt index 9c3930ac64..284d583de8 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt @@ -17,7 +17,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.datasource.LoremIpsum @@ -39,7 +40,10 @@ fun SimpleModalBottomSheet( ModalBottomSheet( onDismissRequest = onDismiss, modifier = modifier, - sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), + ), scrollable = false, ) { Column( @@ -61,7 +65,7 @@ fun SimpleModalBottomSheet( @PreviewsDayNight @Composable -internal fun SimpleModalBottomSheetPreview() = ElementPreview { +internal fun SimpleModalBottomSheetPreview() = ElementPreview(fillMaxSize = true) { SimpleModalBottomSheet(title = "A title", onDismiss = {}) { Text( text = LoremIpsum(20).values.first(), diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/organisms/InfoListOrganism.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualList.kt similarity index 71% rename from libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/organisms/InfoListOrganism.kt rename to libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualList.kt index f52ee2512f..0b5e63dcbe 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/organisms/InfoListOrganism.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualList.kt @@ -6,25 +6,19 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.designsystem.atomic.organisms +package io.element.android.libraries.designsystem.components.visuallist -import androidx.annotation.DrawableRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.size -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.LocalTextStyle import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme -import io.element.android.libraries.designsystem.atomic.molecules.InfoListItemMolecule -import io.element.android.libraries.designsystem.atomic.molecules.InfoListItemPosition import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon @@ -32,14 +26,17 @@ import io.element.android.libraries.designsystem.theme.components.Text import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +/** + * Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2001-140 + */ @Composable -fun InfoListOrganism( - items: ImmutableList, +fun VisualList( + items: ImmutableList, modifier: Modifier = Modifier, backgroundColor: Color = ElementTheme.colors.bgSubtleSecondary, - iconTint: Color = LocalContentColor.current, + iconTint: Color = ElementTheme.colors.iconSecondary, iconSize: Dp = 20.dp, - textStyle: TextStyle = LocalTextStyle.current, + textStyle: TextStyle = ElementTheme.typography.fontBodyMdMedium, textColor: Color = ElementTheme.colors.textPrimary, verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(4.dp), ) { @@ -49,12 +46,12 @@ fun InfoListOrganism( ) { for ((index, item) in items.withIndex()) { val position = when { - items.size == 1 -> InfoListItemPosition.Single - index == 0 -> InfoListItemPosition.Top - index == items.size - 1 -> InfoListItemPosition.Bottom - else -> InfoListItemPosition.Middle + items.size == 1 -> VisualListItemPosition.Single + index == 0 -> VisualListItemPosition.Top + index == items.size - 1 -> VisualListItemPosition.Bottom + else -> VisualListItemPosition.Middle } - InfoListItemMolecule( + VisualListItem( message = { if (item.message is AnnotatedString) { Text( @@ -96,22 +93,15 @@ fun InfoListOrganism( } } -data class InfoListItem( - val message: CharSequence, - @DrawableRes val iconId: Int? = null, - val iconVector: ImageVector? = null, - val iconComposable: @Composable () -> Unit = {}, -) - @PreviewsDayNight @Composable -internal fun InfoListOrganismPreview() = ElementPreview { +internal fun VisualListPreview() = ElementPreview { val items = persistentListOf( - InfoListItem(message = "A top item"), - InfoListItem(message = "A middle item"), - InfoListItem(message = "A bottom item"), + VisualListItemData(message = "A top item"), + VisualListItemData(message = "A middle item"), + VisualListItemData(message = "A bottom item"), ) - InfoListOrganism( + VisualList( items = items, ) } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/InfoListItemMolecule.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualListItem.kt similarity index 74% rename from libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/InfoListItemMolecule.kt rename to libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualListItem.kt index 46d8029c89..276fb1522e 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/InfoListItemMolecule.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualListItem.kt @@ -6,7 +6,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.designsystem.atomic.molecules +package io.element.android.libraries.designsystem.components.visuallist import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -27,10 +27,13 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text +/** + * Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2001-159 + */ @Composable -fun InfoListItemMolecule( +fun VisualListItem( message: @Composable () -> Unit, - position: InfoListItemPosition, + position: VisualListItemPosition, backgroundColor: Color, modifier: Modifier = Modifier, icon: @Composable () -> Unit = {}, @@ -38,10 +41,10 @@ fun InfoListItemMolecule( val radius = 14.dp val backgroundShape = remember(position) { when (position) { - InfoListItemPosition.Single -> RoundedCornerShape(radius) - InfoListItemPosition.Top -> RoundedCornerShape(topStart = radius, topEnd = radius) - InfoListItemPosition.Middle -> RoundedCornerShape(0.dp) - InfoListItemPosition.Bottom -> RoundedCornerShape(bottomStart = radius, bottomEnd = radius) + VisualListItemPosition.Single -> RoundedCornerShape(radius) + VisualListItemPosition.Top -> RoundedCornerShape(topStart = radius, topEnd = radius) + VisualListItemPosition.Middle -> RoundedCornerShape(0.dp) + VisualListItemPosition.Bottom -> RoundedCornerShape(bottomStart = radius, bottomEnd = radius) } } Row( @@ -61,42 +64,42 @@ fun InfoListItemMolecule( @PreviewsDayNight @Composable -internal fun InfoListItemMoleculePreview() { +internal fun VisualListItemPreview() { ElementPreview { val color = ElementTheme.colors.bgSubtleSecondary Column( modifier = Modifier.padding(10.dp), verticalArrangement = Arrangement.spacedBy(8.dp), ) { - InfoListItemMolecule( + VisualListItem( message = { Text("A single item") }, icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) }, - position = InfoListItemPosition.Single, + position = VisualListItemPosition.Single, backgroundColor = color, ) - InfoListItemMolecule( + VisualListItem( message = { Text("A top item") }, icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) }, - position = InfoListItemPosition.Top, + position = VisualListItemPosition.Top, backgroundColor = color, ) - InfoListItemMolecule( + VisualListItem( message = { Text("A middle item") }, icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) }, - position = InfoListItemPosition.Middle, + position = VisualListItemPosition.Middle, backgroundColor = color, ) - InfoListItemMolecule( + VisualListItem( message = { Text("A bottom item") }, icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) }, - position = InfoListItemPosition.Bottom, + position = VisualListItemPosition.Bottom, backgroundColor = color, ) } } } -enum class InfoListItemPosition { +enum class VisualListItemPosition { Top, Middle, Bottom, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualListItemData.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualListItemData.kt new file mode 100644 index 0000000000..ace971ac61 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/visuallist/VisualListItemData.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.components.visuallist + +import androidx.annotation.DrawableRes +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.vector.ImageVector + +data class VisualListItemData( + val message: CharSequence, + @DrawableRes val iconId: Int? = null, + val iconVector: ImageVector? = null, + val iconComposable: @Composable () -> Unit = {}, +) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/BringIntoViewOnImeVisible.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/BringIntoViewOnImeVisible.kt new file mode 100644 index 0000000000..155172c96f --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/BringIntoViewOnImeVisible.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.modifiers + +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.isImeVisible +import androidx.compose.foundation.relocation.BringIntoViewRequester +import androidx.compose.foundation.relocation.bringIntoViewRequester +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged +import kotlinx.coroutines.delay +import kotlin.time.Duration.Companion.milliseconds + +/** + * Keeps the focused field visible above the keyboard. Intended for a field inside a scrollable + * container: the field is never clipped by a pinned footer, but the IME is shown only after focus + * arrives, so we re-request bringIntoView once it is visible to scroll the field back into the + * reduced viewport. + */ +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun Modifier.bringIntoViewOnImeVisible(): Modifier { + val bringIntoViewRequester = remember { BringIntoViewRequester() } + var isFocused by remember { mutableStateOf(false) } + val isImeVisible = WindowInsets.isImeVisible + LaunchedEffect(isImeVisible, isFocused) { + if (isImeVisible && isFocused) { + // Delay to ensure the keyboard is fully shown before scrolling the field into view. + delay(100.milliseconds) + bringIntoViewRequester.bringIntoView() + } + } + return this + .bringIntoViewRequester(bringIntoViewRequester) + .onFocusChanged { isFocused = it.isFocused } +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/ElementPreview.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/ElementPreview.kt index e4030a77ea..693b3f5b79 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/ElementPreview.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/ElementPreview.kt @@ -10,8 +10,13 @@ package io.element.android.libraries.designsystem.preview import androidx.annotation.DrawableRes import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.movableContentOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.core.content.res.ResourcesCompat import coil3.annotation.ExperimentalCoilApi @@ -29,6 +34,7 @@ import io.element.android.libraries.designsystem.utils.CommonDrawables fun ElementPreview( theme: Theme = if (isSystemInDarkTheme()) Theme.Dark else Theme.Light, showBackground: Boolean = true, + fillMaxSize: Boolean = false, @DrawableRes drawableFallbackForImages: Int = CommonDrawables.sample_background, content: @Composable () -> Unit @@ -40,11 +46,21 @@ fun ElementPreview( } ) { ElementTheme(theme = theme) { + val movableContent = remember { movableContentOf { content() } } if (showBackground) { // If we have a proper contentColor applied we need a Surface instead of a Box - Surface(content = content) + Surface( + modifier = if (fillMaxSize) Modifier.fillMaxSize() else Modifier, + content = movableContent, + ) } else { - content() + if (fillMaxSize) { + Box(modifier = Modifier.fillMaxSize()) { + movableContent() + } + } else { + movableContent() + } } } } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/PreviewWithLargeHeight.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/PreviewWithLargeHeight.kt index 163ee21590..8d745ec0e7 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/PreviewWithLargeHeight.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/PreviewWithLargeHeight.kt @@ -16,3 +16,6 @@ import androidx.compose.ui.tooling.preview.Preview */ @Preview(heightDp = 1000) annotation class PreviewWithLargeHeight + +@Preview(heightDp = 1600) +annotation class PreviewWithExtraLargeHeight diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/SheetState.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/SheetState.kt index 7e687e9b89..8d03cfb7a5 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/SheetState.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/preview/SheetState.kt @@ -11,12 +11,10 @@ package io.element.android.libraries.designsystem.preview import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SheetState import androidx.compose.material3.SheetValue -import androidx.compose.runtime.Composable @OptIn(ExperimentalMaterial3Api::class) -@Composable fun sheetStateForPreview() = SheetState( - skipPartiallyExpanded = true, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), positionalThreshold = { 0.5f }, velocityThreshold = { 400f }, initialValue = SheetValue.Expanded, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalDivider.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalDivider.kt index b4c7eddf31..0a3d717b09 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalDivider.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/HorizontalDivider.kt @@ -10,7 +10,6 @@ package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding -import androidx.compose.material3.DividerDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -18,6 +17,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.PreviewGroup @@ -25,7 +25,7 @@ import io.element.android.libraries.designsystem.preview.PreviewGroup fun HorizontalDivider( modifier: Modifier = Modifier, thickness: Dp = ElementDividerDefaults.thickness, - color: Color = DividerDefaults.color, + color: Color = ElementDividerDefaults.color, ) { androidx.compose.material3.HorizontalDivider( modifier = modifier, @@ -35,7 +35,9 @@ fun HorizontalDivider( } object ElementDividerDefaults { - val thickness = 0.5.dp + val thickness = 1.dp + val color + @Composable get() = ElementTheme.colors.separatorSecondary } @Preview(group = PreviewGroup.Dividers) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt index ec5f7ce456..6cb49a6218 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt @@ -21,8 +21,9 @@ import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SheetState +import androidx.compose.material3.SheetValue import androidx.compose.material3.contentColorFor -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.movableContentOf import androidx.compose.runtime.remember @@ -57,7 +58,9 @@ fun ModalBottomSheet( onDismissRequest: () -> Unit, scrollable: Boolean, modifier: Modifier = Modifier, - sheetState: SheetState = rememberModalBottomSheetState(), + sheetState: SheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + ), shape: Shape = BottomSheetDefaults.ExpandedShape, containerColor: Color = MaterialTheme.colorScheme.surface, contentColor: Color = contentColorFor(containerColor), diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/PasswordVisibilityToggle.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/PasswordVisibilityToggle.kt new file mode 100644 index 0000000000..9154ec6292 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/PasswordVisibilityToggle.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.theme.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.libraries.ui.strings.CommonStrings + +/** + * Show/hide toggle for a password [TextField], intended for its `trailingIcon` slot. + * Shared so every password field reveals plaintext the same way and announces the + * same accessibility labels. + */ +@Composable +fun PasswordVisibilityToggle( + visible: Boolean, + onToggle: () -> Unit, + modifier: Modifier = Modifier, +) { + Box(modifier.clickable(onClick = onToggle)) { + Icon( + imageVector = if (visible) CompoundIcons.VisibilityOn() else CompoundIcons.VisibilityOff(), + contentDescription = stringResource( + if (visible) CommonStrings.a11y_hide_password else CommonStrings.a11y_show_password + ), + ) + } +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcher.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcher.kt index 56bb070228..566c92d5cf 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcher.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcher.kt @@ -18,39 +18,35 @@ import androidx.compose.runtime.remember import androidx.compose.ui.res.stringResource import io.element.android.libraries.designsystem.theme.components.Snackbar import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.isActive -import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow /** * A global dispatcher of [SnackbarMessage] to be displayed in [Snackbar] via a [SnackbarHostState]. + * + * The current head of the queue is exposed as a [MutableStateFlow] so that every collector — including + * hosts that subscribe *after* a message was posted (e.g. a screen recomposing as a flow pops back to + * it) — observes the current message. An earlier mutex-gated implementation delivered each message to + * whichever single collector happened to be parked on the lock, which could starve the host that was + * actually on screen, dropping the snackbar. */ class SnackbarDispatcher { - private val queueMutex = Mutex() private val snackBarMessageQueue = ArrayDeque() - val snackbarMessage: Flow = flow { - while (currentCoroutineContext().isActive) { - queueMutex.lock() - emit(snackBarMessageQueue.firstOrNull()) - } - } + private val currentMessage = MutableStateFlow(null) + val snackbarMessage: Flow = currentMessage.asStateFlow() + + @Synchronized fun post(message: SnackbarMessage) { - if (snackBarMessageQueue.isEmpty()) { - snackBarMessageQueue.add(message) - if (queueMutex.isLocked) queueMutex.unlock() - } else { - snackBarMessageQueue.add(message) - } + snackBarMessageQueue.add(message) + currentMessage.value = snackBarMessageQueue.firstOrNull() } + @Synchronized fun clear() { - if (snackBarMessageQueue.isNotEmpty()) { - snackBarMessageQueue.removeFirstOrNull() - if (queueMutex.isLocked) queueMutex.unlock() - } + snackBarMessageQueue.removeFirstOrNull() + currentMessage.value = snackBarMessageQueue.firstOrNull() } } diff --git a/libraries/designsystem/src/main/res/drawable-night/sample_map.png b/libraries/designsystem/src/main/res/drawable-night/sample_map.png new file mode 100644 index 0000000000..7c58760c15 Binary files /dev/null and b/libraries/designsystem/src/main/res/drawable-night/sample_map.png differ diff --git a/libraries/designsystem/src/main/res/drawable/sample_map.png b/libraries/designsystem/src/main/res/drawable/sample_map.png new file mode 100644 index 0000000000..9bda2e15f2 Binary files /dev/null and b/libraries/designsystem/src/main/res/drawable/sample_map.png differ diff --git a/libraries/designsystem/src/test/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcherTest.kt b/libraries/designsystem/src/test/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcherTest.kt index 91c32b1da0..fe17aa0b6c 100644 --- a/libraries/designsystem/src/test/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcherTest.kt +++ b/libraries/designsystem/src/test/kotlin/io/element/android/libraries/designsystem/utils/snackbar/SnackbarDispatcherTest.kt @@ -54,6 +54,27 @@ class SnackbarDispatcherTest { } } + @Test + fun `a host that subscribes after a message is posted still receives it`() = runTest { + val snackbarDispatcher = SnackbarDispatcher() + val message = SnackbarMessage(0) + // A first host is already collecting (mirrors a background screen still subscribed). + snackbarDispatcher.snackbarMessage.test { + assertThat(awaitItem()).isNull() + snackbarDispatcher.post(message) + assertThat(awaitItem()).isEqualTo(message) + + // A second host subscribes only afterwards — e.g. the screen a flow pops back to once the + // message has already been posted. It must observe the current message rather than being + // starved waiting for the next post (regression: an earlier mutex-gated implementation + // delivered each post to a single parked collector, dropping the snackbar for any host + // that subscribed later). + snackbarDispatcher.snackbarMessage.test { + assertThat(awaitItem()).isEqualTo(message) + } + } + } + @Test fun `given 2 message emissions, the next message is displayed only after a call to clear`() = runTest { val snackbarDispatcher = SnackbarDispatcher() diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt index c8afba3603..1311c524e4 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt @@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageT import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent @@ -104,6 +105,9 @@ class DefaultPinnedMessagesBannerFormatter( is OtherMessageType -> { messageType.body } + is GalleryMessageType -> { + messageType.body.prefixWith(CommonStrings.common_gallery) + } is NoticeMessageType -> { messageType.body } diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt index e8a462da16..1c5cd72977 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInviteContent import io.element.android.libraries.matrix.api.timeline.item.event.LiveLocationContent @@ -167,6 +168,9 @@ class DefaultRoomLatestEventFormatter( is OtherMessageType -> { messageType.body } + is GalleryMessageType -> { + messageType.body.prefixWith(sp.getString(CommonStrings.common_gallery)) + } is NoticeMessageType -> { messageType.body } diff --git a/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml b/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml index e14813bb69..196e6ec3e1 100644 --- a/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml +++ b/libraries/eventformatter/impl/src/main/res/values-ru/translations.xml @@ -27,7 +27,7 @@ "%1$s принял(а) приглашение" "Вы приняли приглашение" "Вы пригласили %1$s" - "%1$s пригласил(а) вас" + "%1$s пригласил(а) Вас" "%1$s присоединился(ась)" "Вы присоединились к комнате" "%1$s хочет присоединиться" @@ -47,8 +47,8 @@ "Вы удалили название" "%1$s не внес(ла) изменений" "Вы не внесли изменений" - "%1$s изменил(а) закрепленные сообщения" - "Вы изменили закрепленные сообщения" + "%1$s изменил(а) закреплённые сообщения" + "Вы изменили закреплённые сообщения" "%1$s закрепил(а) сообщение" "Вы закрепили сообщение" "%1$s открепил(а) сообщение" diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt index 38334afad5..198da2bf7d 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt @@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventTimeline import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange @@ -50,16 +51,14 @@ import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.toolbox.impl.strings.AndroidStringProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config @Suppress("LargeClass") -@RunWith(RobolectricTestRunner::class) -class DefaultPinnedMessagesBannerFormatterTest { +class DefaultPinnedMessagesBannerFormatterTest : RobolectricTest() { private lateinit var context: Context private lateinit var fakeMatrixClient: FakeMatrixClient private lateinit var formatter: DefaultPinnedMessagesBannerFormatter @@ -143,6 +142,7 @@ class DefaultPinnedMessagesBannerFormatterTest { AudioMessageType(body, null, null, MediaSource("url"), null), VoiceMessageType(body, null, null, MediaSource("url"), null, null), ImageMessageType(body, null, null, MediaSource("url"), null), + GalleryMessageType(body, null, emptyList()), StickerMessageType(body, null, null, MediaSource("url"), null), FileMessageType(body, null, null, MediaSource("url"), null), LocationMessageType(body, "geo:1,2", null, null), @@ -165,6 +165,7 @@ class DefaultPinnedMessagesBannerFormatterTest { is VideoMessageType, is AudioMessageType, is ImageMessageType, + is GalleryMessageType, is StickerMessageType, is FileMessageType, is LocationMessageType -> AnnotatedString::class.java @@ -183,6 +184,7 @@ class DefaultPinnedMessagesBannerFormatterTest { is AudioMessageType -> "Audio: Shared body" is VoiceMessageType -> "Voice message" is ImageMessageType -> "Image: Shared body" + is GalleryMessageType -> "Gallery: Shared body" is StickerMessageType -> "Sticker: Shared body" is FileMessageType -> "File: Shared body" is LocationMessageType -> "Shared location: Shared body" diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt index 2e55fb0999..791a363f77 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange @@ -51,16 +52,14 @@ import io.element.android.libraries.matrix.test.timeline.aProfileDetails import io.element.android.libraries.matrix.test.timeline.aStickerContent import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembershipContent import io.element.android.services.toolbox.impl.strings.AndroidStringProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config @Suppress("LargeClass") -@RunWith(RobolectricTestRunner::class) -class DefaultRoomLatestEventFormatterTest { +class DefaultRoomLatestEventFormatterTest : RobolectricTest() { private lateinit var context: Context private lateinit var fakeMatrixClient: FakeMatrixClient private lateinit var formatter: DefaultRoomLatestEventFormatter @@ -197,6 +196,7 @@ class DefaultRoomLatestEventFormatterTest { AudioMessageType(body, null, null, MediaSource("url"), null), VoiceMessageType(body, null, null, MediaSource("url"), null, null), ImageMessageType(body, null, null, MediaSource("url"), null), + GalleryMessageType(body, null, emptyList()), StickerMessageType(body, null, null, MediaSource("url"), null), FileMessageType(body, null, null, MediaSource("url"), null), LocationMessageType(body, "geo:1,2", null, null), @@ -229,6 +229,7 @@ class DefaultRoomLatestEventFormatterTest { is AudioMessageType -> "Audio: Shared body" is VoiceMessageType -> "Voice message" is ImageMessageType -> "Image: Shared body" + is GalleryMessageType -> "Gallery: Shared body" is StickerMessageType -> "Sticker: Shared body" is FileMessageType -> "File: Shared body" is LocationMessageType -> "Shared location" @@ -249,6 +250,7 @@ class DefaultRoomLatestEventFormatterTest { is TextMessageType -> false is NoticeMessageType -> false is OtherMessageType -> false + is GalleryMessageType -> true } if (shouldCreateAnnotatedString) { assertWithMessage("$type doesn't produce an AnnotatedString") @@ -266,6 +268,7 @@ class DefaultRoomLatestEventFormatterTest { is AudioMessageType -> "$expectedPrefix: Audio: Shared body" is VoiceMessageType -> "$expectedPrefix: Voice message" is ImageMessageType -> "$expectedPrefix: Image: Shared body" + is GalleryMessageType -> "$expectedPrefix: Gallery: Shared body" is StickerMessageType -> "$expectedPrefix: Sticker: Shared body" is FileMessageType -> "$expectedPrefix: File: Shared body" is LocationMessageType -> "$expectedPrefix: Shared location" @@ -286,6 +289,7 @@ class DefaultRoomLatestEventFormatterTest { is TextMessageType -> true is NoticeMessageType -> true is OtherMessageType -> true + is GalleryMessageType -> true } if (shouldCreateAnnotatedString) { assertWithMessage("$type doesn't produce an AnnotatedString") diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt index dca34db3cc..cd3a8df349 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt @@ -15,17 +15,14 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID_3 import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.services.toolbox.impl.strings.AndroidStringProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -import kotlin.toString @Suppress("LargeClass") -@RunWith(RobolectricTestRunner::class) -class RtcNotificationContentFormatterTest { +class RtcNotificationContentFormatterTest : RobolectricTest() { private lateinit var context: Context private lateinit var fakeMatrixClient: FakeMatrixClient private lateinit var formatter: RtcNotificationContentFormatter diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt index 097df99800..29c7be3a3d 100644 --- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt @@ -108,10 +108,11 @@ enum class FeatureFlags( defaultValue = { true }, isFinished = false, ), - FloatingDateBadge( - key = "feature.floating_date_badge", - title = "Display sticky date headers in the timeline", - description = "When scrolling, a sticky date badge will be displayed so you can easily know on which date the messages you're seeing were sent.", + JumpToUnread( + key = "feature.jump_to_unread", + title = "Jump to unread messages", + description = "Show a button to jump to the read marker, plus a count badge on the scroll-to-bottom button " + + "when new messages arrive while scrolled away.", defaultValue = { false }, isFinished = false, ), @@ -137,4 +138,18 @@ enum class FeatureFlags( defaultValue = { false }, isFinished = false, ), + UnreadIndicatorCount( + key = "feature.unread_indicator_count", + title = "Unread indicator count", + description = "Show the number of unread messages on the unread indicator in the room list.", + defaultValue = { false }, + isFinished = false, + ), + SendGalleryMessages( + key = "feature.send_gallery_messages", + title = "Send gallery messages", + description = "Allow sending multiple media items in a single message.", + defaultValue = { false }, + isFinished = false, + ), } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index 836459f8c7..6546e4c41a 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.api.media.MediaPreviewService import io.element.android.libraries.matrix.api.notification.NotificationService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.oauth.AccountManagementAction +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.matrix.api.pusher.PushersService import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -53,6 +54,7 @@ import java.util.Optional interface MatrixClient { val sessionId: SessionId val deviceId: DeviceId + val sessionPaths: SessionPaths val userProfile: StateFlow val roomListService: RoomListService val spaceService: SpaceService @@ -201,6 +203,12 @@ interface MatrixClient { */ suspend fun markRoomAsFullyRead(roomId: RoomId, eventId: EventId): Result + /** + * Mark all joined rooms as read by sending public, private and fully-read receipts + * on each room's latest event. Per-room errors are logged and skipped by the SDK. + */ + suspend fun markAllRoomsAsRead(): Result + /** * Check if linking a new device using QrCode is supported by the server. */ diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/GetDatabaseSizesUseCase.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/GetDatabaseSizesUseCase.kt index ab11374116..fde02fb2c6 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/GetDatabaseSizesUseCase.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/GetDatabaseSizesUseCase.kt @@ -10,5 +10,5 @@ package io.element.android.libraries.matrix.api.analytics import io.element.android.libraries.matrix.api.core.SessionId fun interface GetDatabaseSizesUseCase { - suspend operator fun invoke(sessionId: SessionId): Result + operator fun invoke(sessionId: SessionId): Result } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt index 333cfb709b..f82cdc1969 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt @@ -24,9 +24,15 @@ interface EncryptionService { suspend fun enableBackups(): Result /** - * Enable recovery. Observe enableProgressStateFlow to get progress and recovery key. + * Enable recovery and return the SDK-generated recovery key on success. + * Observe [enableRecoveryProgressStateFlow] for in-progress UI updates. + * + * @param waitForBackupsToUpload when true, suspends until existing room keys finish uploading. + * @param passphrase optional user-supplied passphrase. When set, the SDK derives the + * secret-storage key from it instead of a random base58 key; the passphrase can later be + * passed to [recover], and the returned base58 key should not be surfaced to the user. */ - suspend fun enableRecovery(waitForBackupsToUpload: Boolean): Result + suspend fun enableRecovery(waitForBackupsToUpload: Boolean, passphrase: String? = null): Result /** * Change the recovery and return the new recovery key. diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt index 52b1577bf0..565dc59614 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ClientException.kt @@ -15,6 +15,7 @@ sealed class ClientException(message: String, val details: String?, cause: Throw details = details, cause = cause ) + class ContentScanner(message: String, val reason: ContentScannerErrorReason) : ClientException(message, null, null) class Other(message: String, cause: Throwable? = null) : ClientException(message, null, cause) } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ContentScannerErrorReason.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ContentScannerErrorReason.kt new file mode 100644 index 0000000000..5c32b3989b --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/ContentScannerErrorReason.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.exception + +enum class ContentScannerErrorReason { + MCS_MALFORMED_JSON, + MCS_MEDIA_FAILED_TO_DECRYPT, + M_MISSING_TOKEN, + M_UNKNOWN_TOKEN, + M_NOT_FOUND, + MCS_MEDIA_NOT_CLEAN, + MCS_MIME_TYPE_FORBIDDEN, + MCS_BAD_DECRYPTION, + M_UNKNOWN, + MCS_MEDIA_REQUEST_FAILED; + + companion object; + + fun isDangerous(): Boolean = when (this) { + MCS_MEDIA_NOT_CLEAN, MCS_MIME_TYPE_FORBIDDEN -> true + else -> false + } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt index 1947729c7f..eb2d49b5b0 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/LinkMobileHandler.kt @@ -16,6 +16,9 @@ interface LinkMobileHandler { sealed interface LinkMobileStep { data object Uninitialized : LinkMobileStep + + // Internal application step, for the UI + data object CreatingQrCode : LinkMobileStep data object Starting : LinkMobileStep data class QrReady(val data: String) : LinkMobileStep data object QrRotating : LinkMobileStep diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/GalleryItemInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/GalleryItemInfo.kt new file mode 100644 index 0000000000..484e701dbc --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/GalleryItemInfo.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.media + +import java.io.File + +sealed interface GalleryItemInfo { + val file: File + + data class Image( + override val file: File, + val imageInfo: ImageInfo, + val thumbnailFile: File?, + ) : GalleryItemInfo + + data class Video( + override val file: File, + val videoInfo: VideoInfo, + val thumbnailFile: File?, + ) : GalleryItemInfo + + data class Audio( + override val file: File, + val audioInfo: AudioInfo, + ) : GalleryItemInfo + + data class MediaFile( + override val file: File, + val fileInfo: FileInfo, + ) : GalleryItemInfo +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/paths/SessionPaths.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/paths/SessionPaths.kt new file mode 100644 index 0000000000..d481316f9d --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/paths/SessionPaths.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.paths + +import java.io.File + +data class SessionPaths( + val fileDirectory: File, + val cacheDirectory: File, +) { + fun deleteRecursively() { + fileDirectory.deleteRecursively() + cacheDirectory.deleteRecursively() + } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt index f7f4924d5a..d49343f998 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt @@ -157,11 +157,6 @@ interface BaseRoom : Closeable { */ suspend fun setUnreadFlag(isUnread: Boolean): Result - /** - * Clear the event cache storage for the current room. - */ - suspend fun clearEventCacheStorage(): Result - /** * Get the permalink for the room. */ diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt index f3fefab9a8..6d8325427b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt @@ -212,4 +212,11 @@ interface JoinedRoom : BaseRoom { * @return Result indicating success or failure. */ suspend fun sendLiveLocation(geoUri: String): Result + + /** + * Sets the display name of the current user within this room. + * This is different from the global setDisplayName which updates + * the user's display name across all of their rooms. + */ + suspend fun setOwnMemberDisplayName(displayName: String): Result } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/StateEventType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/StateEventType.kt index 705dd25122..7bfc5dc6bb 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/StateEventType.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/StateEventType.kt @@ -34,6 +34,7 @@ sealed interface StateEventType { data object MemberHints : StateEventType data object RoomImagePack : StateEventType data object RoomLanguage : StateEventType + data object RoomPolicy : StateEventType data class Custom(val type: String) : StateEventType } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt index fe73230dce..8cb933205b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/Timeline.kt @@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo +import io.element.android.libraries.matrix.api.media.GalleryItemInfo import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo @@ -157,6 +158,13 @@ interface Timeline : AutoCloseable { inReplyToEventId: EventId?, ): Result + suspend fun sendGallery( + items: List, + caption: String?, + formattedCaption: String?, + inReplyToEventId: EventId?, + ): Result + suspend fun redactEvent(eventOrTransactionId: EventOrTransactionId, reason: String?): Result suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result @@ -216,6 +224,13 @@ interface Timeline : AutoCloseable { suspend fun loadReplyDetails(eventId: EventId): InReplyTo + /** + * Returns true if [eventId] is currently loaded in this timeline's window, even if the display + * layer does not render it (e.g. filtered or state events). This distinguishes "in the window + * but not displayed" from "genuinely outside the loaded window". + */ + suspend fun isEventLoaded(eventId: EventId): Boolean + /** * Adds a new pinned event by sending an updated `m.room.pinned_events` * event containing the new event id. diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt index 0cc5ca0ff7..fdc538ec44 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt @@ -102,6 +102,21 @@ data class TextMessageType( val formatted: FormattedBody? ) : MessageType +data class GalleryMessageType( + val body: String, + val formatted: FormattedBody?, + val items: List, +) : MessageType + +@Immutable +sealed interface GalleryItemType { + data class Image(val content: ImageMessageType) : GalleryItemType + data class Audio(val content: AudioMessageType) : GalleryItemType + data class Video(val content: VideoMessageType) : GalleryItemType + data class File(val content: FileMessageType) : GalleryItemType + data class Other(val itemType: String, val body: String) : GalleryItemType +} + data class OtherMessageType( val msgType: String, val body: String, diff --git a/libraries/matrix/impl/build.gradle.kts b/libraries/matrix/impl/build.gradle.kts index 0a95147f21..2499b720e3 100644 --- a/libraries/matrix/impl/build.gradle.kts +++ b/libraries/matrix/impl/build.gradle.kts @@ -44,7 +44,7 @@ dependencies { implementation(projects.services.toolbox.api) api(projects.libraries.matrix.api) implementation(projects.libraries.core) - implementation("net.java.dev.jna:jna:5.18.1@aar") + implementation(variantOf(libs.jna) { artifactType("aar") }) implementation(libs.androidx.datastore.preferences) implementation(libs.serialization.json) implementation(libs.kotlinx.collections.immutable) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index bec20aedf2..2cfbbbdc73 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -32,6 +32,7 @@ import io.element.android.libraries.matrix.api.linknewdevice.LinkDesktopHandler import io.element.android.libraries.matrix.api.linknewdevice.LinkMobileHandler import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.oauth.AccountManagementAction +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -81,7 +82,6 @@ import io.element.android.libraries.matrix.impl.spaces.RustSpaceService import io.element.android.libraries.matrix.impl.sync.RustSyncService import io.element.android.libraries.matrix.impl.sync.map import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper -import io.element.android.libraries.matrix.impl.util.SessionPathsProvider import io.element.android.libraries.matrix.impl.util.cancelAndDestroy import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService @@ -137,6 +137,7 @@ import org.matrix.rustcomponents.sdk.RoomPreset as RustRoomPreset import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService class RustMatrixClient( + override val sessionPaths: SessionPaths, private val innerClient: Client, private val sessionStore: SessionStore, private val sessionDelegate: RustClientSessionDelegate, @@ -187,8 +188,6 @@ class RustMatrixClient( sessionDispatcher = sessionDispatcher, ) - private val sessionPathsProvider = SessionPathsProvider(sessionStore) - private val roomSyncSubscriber: RoomSyncSubscriber = RoomSyncSubscriber(innerRoomListService, dispatchers) override val roomListService: RoomListService = RustRoomListService( @@ -801,6 +800,12 @@ class RustMatrixClient( } } + override suspend fun markAllRoomsAsRead(): Result = withContext(sessionDispatcher) { + runCatchingExceptions { + innerClient.markAllRoomsAsRead() + } + } + override suspend fun performDatabaseVacuum(): Result = withContext(sessionDispatcher) { runCatchingExceptions { Timber.d("Performing database vacuuming for session $sessionId...") @@ -824,17 +829,16 @@ class RustMatrixClient( private suspend fun getCacheSize( includeCryptoDb: Boolean = false, ): Long = withContext(sessionDispatcher) { - val sessionDirectory = sessionPathsProvider.provides(sessionId) ?: return@withContext 0L - val cacheSize = sessionDirectory.cacheDirectory.getSizeOfFiles() + val cacheSize = sessionPaths.cacheDirectory.getSizeOfFiles() if (includeCryptoDb) { - cacheSize + sessionDirectory.fileDirectory.getSizeOfFiles() + cacheSize + sessionPaths.fileDirectory.getSizeOfFiles() } else { cacheSize + listOf( "matrix-sdk-state.sqlite3", "matrix-sdk-state.sqlite3-shm", "matrix-sdk-state.sqlite3-wal", ).map { fileName -> - File(sessionDirectory.fileDirectory, fileName) + File(sessionPaths.fileDirectory, fileName) }.sumOf { file -> file.length() } @@ -843,7 +847,7 @@ class RustMatrixClient( private suspend fun deleteSessionDirectory() = withContext(sessionDispatcher) { // Delete all the files for this session - sessionPathsProvider.provides(sessionId)?.deleteRecursively() + sessionPaths.deleteRecursively() } private fun scheduleDatabaseVacuum() { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index 4a91462399..fae99b75c8 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -17,9 +17,8 @@ import io.element.android.libraries.di.CacheDirectory import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.matrix.impl.analytics.UtdTracker -import io.element.android.libraries.matrix.impl.certificates.UserCertificatesProvider -import io.element.android.libraries.matrix.impl.paths.SessionPaths import io.element.android.libraries.matrix.impl.paths.getSessionPaths import io.element.android.libraries.matrix.impl.proxy.ProxyProvider import io.element.android.libraries.matrix.impl.room.TimelineEventFilterFactory @@ -60,7 +59,6 @@ class RustMatrixClientFactory( private val sessionStore: SessionStore, private val userAgentProvider: UserAgentProvider, private val proxyProvider: ProxyProvider, - private val userCertificatesProvider: UserCertificatesProvider, private val clock: SystemClock, private val analyticsService: AnalyticsService, private val featureFlagService: FeatureFlagService, @@ -102,10 +100,10 @@ class RustMatrixClientFactory( client.restoreSession(sessionData.toSession()) - create(client) + create(client, sessionData) } - suspend fun create(client: Client): RustMatrixClient { + suspend fun create(client: Client, sessionData: SessionData): RustMatrixClient { val (anonymizedAccessToken, anonymizedRefreshToken) = client.session().anonymizedTokens() // Must be called before creating the sync service, timelines etc. @@ -121,6 +119,7 @@ class RustMatrixClientFactory( .finish() return RustMatrixClient( + sessionPaths = sessionData.getSessionPaths(), innerClient = client, sessionStore = sessionStore, appCoroutineScope = appCoroutineScope, @@ -151,7 +150,6 @@ class RustMatrixClientFactory( } .setSessionDelegate(sessionDelegate) .userAgent(userAgentProvider.provide()) - .addRootCertificates(userCertificatesProvider.provides()) .autoEnableBackups(true) .autoEnableCrossSigning(true) .roomKeyRecipientStrategy( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/DefaultGetDatabaseSizesUseCase.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/DefaultGetDatabaseSizesUseCase.kt index 8973483132..8dba525788 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/DefaultGetDatabaseSizesUseCase.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/DefaultGetDatabaseSizesUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Element Creations Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. @@ -9,19 +9,53 @@ package io.element.android.libraries.matrix.impl.analytics import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.core.data.bytes import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.analytics.GetDatabaseSizesUseCase import io.element.android.libraries.matrix.api.analytics.SdkStoreSizes import io.element.android.libraries.matrix.api.core.SessionId +import java.io.File +import kotlin.math.max +/** + * An implementation of [GetDatabaseSizesUseCase] that manually calculates the database sizes by checking the file system. + * This is not as accurate as the SDK's internal method, but is used as a fallback for Sentry's non-suspendable hook where + * calling the SDK's suspendable method blocks the main thread and causes ANRs. + */ @ContributesBinding(AppScope::class) class DefaultGetDatabaseSizesUseCase( private val clientProvider: Lazy, ) : GetDatabaseSizesUseCase { - override suspend fun invoke(sessionId: SessionId): Result { + override fun invoke(sessionId: SessionId): Result { val client = clientProvider.value.getOrNull(sessionId) ?: return Result.failure(IllegalArgumentException("No MatrixClient for session $sessionId")) - return client.getDatabaseSizes() + val fileDir = client.sessionPaths.fileDirectory + val cacheDir = client.sessionPaths.cacheDirectory + + val cryptoSize = getDatabaseSize(fileDir, "matrix-sdk-crypto") + val stateSize = getDatabaseSize(fileDir, "matrix-sdk-state") + + val eventCacheSize = getDatabaseSize(cacheDir, "matrix-sdk-event-cache") + val mediaCacheSize = getDatabaseSize(cacheDir, "matrix-sdk-media") + + return Result.success(SdkStoreSizes( + stateStore = stateSize.bytes, + cryptoStore = cryptoSize.bytes, + eventCacheStore = eventCacheSize.bytes, + mediaStore = mediaCacheSize.bytes, + )) + } + + private fun getDatabaseSize(baseDirectory: File, databaseFileName: String): Long { + // Check the sizes of both the main database file and the -wal file, and return the max of the two: + // The -wal file can contain additional data not yet merged into the main file, becoming larger than it. + val databaseFile = File(baseDirectory, "$databaseFileName.sqlite3") + val walFile = File(baseDirectory, "$databaseFileName.sqlite3-wal") + + val databaseSize = if (databaseFile.exists()) databaseFile.length() else 0L + val walSize = if (walFile.exists()) walFile.length() else 0L + + return max(databaseSize, walSize) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt index 3f8893138f..42cbd14cb3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt @@ -13,19 +13,16 @@ import dev.zacsweers.metro.ContributesBinding import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.matrix.api.auth.HomeServerLoginCompatibilityChecker import io.element.android.libraries.matrix.impl.ClientBuilderProvider -import io.element.android.libraries.matrix.impl.certificates.UserCertificatesProvider import timber.log.Timber @ContributesBinding(AppScope::class) class RustHomeServerLoginCompatibilityChecker( private val clientBuilderProvider: ClientBuilderProvider, - private val userCertificatesProvider: UserCertificatesProvider, ) : HomeServerLoginCompatibilityChecker { override suspend fun check(url: String): Result = runCatchingExceptions { clientBuilderProvider.provide() .inMemoryStore() .serverNameOrHomeserverUrl(url) - .addRootCertificates(userCertificatesProvider.provides()) .build() .use { it.homeserverLoginDetails() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index c44f7ffae7..639031334e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginDat import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.impl.ClientBuilderSlidingSync import io.element.android.libraries.matrix.impl.RustMatrixClientFactory @@ -38,7 +39,6 @@ import io.element.android.libraries.matrix.impl.auth.qrlogin.toStep import io.element.android.libraries.matrix.impl.exception.mapClientException import io.element.android.libraries.matrix.impl.keys.SecretGenerator import io.element.android.libraries.matrix.impl.mapper.toSessionData -import io.element.android.libraries.matrix.impl.paths.SessionPaths import io.element.android.libraries.matrix.impl.paths.SessionPathsFactory import io.element.android.libraries.matrix.impl.toSession import io.element.android.libraries.sessionstorage.api.LoginType @@ -160,7 +160,7 @@ class RustMatrixAuthenticationService( passphrase = pendingKey.formattedAsString(), sessionPaths = currentSessionPaths, ) - val matrixClient = rustMatrixClientFactory.create(client) + val matrixClient = rustMatrixClientFactory.create(client, sessionData) newMatrixClientObservers.forEach { it.invoke(matrixClient) } sessionStore.addSession(sessionData) @@ -235,7 +235,7 @@ class RustMatrixAuthenticationService( // We restore the client using the just retrieved session data client.restoreSession(sessionData.toSession()) - val matrixClient = rustMatrixClientFactory.create(client) + val matrixClient = rustMatrixClientFactory.create(client, sessionData) // We wait for the verification state to be known matrixClient.waitForKnownVerificationState() @@ -325,7 +325,7 @@ class RustMatrixAuthenticationService( passphrase = pendingKey.formattedAsString(), sessionPaths = currentSessionPaths, ) - val matrixClient = rustMatrixClientFactory.create(client) + val matrixClient = rustMatrixClientFactory.create(client, sessionData) matrixClient.waitForKnownVerificationState() newMatrixClientObservers.forEach { it.invoke(matrixClient) } @@ -390,7 +390,7 @@ class RustMatrixAuthenticationService( passphrase = pendingKey.formattedAsString(), sessionPaths = emptySessionPaths, ) - val matrixClient = rustMatrixClientFactory.create(client) + val matrixClient = rustMatrixClientFactory.create(client, sessionData) newMatrixClientObservers.forEach { it.invoke(matrixClient) } sessionStore.addSession(sessionData) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt deleted file mode 100644 index 39be03ce5b..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/certificates/DefaultUserCertificatesProvider.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2026 Element Creations Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.certificates - -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding -import timber.log.Timber -import java.security.KeyStore -import java.security.KeyStoreException - -@ContributesBinding(AppScope::class) -class DefaultUserCertificatesProvider : UserCertificatesProvider { - /** - * Get additional user-installed certificates from the `AndroidCAStore` `Keystore`. - * - * The Rust HTTP client doesn't include user-installed certificates in its internal certificate - * store. This means that whatever the user installs will be ignored. - * - * While most users don't need user-installed certificates some special deployments or debugging - * setups using a proxy might want to use them. - * - * @return A list of byte arrays where each byte array is a single user-installed certificate - * in encoded form. - */ - override fun provides(): List { - // At least for API 34 the `AndroidCAStore` `Keystore` type contained user certificates as well. - // I have not found this to be documented anywhere. - val keyStore: KeyStore = try { - KeyStore.getInstance("AndroidCAStore") - } catch (e: KeyStoreException) { - Timber.w(e, "Failed to get AndroidCAStore keystore") - return emptyList() - } - val aliases = try { - keyStore.load(null) - keyStore.aliases() - } catch (e: Exception) { - Timber.w(e, "Failed to load and get aliases AndroidCAStore keystore") - return emptyList() - } - return aliases.toList() - .filter { alias -> - // The certificate alias always contains the prefix `system` or - // `user` and the MD5 subject hash separated by a colon. - // - // The subject hash can be calculated using openssl as such: - // openssl x509 -subject_hash_old -noout -in mycert.cer - // - // Again, I have not found this to be documented somewhere. - alias.startsWith("user") - } - .mapNotNull { alias -> - try { - keyStore.getEntry(alias, null) - } catch (e: Exception) { - Timber.w(e, "Failed to get entry for alias $alias") - null - } - } - .filterIsInstance() - .map { trustedCertificateEntry -> - trustedCertificateEntry.trustedCertificate.encoded - } - .also { - // Let's at least log the number of user-installed certificates we found, - // since the alias isn't particularly useful nor does the issuer seem to - // be easily available. - Timber.i("Found ${it.size} additional user-provided certificates.") - } - } -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt index f67b7cb7e1..74f235f9f8 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt @@ -131,19 +131,28 @@ class RustEncryptionService( override suspend fun enableRecovery( waitForBackupsToUpload: Boolean, - ): Result = withContext(dispatchers.io) { + passphrase: String?, + ): Result = withContext(dispatchers.io) { runCatchingExceptions { - service.enableRecovery( + // The key arrives as the suspend return value (like resetRecoveryKey), avoiding a + // flow/return-value race; the listener only feeds sub-progress. + enableRecoveryProgressStateFlow.value = EnableRecoveryProgress.Starting + val key = service.enableRecovery( waitForBackupsToUpload = waitForBackupsToUpload, progressListener = object : EnableRecoveryProgressListener { override fun onUpdate(status: RustEnableRecoveryProgress) { enableRecoveryProgressStateFlow.value = enableRecoveryProgressMapper.map(status) } }, - passphrase = null, + passphrase = passphrase, ) - // enableRecovery returns the encryption key, but we read it from the state flow - .let { } + // Pin Done explicitly so observers get a coherent terminal value. For the passphrase + // path the user never sees the SDK base58 key, so keep it out of this session-scoped + // (in-memory) flow entirely; the caller still receives it as the return value and is + // responsible for scrubbing it. The auto-generated path must retain the key here since + // that is how it is surfaced to the user. + enableRecoveryProgressStateFlow.value = EnableRecoveryProgress.Done(if (passphrase != null) "" else key) + key }.mapFailure { it.mapRecoveryException() } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/exception/ClientException.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/exception/ClientException.kt index eefa6d4986..27d799f67b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/exception/ClientException.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/exception/ClientException.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl.exception import io.element.android.libraries.matrix.api.exception.ClientException +import io.element.android.libraries.matrix.api.exception.ContentScannerErrorReason import org.matrix.rustcomponents.sdk.ClientException as RustClientException fun Throwable.mapClientException(): ClientException { @@ -23,6 +24,10 @@ fun Throwable.mapClientException(): ClientException { details = details, cause = this, ) + is RustClientException.ContentScanner -> ClientException.ContentScanner( + message = message, + reason = ContentScannerErrorReason.fromRust(reason), + ) } } else -> ClientException.Other(message ?: "Unknown error", this) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/exception/ContentScannerErrorReason.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/exception/ContentScannerErrorReason.kt new file mode 100644 index 0000000000..085a570278 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/exception/ContentScannerErrorReason.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.exception + +import io.element.android.libraries.matrix.api.exception.ContentScannerErrorReason +import uniffi.matrix_sdk_contentscanner.ErrorReason +import uniffi.matrix_sdk_contentscanner.ErrorReason.MCS_BAD_DECRYPTION +import uniffi.matrix_sdk_contentscanner.ErrorReason.MCS_MALFORMED_JSON +import uniffi.matrix_sdk_contentscanner.ErrorReason.MCS_MEDIA_FAILED_TO_DECRYPT +import uniffi.matrix_sdk_contentscanner.ErrorReason.MCS_MEDIA_NOT_CLEAN +import uniffi.matrix_sdk_contentscanner.ErrorReason.MCS_MEDIA_REQUEST_FAILED +import uniffi.matrix_sdk_contentscanner.ErrorReason.MCS_MIME_TYPE_FORBIDDEN +import uniffi.matrix_sdk_contentscanner.ErrorReason.M_MISSING_TOKEN +import uniffi.matrix_sdk_contentscanner.ErrorReason.M_NOT_FOUND +import uniffi.matrix_sdk_contentscanner.ErrorReason.M_UNKNOWN +import uniffi.matrix_sdk_contentscanner.ErrorReason.M_UNKNOWN_TOKEN + +fun ContentScannerErrorReason.Companion.fromRust(reason: ErrorReason) = when (reason) { + M_UNKNOWN -> ContentScannerErrorReason.M_UNKNOWN + M_MISSING_TOKEN -> ContentScannerErrorReason.M_MISSING_TOKEN + M_UNKNOWN_TOKEN -> ContentScannerErrorReason.M_UNKNOWN_TOKEN + MCS_MALFORMED_JSON -> ContentScannerErrorReason.MCS_MALFORMED_JSON + MCS_MEDIA_FAILED_TO_DECRYPT -> ContentScannerErrorReason.MCS_MEDIA_FAILED_TO_DECRYPT + M_NOT_FOUND -> ContentScannerErrorReason.M_NOT_FOUND + MCS_MEDIA_NOT_CLEAN -> ContentScannerErrorReason.MCS_MEDIA_NOT_CLEAN + MCS_MIME_TYPE_FORBIDDEN -> ContentScannerErrorReason.MCS_MIME_TYPE_FORBIDDEN + MCS_BAD_DECRYPTION -> ContentScannerErrorReason.MCS_BAD_DECRYPTION + MCS_MEDIA_REQUEST_FAILED -> ContentScannerErrorReason.MCS_MEDIA_REQUEST_FAILED +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt index cb387a9d21..a44a8d5943 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt @@ -51,6 +51,10 @@ class RustLinkMobileHandler( ) // We emit Done in case the progress listener was deallocated before generate() sent the Done _linkMobileStep.emit(LinkMobileStep.Done) + } catch (e: HumanQrGrantLoginException.Expired) { + // Note: the SDK does not return this error, but is returning `.NotFound` instead when the QR code expires. We catch both just in case. + Timber.tag(tag.value).w(e, "QR code has expired") + _linkMobileStep.emit(LinkMobileStep.QrRotating) } catch (e: HumanQrGrantLoginException.NotFound) { Timber.tag(tag.value).w(e, "Error during QR login grant") // Catch timeout here? diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt index dfda37d7e1..b5964f1a2e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.matrix.impl.mapper import io.element.android.libraries.matrix.api.auth.external.ExternalSession -import io.element.android.libraries.matrix.impl.paths.SessionPaths +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.sessionstorage.api.LoginType import io.element.android.libraries.sessionstorage.api.SessionData import org.matrix.rustcomponents.sdk.Session diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/GalleryItemInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/GalleryItemInfoMapper.kt new file mode 100644 index 0000000000..6e90ea3d62 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/GalleryItemInfoMapper.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.media + +import io.element.android.libraries.matrix.api.media.GalleryItemInfo +import org.matrix.rustcomponents.sdk.GalleryItemInfo as RustGalleryItemInfo +import org.matrix.rustcomponents.sdk.UploadSource as RustUploadSource + +fun GalleryItemInfo.map(): RustGalleryItemInfo = when (this) { + is GalleryItemInfo.Image -> { + RustGalleryItemInfo.Image( + imageInfo = imageInfo.map(), + source = RustUploadSource.File(file.path), + caption = null, + formattedCaption = null, + thumbnailSource = thumbnailFile?.path?.let(RustUploadSource::File), + ) + } + is GalleryItemInfo.Video -> { + RustGalleryItemInfo.Video( + videoInfo = videoInfo.map(), + source = RustUploadSource.File(file.path), + caption = null, + formattedCaption = null, + thumbnailSource = thumbnailFile?.path?.let(RustUploadSource::File), + ) + } + is GalleryItemInfo.Audio -> { + RustGalleryItemInfo.Audio( + audioInfo = audioInfo.map(), + source = RustUploadSource.File(file.path), + caption = null, + formattedCaption = null, + ) + } + is GalleryItemInfo.MediaFile -> { + RustGalleryItemInfo.File( + fileInfo = fileInfo.map(), + source = RustUploadSource.File(file.path), + caption = null, + formattedCaption = null, + ) + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/GalleryMediaUploadHandlerImpl.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/GalleryMediaUploadHandlerImpl.kt new file mode 100644 index 0000000000..5bb01cdb56 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/GalleryMediaUploadHandlerImpl.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.media + +import io.element.android.libraries.androidutils.file.safeDelete +import io.element.android.libraries.core.extensions.runCatchingExceptions +import io.element.android.libraries.matrix.api.media.MediaUploadHandler +import org.matrix.rustcomponents.sdk.SendGalleryJoinHandle +import java.io.File + +class GalleryMediaUploadHandlerImpl( + private val filesToUpload: List, + private val sendGalleryJoinHandle: SendGalleryJoinHandle, +) : MediaUploadHandler { + override suspend fun await(): Result = + runCatchingExceptions { + sendGalleryJoinHandle.join() + } + .also { cleanUpFiles() } + + override fun cancel() { + sendGalleryJoinHandle.cancel() + cleanUpFiles() + } + + private fun cleanUpFiles() { + filesToUpload.forEach { file -> file.safeDelete() } + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt index 7e65a1cc5c..84fd2e80e8 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt @@ -97,7 +97,10 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon is MessageLikeEventContent.ReactionContent -> NotificationContent.MessageLike.ReactionContent(relatedEventId) MessageLikeEventContent.RoomEncrypted -> NotificationContent.MessageLike.RoomEncrypted is MessageLikeEventContent.RoomMessage -> { - NotificationContent.MessageLike.RoomMessage(senderId, EventMessageMapper().mapMessageType(messageType)) + NotificationContent.MessageLike.RoomMessage( + senderId, + EventMessageMapper().mapMessageType(messageType) + ) } is MessageLikeEventContent.RoomRedaction -> NotificationContent.MessageLike.RoomRedaction( redactedEventId = redactedEventId?.let(::EventId), diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPaths.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPaths.kt index 1888cd0f88..8a2403f772 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPaths.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPaths.kt @@ -8,19 +8,10 @@ package io.element.android.libraries.matrix.impl.paths +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.sessionstorage.api.SessionData import java.io.File -data class SessionPaths( - val fileDirectory: File, - val cacheDirectory: File, -) { - fun deleteRecursively() { - fileDirectory.deleteRecursively() - cacheDirectory.deleteRecursively() - } -} - internal fun SessionData.getSessionPaths(): SessionPaths { return SessionPaths( fileDirectory = File(sessionPath), diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPathsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPathsFactory.kt index d2e519fa9e..f40c134209 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPathsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/paths/SessionPathsFactory.kt @@ -11,6 +11,7 @@ package io.element.android.libraries.matrix.impl.paths import dev.zacsweers.metro.Inject import io.element.android.libraries.di.BaseDirectory import io.element.android.libraries.di.CacheDirectory +import io.element.android.libraries.matrix.api.paths.SessionPaths import java.io.File import java.util.UUID diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt index 1b02c03e30..68fcf6287c 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.matrix.impl.room +import io.element.android.appconfig.TimelineConfig import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.core.extensions.mapFailure @@ -218,11 +219,18 @@ class JoinedRustRoom( RoomMessageEventMessageType.IMAGE, RoomMessageEventMessageType.VIDEO, RoomMessageEventMessageType.AUDIO, + RoomMessageEventMessageType.GALLERY, ) ) is CreateTimelineParams.Focused, CreateTimelineParams.PinnedOnly, - is CreateTimelineParams.Threaded -> TimelineFilter.All + is CreateTimelineParams.Threaded -> { + RustTimelineEventFilterFactory().create( + joinRule = roomInfoFlow.value.joinRule, + isEncrypted = roomInfoFlow.value.isEncrypted, + excludedStateTypes = TimelineConfig.excludedEvents, + )?.let(TimelineFilter::EventFilter) ?: TimelineFilter.All + } } val internalIdPrefix = when (createTimelineParams) { @@ -548,6 +556,12 @@ class JoinedRustRoom( } } + override suspend fun setOwnMemberDisplayName(displayName: String): Result = withContext(roomDispatcher) { + runCatchingExceptions { + innerRoom.setOwnMemberDisplayName(displayName) + } + } + override fun close() = destroy() override fun destroy() { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt index 47b37b7923..bb1460863f 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventType.kt @@ -9,7 +9,8 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.matrix.api.room.MessageEventType -import org.matrix.rustcomponents.sdk.MessageLikeEventType +import uniffi.ruma_events.MessageLikeEventType +import uniffi.ruma_events.messageLikeEventTypeFromString fun MessageEventType.map(): MessageLikeEventType = when (this) { MessageEventType.Audio -> MessageLikeEventType.Audio @@ -51,7 +52,7 @@ fun MessageEventType.map(): MessageLikeEventType = when (this) { MessageEventType.UnstablePollStart -> MessageLikeEventType.UnstablePollStart MessageEventType.Video -> MessageLikeEventType.Video MessageEventType.Voice -> MessageLikeEventType.Voice - is MessageEventType.Other -> MessageLikeEventType.Other(type) + is MessageEventType.Other -> messageLikeEventTypeFromString(type) } fun MessageLikeEventType.map(): MessageEventType = when (this) { @@ -94,5 +95,5 @@ fun MessageLikeEventType.map(): MessageEventType = when (this) { MessageLikeEventType.RtcDecline -> MessageEventType.RtcDecline MessageLikeEventType.Video -> MessageEventType.Video MessageLikeEventType.Voice -> MessageEventType.Voice - is MessageLikeEventType.Other -> MessageEventType.Other(v1) + is MessageLikeEventType.Custom -> MessageEventType.Other(type = toString()) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt index e000c2f916..39cde68c31 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomContentForwarder.kt @@ -49,7 +49,7 @@ class RoomContentForwarder( val content = (messageLikeContent.kind as? MsgLikeKind.Message)?.content ?: throw ForwardEventException(toRoomIds) - val targetRooms = toRoomIds.mapNotNull { roomId -> roomListService.roomOrNull(roomId.value) } + val targetRooms = toRoomIds.toSet().mapNotNull { roomId -> roomListService.roomOrNull(roomId.value) } val failedForwardingTo = mutableSetOf() targetRooms.parallelMap { room -> room.use { targetRoom -> diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt index 0551891a6d..7c5cd10658 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt @@ -200,12 +200,6 @@ class RustBaseRoom( } } - override suspend fun clearEventCacheStorage(): Result = withContext(roomDispatcher) { - runCatchingExceptions { - innerRoom.clearEventCacheStorage() - } - } - override suspend fun setIsFavorite(isFavorite: Boolean): Result = withContext(roomDispatcher) { runCatchingExceptions { innerRoom.setIsFavourite(isFavorite, null) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt index 15a0850184..b5f9c3ee80 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt @@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.awaitLoaded +import io.element.android.libraries.matrix.impl.room.join.map import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper import io.element.android.libraries.matrix.impl.roomlist.roomOrNull import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction @@ -41,6 +42,7 @@ import org.matrix.rustcomponents.sdk.TimelineConfiguration import org.matrix.rustcomponents.sdk.TimelineFilter import org.matrix.rustcomponents.sdk.TimelineFocus import timber.log.Timber +import uniffi.matrix_sdk_base.EncryptionState import uniffi.matrix_sdk_ui.TimelineReadReceiptTracking import java.util.concurrent.atomic.AtomicBoolean import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService @@ -66,12 +68,6 @@ class RustRoomFactory( private val mutex = Mutex() private val isDestroyed: AtomicBoolean = AtomicBoolean(false) - private val eventFilters = TimelineConfig.excludedEvents - .takeIf { it.isNotEmpty() } - ?.let { listStateEventType -> - timelineEventFilterFactory.create(listStateEventType) - } - suspend fun destroy() { withContext(NonCancellable + dispatcher) { mutex.withLock { @@ -128,10 +124,20 @@ class RustRoomFactory( operation = "sdkRoom.timelineWithConfiguration", description = "Get timeline from the SDK", ) { + val isEncrypted = when (roomInfo.encryptionState) { + EncryptionState.ENCRYPTED -> true + EncryptionState.NOT_ENCRYPTED -> false + EncryptionState.UNKNOWN -> null + } + val timelineFilter = timelineEventFilterFactory.create( + joinRule = roomInfo.joinRule?.map(), + isEncrypted = isEncrypted, + excludedStateTypes = TimelineConfig.excludedEvents, + ) sdkRoom.timelineWithConfiguration( TimelineConfiguration( focus = TimelineFocus.Live(hideThreadedEvents = hideThreadedEvents), - filter = eventFilters?.let(TimelineFilter::EventFilter) ?: TimelineFilter.All, + filter = timelineFilter?.let(TimelineFilter::EventFilter) ?: TimelineFilter.All, internalIdPrefix = "live", dateDividerMode = DateDividerMode.DAILY, trackReadReceipts = TimelineReadReceiptTracking.ALL_EVENTS, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/StateEventType.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/StateEventType.kt index 897d9a34cb..13a040525e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/StateEventType.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/StateEventType.kt @@ -9,7 +9,8 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.matrix.api.room.StateEventType -import org.matrix.rustcomponents.sdk.StateEventType as RustStateEventType +import uniffi.ruma_events.stateEventTypeFromString +import uniffi.ruma_events.StateEventType as RustStateEventType fun StateEventType.map(): RustStateEventType = when (this) { StateEventType.PolicyRuleRoom -> RustStateEventType.PolicyRuleRoom @@ -23,7 +24,7 @@ fun StateEventType.map(): RustStateEventType = when (this) { StateEventType.RoomGuestAccess -> RustStateEventType.RoomGuestAccess StateEventType.RoomHistoryVisibility -> RustStateEventType.RoomHistoryVisibility StateEventType.RoomJoinRules -> RustStateEventType.RoomJoinRules - StateEventType.RoomMemberEvent -> RustStateEventType.RoomMemberEvent + StateEventType.RoomMemberEvent -> RustStateEventType.RoomMember StateEventType.RoomName -> RustStateEventType.RoomName StateEventType.RoomPinnedEvents -> RustStateEventType.RoomPinnedEvents StateEventType.RoomPowerLevels -> RustStateEventType.RoomPowerLevels @@ -37,7 +38,8 @@ fun StateEventType.map(): RustStateEventType = when (this) { StateEventType.MemberHints -> RustStateEventType.MemberHints StateEventType.RoomImagePack -> RustStateEventType.RoomImagePack StateEventType.RoomLanguage -> RustStateEventType.RoomLanguage - is StateEventType.Custom -> RustStateEventType.Custom(type) + StateEventType.RoomPolicy -> RustStateEventType.RoomPolicy + is StateEventType.Custom -> stateEventTypeFromString(type) } fun RustStateEventType.map(): StateEventType = when (this) { @@ -52,7 +54,7 @@ fun RustStateEventType.map(): StateEventType = when (this) { RustStateEventType.RoomGuestAccess -> StateEventType.RoomGuestAccess RustStateEventType.RoomHistoryVisibility -> StateEventType.RoomHistoryVisibility RustStateEventType.RoomJoinRules -> StateEventType.RoomJoinRules - RustStateEventType.RoomMemberEvent -> StateEventType.RoomMemberEvent + RustStateEventType.RoomMember -> StateEventType.RoomMemberEvent RustStateEventType.RoomName -> StateEventType.RoomName RustStateEventType.RoomPinnedEvents -> StateEventType.RoomPinnedEvents RustStateEventType.RoomPowerLevels -> StateEventType.RoomPowerLevels @@ -66,5 +68,6 @@ fun RustStateEventType.map(): StateEventType = when (this) { RustStateEventType.MemberHints -> StateEventType.MemberHints RustStateEventType.RoomImagePack -> StateEventType.RoomImagePack RustStateEventType.RoomLanguage -> StateEventType.RoomLanguage - is RustStateEventType.Custom -> StateEventType.Custom(value) + RustStateEventType.RoomPolicy -> StateEventType.RoomPolicy + is RustStateEventType.Custom -> StateEventType.Custom(this.toString()) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/TimelineEventFilterFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/TimelineEventFilterFactory.kt index b4735fdaf3..a966acaa2b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/TimelineEventFilterFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/TimelineEventFilterFactory.kt @@ -11,20 +11,45 @@ package io.element.android.libraries.matrix.impl.room import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import io.element.android.libraries.matrix.api.room.StateEventType +import io.element.android.libraries.matrix.api.room.join.JoinRule +import org.matrix.rustcomponents.sdk.FilterTimelineEventCondition import org.matrix.rustcomponents.sdk.FilterTimelineEventType import org.matrix.rustcomponents.sdk.TimelineEventFilter +import uniffi.matrix_sdk_ui.MembershipChangeFilter interface TimelineEventFilterFactory { - fun create(listStateEventType: List): TimelineEventFilter + fun create( + joinRule: JoinRule?, + isEncrypted: Boolean?, + excludedStateTypes: List + ): TimelineEventFilter? } @ContributesBinding(AppScope::class) class RustTimelineEventFilterFactory : TimelineEventFilterFactory { - override fun create(listStateEventType: List): TimelineEventFilter { - return TimelineEventFilter.excludeEventTypes( - listStateEventType.map { stateEventType -> - FilterTimelineEventType.State(stateEventType.map()) - } - ) + override fun create( + joinRule: JoinRule?, + isEncrypted: Boolean?, + excludedStateTypes: List + ): TimelineEventFilter? { + val excludedEventTypes = excludedStateTypes.map { + FilterTimelineEventCondition.EventType(FilterTimelineEventType.State(it.map())) + } + // If the room is publicly joinable and not encrypted, we also want to exclude membership changes and profile changes, + // as they will pollute the timelines since they're quite common and not add much value. + val excludedMembershipChanges = if (joinRule !is JoinRule.Invite && isEncrypted == false) { + listOf( + FilterTimelineEventCondition.MembershipChange(MembershipChangeFilter.JOIN), + FilterTimelineEventCondition.MembershipChange(MembershipChangeFilter.LEAVE), + FilterTimelineEventCondition.ProfileChange, + ) + } else { + emptyList() + } + return if (excludedEventTypes.isNotEmpty() || excludedMembershipChanges.isNotEmpty()) { + TimelineEventFilter.exclude(excludedEventTypes + excludedMembershipChanges) + } else { + null + } } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt index 3fdfb7a179..4cfcf1a95e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilder.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.impl.storage import io.element.android.libraries.androidutils.crypto.ClientSecret import io.element.android.libraries.core.data.ByteUnit import io.element.android.libraries.core.data.megaBytes -import io.element.android.libraries.matrix.impl.paths.SessionPaths +import io.element.android.libraries.matrix.api.paths.SessionPaths import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.SqliteStoreBuilder as SdkSqliteStoreBuilder diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilderProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilderProvider.kt index 29a30f3c56..5d79e72403 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilderProvider.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/storage/SqliteStoreBuilderProvider.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.matrix.impl.storage import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.matrix.impl.paths.SessionPaths +import io.element.android.libraries.matrix.api.paths.SessionPaths interface SqliteStoreBuilderProvider { fun provide(sessionPaths: SessionPaths): SqliteStoreBuilder diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index d44676d34a..bd756bc002 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo +import io.element.android.libraries.matrix.api.media.GalleryItemInfo import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo @@ -30,6 +31,7 @@ import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.TimelineException import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo +import io.element.android.libraries.matrix.impl.media.GalleryMediaUploadHandlerImpl import io.element.android.libraries.matrix.impl.media.MediaUploadHandlerImpl import io.element.android.libraries.matrix.impl.media.map import io.element.android.libraries.matrix.impl.poll.toInner @@ -38,8 +40,6 @@ import io.element.android.libraries.matrix.impl.room.location.into import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper -import io.element.android.libraries.matrix.impl.timeline.postprocessor.FilterEmptyDayPostProcessor -import io.element.android.libraries.matrix.impl.timeline.postprocessor.FilterPublicMembershipChangesPostProcessor import io.element.android.libraries.matrix.impl.timeline.postprocessor.LastForwardIndicatorsPostProcessor import io.element.android.libraries.matrix.impl.timeline.postprocessor.LoadingIndicatorsPostProcessor import io.element.android.libraries.matrix.impl.timeline.postprocessor.RoomBeginningPostProcessor @@ -69,6 +69,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.EditedContent import org.matrix.rustcomponents.sdk.FormattedBody +import org.matrix.rustcomponents.sdk.GalleryUploadParameters import org.matrix.rustcomponents.sdk.MessageFormat import org.matrix.rustcomponents.sdk.PollData import org.matrix.rustcomponents.sdk.SendAttachmentJoinHandle @@ -125,8 +126,6 @@ class RustTimeline( private val loadingIndicatorsPostProcessor = LoadingIndicatorsPostProcessor(systemClock) private val lastForwardIndicatorsPostProcessor = LastForwardIndicatorsPostProcessor(mode) private val typingNotificationPostProcessor = TypingNotificationPostProcessor(mode) - private val publicMembershipChangesPostProcessor = FilterPublicMembershipChangesPostProcessor() - private val emptyDayPostProcessor = FilterEmptyDayPostProcessor() private data class RoomTimelineInfo( val roomCreators: ImmutableList, @@ -252,18 +251,6 @@ class RustTimeline( hasMoreToLoadBackwards = backwardPaginationStatus.hasMoreToLoad, ) } - // This should be the first post processor after room beginning. - .let { items -> - publicMembershipChangesPostProcessor.process( - items = items, - joinRule = joinRule, - isEncrypted = isEncrypted, - ) - } - // After removing public membership changes, we might end up with empty days, so we need to filter them out. - .let { items -> - emptyDayPostProcessor.process(items) - } .let { items -> loadingIndicatorsPostProcessor.process( items = items, @@ -551,6 +538,42 @@ class RustTimeline( } } + override suspend fun sendGallery( + items: List, + caption: String?, + formattedCaption: String?, + inReplyToEventId: EventId?, + ): Result { + Timber.d("Sending gallery with ${items.size} items") + val allFiles = items.flatMap { item -> + when (item) { + is GalleryItemInfo.Image -> listOfNotNull(item.file, item.thumbnailFile) + is GalleryItemInfo.Video -> listOfNotNull(item.file, item.thumbnailFile) + is GalleryItemInfo.Audio -> listOf(item.file) + is GalleryItemInfo.MediaFile -> listOf(item.file) + } + } + return sendGalleryAttachment(allFiles) { + inner.sendGallery( + params = GalleryUploadParameters( + caption = caption, + formattedCaption = formattedCaption?.let { + FormattedBody(body = it, format = MessageFormat.Html) + }, + mentions = null, + inReplyTo = inReplyToEventId?.value, + ), + itemInfos = items.map { it.map() }, + ) + } + } + + private fun sendGalleryAttachment(files: List, handle: () -> org.matrix.rustcomponents.sdk.SendGalleryJoinHandle): Result { + return runCatchingExceptions { + GalleryMediaUploadHandlerImpl(files, handle()) + } + } + override suspend fun createPoll( question: String, answers: List, @@ -637,6 +660,24 @@ class RustTimeline( } } + override suspend fun isEventLoaded(eventId: EventId): Boolean = withContext(dispatcher) { + val isInLoadedItems = _timelineItems.replayCache.firstOrNull().orEmpty().any { timelineItem -> + timelineItem is MatrixTimelineItem.Event && timelineItem.eventId == eventId + } + if (isInLoadedItems) { + // Displayed events are caught above. The SDK-level list still holds events the display + // layer later drops, so this avoids the FFI call for in-window-but-not-rendered events. + true + } else { + // getEventTimelineItemByEventId throws when the event isn't in the loaded window. + // EventTimelineItem is a Disposable wrapping a native handle, so release it once we've + // confirmed presence — otherwise the handle lingers until the GC cleaner runs. + runCatchingExceptions { + inner.getEventTimelineItemByEventId(eventId.value).use { /* presence is all we need */ } + }.isSuccess + } + } + override suspend fun pinEvent(eventId: EventId): Result = withContext(dispatcher) { runCatchingExceptions { inner.pinEvent(eventId = eventId.value) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt index e382bce8db..0811cd741d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt @@ -13,6 +13,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageT import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType @@ -31,12 +33,10 @@ import org.matrix.rustcomponents.sdk.MessageType import org.matrix.rustcomponents.sdk.MsgLikeKind import org.matrix.rustcomponents.sdk.use import org.matrix.rustcomponents.sdk.FormattedBody as RustFormattedBody +import org.matrix.rustcomponents.sdk.GalleryItemType as RustGalleryItemType import org.matrix.rustcomponents.sdk.MessageFormat as RustMessageFormat import org.matrix.rustcomponents.sdk.MessageType as RustMessageType -// https://github.com/Johennes/matrix-spec-proposals/blob/johannes/msgtype-galleries/proposals/4274-inline-media-galleries.md#unstable-prefix -private const val MSG_TYPE_GALLERY_UNSTABLE = "dm.filament.gallery" - class EventMessageMapper { private val inReplyToMapper by lazy { InReplyToMapper(TimelineEventContentMapper()) } @@ -124,8 +124,64 @@ class EventMessageMapper { OtherMessageType(type.msgtype, type.body) } is MessageType.Gallery -> { - // TODO expose the GalleryType. - OtherMessageType(MSG_TYPE_GALLERY_UNSTABLE, type.content.body) + GalleryMessageType( + body = type.content.body, + formatted = type.content.formatted?.map(), + items = type.content.itemtypes.map { mapGalleryItemType(it) }, + ) + } + } + + private fun mapGalleryItemType(type: RustGalleryItemType): GalleryItemType = when (type) { + is RustGalleryItemType.Image -> { + GalleryItemType.Image( + content = ImageMessageType( + filename = type.content.filename, + caption = type.content.caption, + formattedCaption = type.content.formattedCaption?.map(), + source = type.content.source.map(), + info = type.content.info?.map(), + ) + ) + } + is RustGalleryItemType.Audio -> { + GalleryItemType.Audio( + content = AudioMessageType( + filename = type.content.filename, + caption = type.content.caption, + formattedCaption = type.content.formattedCaption?.map(), + source = type.content.source.map(), + info = type.content.info?.map(), + ) + ) + } + is RustGalleryItemType.Video -> { + GalleryItemType.Video( + content = VideoMessageType( + filename = type.content.filename, + caption = type.content.caption, + formattedCaption = type.content.formattedCaption?.map(), + source = type.content.source.map(), + info = type.content.info?.map(), + ) + ) + } + is RustGalleryItemType.File -> { + GalleryItemType.File( + content = FileMessageType( + filename = type.content.filename, + caption = type.content.caption, + formattedCaption = type.content.formattedCaption?.map(), + source = type.content.source.map(), + info = type.content.info?.map(), + ) + ) + } + is RustGalleryItemType.Other -> { + GalleryItemType.Other( + itemType = type.itemtype, + body = type.body, + ) } } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterEmptyDayPostProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterEmptyDayPostProcessor.kt deleted file mode 100644 index b7dceafa25..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterEmptyDayPostProcessor.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2026 Element Creations Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.timeline.postprocessor - -import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem -import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem - -/** - * Post-processor to filter out day separators for days that don't contain any events. - */ -class FilterEmptyDayPostProcessor { - /** - * Filters out day separators from [items] for days that don't contain any events. - */ - fun process(items: List): List = buildList { - // The timeline is ordered by descending timestamp, so events that happened during a day appear before the day separator for that day. - // We can use this to determine if a day separator should be kept or not. - var hasEvent = false - for (item in items) { - if (item is MatrixTimelineItem.Event) { - hasEvent = true - add(item) - } else if (item is MatrixTimelineItem.Virtual && item.virtual is VirtualTimelineItem.DayDivider) { - if (hasEvent) { - add(item) - hasEvent = false - } - } else { - add(item) - } - } - } -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterPublicMembershipChangesPostProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterPublicMembershipChangesPostProcessor.kt deleted file mode 100644 index 806c9369bf..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterPublicMembershipChangesPostProcessor.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2026 Element Creations Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.timeline.postprocessor - -import io.element.android.libraries.matrix.api.room.join.JoinRule -import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem -import io.element.android.libraries.matrix.api.timeline.item.event.MembershipChange -import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent -import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent - -/** - * Post-processor to filter out public membership changes for non-encrypted, publicly joinable rooms. - */ -class FilterPublicMembershipChangesPostProcessor { - /** - * Filters out public membership changes from [items] if the room is publicly joinable and not encrypted. - */ - fun process( - items: List, - joinRule: JoinRule?, - isEncrypted: Boolean?, - ): List { - return if (joinRule !is JoinRule.Invite && isEncrypted == false) { - filterMembershipEvents(items) - } else { - items - } - } - - private fun filterMembershipEvents(items: List): List = items.filter { item -> - val eventContent = (item as? MatrixTimelineItem.Event)?.event?.content ?: return@filter true - when (eventContent) { - is RoomMembershipContent -> eventContent.change != null && eventContent.change !in listOf(MembershipChange.JOINED, MembershipChange.LEFT) - is ProfileChangeContent -> false - else -> true - } - } -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionPathsProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionPathsProvider.kt deleted file mode 100644 index 0030c6e23e..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/util/SessionPathsProvider.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2024, 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.util - -import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.matrix.impl.paths.SessionPaths -import io.element.android.libraries.matrix.impl.paths.getSessionPaths -import io.element.android.libraries.sessionstorage.api.SessionStore - -class SessionPathsProvider( - private val sessionStore: SessionStore, -) { - suspend fun provides(sessionId: SessionId): SessionPaths? { - val sessionData = sessionStore.getSession(sessionId.value) ?: return null - return sessionData.getSessionPaths() - } -} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt index 670430e23e..1c25acf088 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactoryTest.kt @@ -12,7 +12,6 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.impl.auth.FakeProxyProvider -import io.element.android.libraries.matrix.impl.auth.FakeUserCertificatesProvider import io.element.android.libraries.matrix.impl.room.FakeTimelineEventFilterFactory import io.element.android.libraries.matrix.impl.storage.FakeSqliteStoreBuilderProvider import io.element.android.libraries.network.useragent.SimpleUserAgentProvider @@ -58,7 +57,6 @@ fun TestScope.createRustMatrixClientFactory( coroutineDispatchers = testCoroutineDispatchers(), sessionStore = sessionStore, userAgentProvider = SimpleUserAgentProvider(), - userCertificatesProvider = FakeUserCertificatesProvider(), proxyProvider = FakeProxyProvider(), clock = FakeSystemClock(), analyticsService = FakeAnalyticsService(), diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt index ed8440fe53..a8e812d031 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt @@ -13,6 +13,7 @@ package io.element.android.libraries.matrix.impl import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.data.bytes import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiClient import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiSyncService import io.element.android.libraries.matrix.impl.room.FakeTimelineEventFilterFactory @@ -141,6 +142,7 @@ class RustMatrixClientTest { ), ) = RustMatrixClient( innerClient = client, + sessionPaths = SessionPaths(fileDirectory = File("files"), cacheDirectory = File("cache")), sessionStore = sessionStore, appCoroutineScope = backgroundScope, sessionDelegate = aRustClientSessionDelegate( diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/FakeUserCertificatesProvider.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/FakeUserCertificatesProvider.kt deleted file mode 100644 index 955af4a23d..0000000000 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/FakeUserCertificatesProvider.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2026 Element Creations Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.auth - -import io.element.android.libraries.matrix.impl.certificates.UserCertificatesProvider - -class FakeUserCertificatesProvider : UserCertificatesProvider { - override fun provides(): List { - return emptyList() - } -} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt index 903273113b..862019091b 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt @@ -49,6 +49,5 @@ class RustHomeserverLoginCompatibilityCheckerTest { FakeFfiClient(homeserverLoginDetailsResult = result) } }, - userCertificatesProvider = FakeUserCertificatesProvider(), ) } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/TimelineEventContentMessageLike.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/TimelineEventContentMessageLike.kt index 877f2056e9..96303a257b 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/TimelineEventContentMessageLike.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/TimelineEventContentMessageLike.kt @@ -8,12 +8,26 @@ package io.element.android.libraries.matrix.impl.fixtures.factories +import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiMediaSource import io.element.android.libraries.matrix.test.A_MESSAGE +import org.matrix.rustcomponents.sdk.AudioInfo +import org.matrix.rustcomponents.sdk.AudioMessageContent +import org.matrix.rustcomponents.sdk.FileInfo +import org.matrix.rustcomponents.sdk.FileMessageContent import org.matrix.rustcomponents.sdk.FormattedBody +import org.matrix.rustcomponents.sdk.GalleryItemType +import org.matrix.rustcomponents.sdk.GalleryMessageContent +import org.matrix.rustcomponents.sdk.ImageInfo +import org.matrix.rustcomponents.sdk.ImageMessageContent +import org.matrix.rustcomponents.sdk.MediaSource import org.matrix.rustcomponents.sdk.MessageLikeEventContent import org.matrix.rustcomponents.sdk.MessageType import org.matrix.rustcomponents.sdk.TextMessageContent import org.matrix.rustcomponents.sdk.TimelineEventContent +import org.matrix.rustcomponents.sdk.UnstableAudioDetailsContent +import org.matrix.rustcomponents.sdk.UnstableVoiceContent +import org.matrix.rustcomponents.sdk.VideoInfo +import org.matrix.rustcomponents.sdk.VideoMessageContent internal fun aRustTimelineEventContentMessageLike( content: MessageLikeEventContent = aRustMessageLikeEventContentRoomMessage(), @@ -42,3 +56,94 @@ internal fun aRustTextMessageContent( body = body, formatted = formatted, ) + +internal fun aRustMessageTypeGallery( + content: GalleryMessageContent = aRustGalleryMessageContent(), +) = MessageType.Gallery(content = content) + +internal fun aRustGalleryMessageContent( + body: String = "A gallery", + formatted: FormattedBody? = null, + itemTypes: List = listOf(aRustGalleryItemTypeImage()), +) = GalleryMessageContent(body = body, formatted = formatted, itemtypes = itemTypes) + +internal fun aRustGalleryItemTypeImage( + content: ImageMessageContent = aRustImageMessageContent(), +) = GalleryItemType.Image(content = content) + +internal fun aRustGalleryItemTypeAudio( + content: AudioMessageContent = aRustAudioMessageContent(), +) = GalleryItemType.Audio(content = content) + +internal fun aRustGalleryItemTypeVideo( + content: VideoMessageContent = aRustVideoMessageContent(), +) = GalleryItemType.Video(content = content) + +internal fun aRustGalleryItemTypeFile( + content: FileMessageContent = aRustFileMessageContent(), +) = GalleryItemType.File(content = content) + +internal fun aRustGalleryItemTypeOther( + itemType: String = "m.unknown", + body: String = "unknown item", +) = GalleryItemType.Other(itemtype = itemType, body = body) + +internal fun aRustImageMessageContent( + filename: String = "image.jpg", + caption: String? = null, + formattedCaption: FormattedBody? = null, + source: MediaSource = FakeFfiMediaSource("mxc://server/image"), + info: ImageInfo? = null, +) = ImageMessageContent( + filename = filename, + caption = caption, + formattedCaption = formattedCaption, + source = source, + info = info, +) + +internal fun aRustAudioMessageContent( + filename: String = "audio.mp3", + caption: String? = null, + formattedCaption: FormattedBody? = null, + source: MediaSource = FakeFfiMediaSource("mxc://server/audio"), + info: AudioInfo? = null, + audio: UnstableAudioDetailsContent? = null, + voice: UnstableVoiceContent? = null, +) = AudioMessageContent( + filename = filename, + caption = caption, + formattedCaption = formattedCaption, + source = source, + info = info, + audio = audio, + voice = voice, +) + +internal fun aRustVideoMessageContent( + filename: String = "video.mp4", + caption: String? = null, + formattedCaption: FormattedBody? = null, + source: MediaSource = FakeFfiMediaSource("mxc://server/video"), + info: VideoInfo? = null, +) = VideoMessageContent( + filename = filename, + caption = caption, + formattedCaption = formattedCaption, + source = source, + info = info, +) + +internal fun aRustFileMessageContent( + filename: String = "document.pdf", + caption: String? = null, + formattedCaption: FormattedBody? = null, + source: MediaSource = FakeFfiMediaSource("mxc://server/file"), + info: FileInfo? = null, +) = FileMessageContent( + filename = filename, + caption = caption, + formattedCaption = formattedCaption, + source = source, + info = info, +) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiMediaSource.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiMediaSource.kt new file mode 100644 index 0000000000..7dbcb1d762 --- /dev/null +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiMediaSource.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.fixtures.fakes + +import org.matrix.rustcomponents.sdk.MediaSource +import org.matrix.rustcomponents.sdk.NoHandle + +internal class FakeFfiMediaSource( + private val fakeUrl: String = "mxc://server/media", +) : MediaSource(NoHandle) { + override fun url(): String = fakeUrl + override fun toJson(): String = """{"url":"$fakeUrl"}""" +} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultSecretGeneratorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultSecretGeneratorTest.kt index 4bda511d42..b18933fb53 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultSecretGeneratorTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/keys/DefaultSecretGeneratorTest.kt @@ -10,12 +10,10 @@ package io.element.android.libraries.matrix.impl.keys import com.google.common.truth.Truth.assertThat import io.element.android.libraries.androidutils.crypto.ClientSecret +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultSecretGeneratorTest { +class DefaultSecretGeneratorTest : RobolectricTest() { @Test fun `check that generated passphrase has the expected length`() { val secretGenerator = DefaultSecretGenerator() diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt index ad751cc86b..3d84e34f45 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt @@ -147,6 +147,32 @@ class RustLinkMobileHandlerTest { } } + @Test + fun `when start throws HumanQrGrantLoginException_Expired, the handler emits QrRotating step`() = runTest { + val completable = CompletableDeferred() + val handler = FakeFfiGrantLoginWithQrCodeHandler( + generateResult = { + completable.await() + throw HumanQrGrantLoginException.Expired("Expired") + } + ) + val sut = createRustLinkMobileHandler( + handler, + ) + sut.linkMobileStep.test { + val initialItem = awaitItem() + assertThat(initialItem).isEqualTo(LinkMobileStep.Uninitialized) + backgroundScope.launch { + sut.start() + } + runCurrent() + // generate returns, error is emitted + completable.complete(Unit) + val qrRotatingState = awaitItem() + assertThat(qrRotatingState).isEqualTo(LinkMobileStep.QrRotating) + } + } + private fun TestScope.createRustLinkMobileHandler( handler: FakeFfiGrantLoginWithQrCodeHandler = FakeFfiGrantLoginWithQrCodeHandler(), ) = RustLinkMobileHandler( diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt index fb9ec6625b..6042f195f8 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt @@ -10,8 +10,8 @@ package io.element.android.libraries.matrix.impl.mapper import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.auth.external.ExternalSession +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.matrix.impl.fixtures.factories.aRustSession -import io.element.android.libraries.matrix.impl.paths.SessionPaths import io.element.android.libraries.matrix.test.A_DEVICE_ID import io.element.android.libraries.matrix.test.A_HOMESERVER_URL import io.element.android.libraries.matrix.test.A_HOMESERVER_URL_2 diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt index dcd2c4594c..97b51c0026 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/permalink/DefaultMatrixToConverterTest.kt @@ -10,12 +10,10 @@ package io.element.android.libraries.matrix.impl.permalink import android.net.Uri import com.google.common.truth.Truth.assertThat +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultMatrixToConverterTest { +class DefaultMatrixToConverterTest : RobolectricTest() { @Test fun `converting a matrix-to url does nothing`() { val url = Uri.parse("https://matrix.to/#/#element-android:matrix.org") diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/FakeTimelineEventFilterFactory.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/FakeTimelineEventFilterFactory.kt index f35746d8d3..713e04d239 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/FakeTimelineEventFilterFactory.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/FakeTimelineEventFilterFactory.kt @@ -9,11 +9,12 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.matrix.api.room.StateEventType +import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimelineEventFilter import org.matrix.rustcomponents.sdk.TimelineEventFilter class FakeTimelineEventFilterFactory : TimelineEventFilterFactory { - override fun create(listStateEventType: List): TimelineEventFilter { + override fun create(joinRule: JoinRule?, isEncrypted: Boolean?, excludedStateTypes: List): TimelineEventFilter { return FakeFfiTimelineEventFilter() } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventTypeKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventTypeKtTest.kt index 654989a393..d36bb80e96 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventTypeKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MessageEventTypeKtTest.kt @@ -10,10 +10,12 @@ package io.element.android.libraries.matrix.impl.room import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.room.MessageEventType +import org.junit.Ignore import org.junit.Test -import org.matrix.rustcomponents.sdk.MessageLikeEventType +import uniffi.ruma_events.MessageLikeEventType class MessageEventTypeKtTest { + @Ignore("Can't use MessageLikeEventType as that will try accessing the Rust SDK") @Test fun `map Rust type should result to correct Kotlin type`() { assertThat(MessageLikeEventType.CallAnswer.map()).isEqualTo(MessageEventType.CallAnswer) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/StateEventTypeTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/StateEventTypeTest.kt index 93a8f0908f..621299243e 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/StateEventTypeTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/StateEventTypeTest.kt @@ -10,10 +10,12 @@ package io.element.android.libraries.matrix.impl.room import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.room.StateEventType +import org.junit.Ignore import org.junit.Test -import org.matrix.rustcomponents.sdk.StateEventType as RustStateEventType +import uniffi.ruma_events.StateEventType as RustStateEventType class StateEventTypeTest { + @Ignore("Can't use RustStateEventType as that will try accessing the Rust SDK") @Test fun `mapping Rust type should work`() { assertThat(RustStateEventType.CallMember.map()).isEqualTo(StateEventType.CallMember) @@ -27,9 +29,10 @@ class StateEventTypeTest { assertThat(RustStateEventType.RoomGuestAccess.map()).isEqualTo(StateEventType.RoomGuestAccess) assertThat(RustStateEventType.RoomHistoryVisibility.map()).isEqualTo(StateEventType.RoomHistoryVisibility) assertThat(RustStateEventType.RoomJoinRules.map()).isEqualTo(StateEventType.RoomJoinRules) - assertThat(RustStateEventType.RoomMemberEvent.map()).isEqualTo(StateEventType.RoomMemberEvent) + assertThat(RustStateEventType.RoomMember.map()).isEqualTo(StateEventType.RoomMemberEvent) assertThat(RustStateEventType.RoomName.map()).isEqualTo(StateEventType.RoomName) assertThat(RustStateEventType.RoomPinnedEvents.map()).isEqualTo(StateEventType.RoomPinnedEvents) + assertThat(RustStateEventType.RoomPolicy.map()).isEqualTo(StateEventType.RoomPolicy) assertThat(RustStateEventType.RoomPowerLevels.map()).isEqualTo(StateEventType.RoomPowerLevels) assertThat(RustStateEventType.RoomServerAcl.map()).isEqualTo(StateEventType.RoomServerAcl) assertThat(RustStateEventType.RoomThirdPartyInvite.map()).isEqualTo(StateEventType.RoomThirdPartyInvite) @@ -37,7 +40,8 @@ class StateEventTypeTest { assertThat(RustStateEventType.RoomTopic.map()).isEqualTo(StateEventType.RoomTopic) assertThat(RustStateEventType.SpaceChild.map()).isEqualTo(StateEventType.SpaceChild) assertThat(RustStateEventType.SpaceParent.map()).isEqualTo(StateEventType.SpaceParent) - assertThat(RustStateEventType.Custom("foo").map()).isEqualTo(StateEventType.Custom("foo")) + // Can't test Custom as it will try calling the Rust code, which is not available in unit tests + // assertThat(stateEventTypeFromString("foo").map()).isEqualTo(StateEventType.Custom("foo")) } @Test @@ -53,9 +57,10 @@ class StateEventTypeTest { assertThat(StateEventType.RoomGuestAccess.map()).isEqualTo(RustStateEventType.RoomGuestAccess) assertThat(StateEventType.RoomHistoryVisibility.map()).isEqualTo(RustStateEventType.RoomHistoryVisibility) assertThat(StateEventType.RoomJoinRules.map()).isEqualTo(RustStateEventType.RoomJoinRules) - assertThat(StateEventType.RoomMemberEvent.map()).isEqualTo(RustStateEventType.RoomMemberEvent) + assertThat(StateEventType.RoomMemberEvent.map()).isEqualTo(RustStateEventType.RoomMember) assertThat(StateEventType.RoomName.map()).isEqualTo(RustStateEventType.RoomName) assertThat(StateEventType.RoomPinnedEvents.map()).isEqualTo(RustStateEventType.RoomPinnedEvents) + assertThat(StateEventType.RoomPolicy.map()).isEqualTo(RustStateEventType.RoomPolicy) assertThat(StateEventType.RoomPowerLevels.map()).isEqualTo(RustStateEventType.RoomPowerLevels) assertThat(StateEventType.RoomServerAcl.map()).isEqualTo(RustStateEventType.RoomServerAcl) assertThat(StateEventType.RoomThirdPartyInvite.map()).isEqualTo(RustStateEventType.RoomThirdPartyInvite) @@ -63,6 +68,7 @@ class StateEventTypeTest { assertThat(StateEventType.RoomTopic.map()).isEqualTo(RustStateEventType.RoomTopic) assertThat(StateEventType.SpaceChild.map()).isEqualTo(RustStateEventType.SpaceChild) assertThat(StateEventType.SpaceParent.map()).isEqualTo(RustStateEventType.SpaceParent) - assertThat(StateEventType.Custom("foo").map()).isEqualTo(RustStateEventType.Custom("foo")) + // Can't test Custom as it will try calling the Rust code, which is not available in unit tests + // assertThat(StateEventType.Custom("foo").map()).isEqualTo(stateEventTypeFromString("foo")) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/storage/FakeSqliteStoreBuilderProvider.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/storage/FakeSqliteStoreBuilderProvider.kt index b196604ca4..af68da7b8a 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/storage/FakeSqliteStoreBuilderProvider.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/storage/FakeSqliteStoreBuilderProvider.kt @@ -7,7 +7,7 @@ package io.element.android.libraries.matrix.impl.storage -import io.element.android.libraries.matrix.impl.paths.SessionPaths +import io.element.android.libraries.matrix.api.paths.SessionPaths class FakeSqliteStoreBuilderProvider : SqliteStoreBuilderProvider { override fun provide(sessionPaths: SessionPaths): SqliteStoreBuilder { diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapperTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapperTest.kt new file mode 100644 index 0000000000..c74f67bfe6 --- /dev/null +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapperTest.kt @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.timeline.item.event + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.room.location.AssetType +import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustAudioMessageContent +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustFileMessageContent +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustGalleryItemTypeAudio +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustGalleryItemTypeFile +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustGalleryItemTypeImage +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustGalleryItemTypeOther +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustGalleryItemTypeVideo +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustGalleryMessageContent +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustImageMessageContent +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustMessageTypeGallery +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustVideoMessageContent +import org.junit.Test +import org.matrix.rustcomponents.sdk.EmoteMessageContent +import org.matrix.rustcomponents.sdk.LocationContent +import org.matrix.rustcomponents.sdk.MessageType +import org.matrix.rustcomponents.sdk.NoticeMessageContent +import org.matrix.rustcomponents.sdk.TextMessageContent +import org.matrix.rustcomponents.sdk.UnstableVoiceContent +import org.matrix.rustcomponents.sdk.AssetType as RustAssetType + +class EventMessageMapperTest { + private val sut = EventMessageMapper() + + @Test + fun `mapMessageType with Text returns TextMessageType`() { + val result = sut.mapMessageType( + MessageType.Text( + content = TextMessageContent(body = "Hello", formatted = null) + ) + ) + assertThat(result).isEqualTo(TextMessageType(body = "Hello", formatted = null)) + } + + @Test + fun `mapMessageType with Notice returns NoticeMessageType`() { + val result = sut.mapMessageType( + MessageType.Notice(content = NoticeMessageContent(body = "A notice", formatted = null)) + ) + assertThat(result).isEqualTo(NoticeMessageType(body = "A notice", formatted = null)) + } + + @Test + fun `mapMessageType with Emote returns EmoteMessageType`() { + val result = sut.mapMessageType( + MessageType.Emote(content = EmoteMessageContent(body = "An emote", formatted = null)) + ) + assertThat(result).isEqualTo(EmoteMessageType(body = "An emote", formatted = null)) + } + + @Test + fun `mapMessageType with Other returns OtherMessageType`() { + val result = sut.mapMessageType( + MessageType.Other(msgtype = "m.custom", body = "custom body") + ) + assertThat(result).isEqualTo(OtherMessageType(msgType = "m.custom", body = "custom body")) + } + + @Test + fun `mapMessageType with Location returns LocationMessageType`() { + val result = sut.mapMessageType( + MessageType.Location( + content = LocationContent( + body = "Location body", + geoUri = "geo:51.5,-0.1", + description = "London", + zoomLevel = null, + asset = RustAssetType.PIN, + ) + ) + ) + assertThat(result).isEqualTo( + LocationMessageType( + body = "Location body", + geoUri = "geo:51.5,-0.1", + description = "London", + assetType = AssetType.PIN, + ) + ) + } + + @Test + fun `mapMessageType with Audio without voice returns AudioMessageType`() { + val result = sut.mapMessageType( + MessageType.Audio(content = aRustAudioMessageContent(filename = "audio.mp3", voice = null)) + ) + assertThat(result).isEqualTo( + AudioMessageType( + filename = "audio.mp3", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/audio", json = """{"url":"mxc://server/audio"}"""), + info = null, + ) + ) + } + + @Test + fun `mapMessageType with Audio with voice returns VoiceMessageType`() { + val result = sut.mapMessageType( + MessageType.Audio(content = aRustAudioMessageContent(filename = "voice.ogg", voice = UnstableVoiceContent())) + ) + assertThat(result).isEqualTo( + VoiceMessageType( + filename = "voice.ogg", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/audio", json = """{"url":"mxc://server/audio"}"""), + info = null, + details = null, + ) + ) + } + + @Test + fun `mapMessageType with File returns FileMessageType`() { + val result = sut.mapMessageType( + MessageType.File(content = aRustFileMessageContent(filename = "document.pdf")) + ) + assertThat(result).isEqualTo( + FileMessageType( + filename = "document.pdf", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/file", json = """{"url":"mxc://server/file"}"""), + info = null, + ) + ) + } + + @Test + fun `mapMessageType with Image returns ImageMessageType`() { + val result = sut.mapMessageType( + MessageType.Image(content = aRustImageMessageContent(filename = "image.jpg")) + ) + assertThat(result).isEqualTo( + ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/image", json = """{"url":"mxc://server/image"}"""), + info = null, + ) + ) + } + + @Test + fun `mapMessageType with Video returns VideoMessageType`() { + val result = sut.mapMessageType( + MessageType.Video(content = aRustVideoMessageContent(filename = "video.mp4")) + ) + assertThat(result).isEqualTo( + VideoMessageType( + filename = "video.mp4", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/video", json = """{"url":"mxc://server/video"}"""), + info = null, + ) + ) + } + + @Test + fun `mapMessageType with Gallery with Image item returns GalleryMessageType with Image`() { + val result = sut.mapMessageType( + aRustMessageTypeGallery( + content = aRustGalleryMessageContent( + body = "A gallery", + itemTypes = listOf(aRustGalleryItemTypeImage(aRustImageMessageContent(filename = "image.jpg"))), + ) + ) + ) + assertThat(result).isEqualTo( + GalleryMessageType( + body = "A gallery", + formatted = null, + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/image", json = """{"url":"mxc://server/image"}"""), + info = null, + ) + ) + ), + ) + ) + } + + @Test + fun `mapMessageType with Gallery with Audio item returns GalleryMessageType with Audio`() { + val result = sut.mapMessageType( + aRustMessageTypeGallery( + content = aRustGalleryMessageContent( + itemTypes = listOf(aRustGalleryItemTypeAudio(aRustAudioMessageContent(filename = "audio.mp3"))) + ) + ) + ) + assertThat(result).isEqualTo( + GalleryMessageType( + body = "A gallery", + formatted = null, + items = listOf( + GalleryItemType.Audio( + content = AudioMessageType( + filename = "audio.mp3", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/audio", json = """{"url":"mxc://server/audio"}"""), + info = null, + ) + ) + ), + ) + ) + } + + @Test + fun `mapMessageType with Gallery with Video item returns GalleryMessageType with Video`() { + val result = sut.mapMessageType( + aRustMessageTypeGallery( + content = aRustGalleryMessageContent( + itemTypes = listOf(aRustGalleryItemTypeVideo(aRustVideoMessageContent(filename = "video.mp4"))) + ) + ) + ) + assertThat(result).isEqualTo( + GalleryMessageType( + body = "A gallery", + formatted = null, + items = listOf( + GalleryItemType.Video( + content = VideoMessageType( + filename = "video.mp4", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/video", json = """{"url":"mxc://server/video"}"""), + info = null, + ) + ) + ), + ) + ) + } + + @Test + fun `mapMessageType with Gallery with File item returns GalleryMessageType with File`() { + val result = sut.mapMessageType( + aRustMessageTypeGallery( + content = aRustGalleryMessageContent( + itemTypes = listOf(aRustGalleryItemTypeFile(aRustFileMessageContent(filename = "document.pdf"))) + ) + ) + ) + assertThat(result).isEqualTo( + GalleryMessageType( + body = "A gallery", + formatted = null, + items = listOf( + GalleryItemType.File( + content = FileMessageType( + filename = "document.pdf", + caption = null, + formattedCaption = null, + source = MediaSource(url = "mxc://server/file", json = """{"url":"mxc://server/file"}"""), + info = null, + ) + ) + ), + ) + ) + } + + @Test + fun `mapMessageType with Gallery with Other item returns GalleryMessageType with Other`() { + val result = sut.mapMessageType( + aRustMessageTypeGallery( + content = aRustGalleryMessageContent( + itemTypes = listOf(aRustGalleryItemTypeOther(itemType = "m.custom", body = "custom item")) + ) + ) + ) + assertThat(result).isEqualTo( + GalleryMessageType( + body = "A gallery", + formatted = null, + items = listOf( + GalleryItemType.Other(itemType = "m.custom", body = "custom item") + ), + ) + ) + } +} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterEmptyDayPostProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterEmptyDayPostProcessorTest.kt deleted file mode 100644 index 7a3a091f4e..0000000000 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterEmptyDayPostProcessorTest.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2026 Element Creations Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.timeline.postprocessor - -import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem -import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem -import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem -import org.junit.Test - -private const val TODAY = 1_779_779_967_000 -private const val YESTERDAY = TODAY - 24 * 60 * 60 * 1000 -private const val DAY_BEFORE_YESTERDAY = YESTERDAY - 24 * 60 * 60 * 1000 - -class FilterEmptyDayPostProcessorTest { - private val anEvent = MatrixTimelineItem.Event( - uniqueId = UniqueId("event"), - event = anEventTimelineItem(), - ) - - private fun aDaySeparator(timestmap: Long) = MatrixTimelineItem.Virtual( - uniqueId = UniqueId("day_$timestmap"), - virtual = VirtualTimelineItem.DayDivider(timestmap) - ) - - @Test - fun `filterEmptyDaySeparators keeps day separator with events after it`() { - val items = listOf( - anEvent, - aDaySeparator(TODAY), - ) - val result = FilterEmptyDayPostProcessor().process(items) - assertThat(result).hasSize(2) - assertThat(result[0]).isEqualTo(anEvent) - assertThat(result[1]).isEqualTo(aDaySeparator(TODAY)) - } - - @Test - fun `filterEmptyDaySeparators removes day separator with no events after it`() { - val items = listOf( - aDaySeparator(TODAY), - aDaySeparator(YESTERDAY), - ) - val result = FilterEmptyDayPostProcessor().process(items) - assertThat(result).isEmpty() - } - - @Test - fun `filterEmptyDaySeparators removes first day separator and keeps second when only second has events`() { - val items = listOf( - aDaySeparator(TODAY), - anEvent, - aDaySeparator(YESTERDAY), - ) - val result = FilterEmptyDayPostProcessor().process(items) - assertThat(result).hasSize(2) - assertThat(result[0]).isEqualTo(anEvent) - assertThat(result[1]).isEqualTo(aDaySeparator(YESTERDAY)) - } - - @Test - fun `filterEmptyDaySeparators handles multiple day separators in a row with no events`() { - val items = listOf( - aDaySeparator(TODAY), - aDaySeparator(YESTERDAY), - aDaySeparator(DAY_BEFORE_YESTERDAY), - ) - val result = FilterEmptyDayPostProcessor().process(items) - assertThat(result).isEmpty() - } - - @Test - fun `filterEmptyDaySeparators keeps all items when no day separators`() { - val items = listOf( - anEvent, - anEvent.copy(uniqueId = UniqueId("event2")), - ) - val result = FilterEmptyDayPostProcessor().process(items) - assertThat(result).hasSize(2) - } - - @Test - fun `filterEmptyDaySeparators removes day separator followed by non-event virtual item`() { - val readMarker = MatrixTimelineItem.Virtual( - uniqueId = UniqueId("readMarker"), - virtual = VirtualTimelineItem.ReadMarker - ) - val items = listOf( - aDaySeparator(TODAY), - readMarker, - ) - val result = FilterEmptyDayPostProcessor().process(items) - assertThat(result).hasSize(1) - assertThat(result[0]).isEqualTo(readMarker) - } - - @Test - fun `filterEmptyDaySeparators keeps day separator when non-event virtual items are between separator and event`() { - val readMarker = MatrixTimelineItem.Virtual( - uniqueId = UniqueId("readMarker"), - virtual = VirtualTimelineItem.ReadMarker - ) - val items = listOf( - anEvent, - readMarker, - aDaySeparator(TODAY), - ) - val result = FilterEmptyDayPostProcessor().process(items) - assertThat(result).hasSize(3) - assertThat(result[2]).isEqualTo(aDaySeparator(TODAY)) - } -} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterPublicMembershipChangesPostProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterPublicMembershipChangesPostProcessorTest.kt deleted file mode 100644 index dd899baf5b..0000000000 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/FilterPublicMembershipChangesPostProcessorTest.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2026 Element Creations Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.timeline.postprocessor - -import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.api.room.join.JoinRule -import org.junit.Test - -class FilterPublicMembershipChangesPostProcessorTest { - @Test - fun `processor removes join, leave, and profile events in unencrypted public rooms`() { - val timelineItems = listOf( - roomCreateEvent, - roomCreatorJoinEvent, - otherMemberJoinEvent, - messageEvent, - otherMemberLeaveEvent, - profileChangeEvent, - ) - val expected = listOf( - roomCreateEvent, - messageEvent, - ) - val processor = FilterPublicMembershipChangesPostProcessor() - val processedItems = processor.process( - timelineItems, - joinRule = JoinRule.Public, - isEncrypted = false, - ) - assertThat(processedItems).isEqualTo(expected) - } - - @Test - fun `processor keeps all events in encrypted public rooms`() { - val timelineItems = listOf( - roomCreateEvent, - roomCreatorJoinEvent, - otherMemberJoinEvent, - messageEvent, - otherMemberLeaveEvent, - profileChangeEvent, - ) - val processor = FilterPublicMembershipChangesPostProcessor() - val processedItems = processor.process( - timelineItems, - joinRule = JoinRule.Public, - isEncrypted = true, - ) - assertThat(processedItems).isEqualTo(timelineItems) - } - - @Test - fun `processor keeps membership events in invite-only rooms`() { - val timelineItems = listOf( - roomCreateEvent, - roomCreatorJoinEvent, - otherMemberJoinEvent, - messageEvent, - otherMemberLeaveEvent, - profileChangeEvent, - ) - val processor = FilterPublicMembershipChangesPostProcessor() - val processedItems = processor.process( - timelineItems, - joinRule = JoinRule.Invite, - isEncrypted = null, - ) - assertThat(processedItems).isEqualTo(timelineItems) - } -} diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/util/SessionPathsProviderTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/util/SessionPathsProviderTest.kt deleted file mode 100644 index 8edc95cdc6..0000000000 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/util/SessionPathsProviderTest.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2024, 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.util - -import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.test.A_SESSION_ID -import io.element.android.libraries.sessionstorage.test.InMemorySessionStore -import io.element.android.libraries.sessionstorage.test.aSessionData -import kotlinx.coroutines.test.runTest -import org.junit.Test - -class SessionPathsProviderTest { - @Test - fun `if session is not found, provides returns null`() = runTest { - val sut = SessionPathsProvider(InMemorySessionStore()) - val result = sut.provides(A_SESSION_ID) - assertThat(result).isNull() - } - - @Test - fun `if session is found, provides returns the data`() = runTest { - val store = InMemorySessionStore( - initialList = listOf( - aSessionData( - sessionPath = "/a/path/to/a/session", - cachePath = "/a/path/to/a/cache", - ) - ) - ) - val sut = SessionPathsProvider(store) - val result = sut.provides(A_SESSION_ID)!! - assertThat(result.fileDirectory.absolutePath).isEqualTo("/a/path/to/a/session") - assertThat(result.cacheDirectory.absolutePath).isEqualTo("/a/path/to/a/cache") - } -} diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 3278eae855..2397f12443 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.api.media.MediaPreviewService import io.element.android.libraries.matrix.api.notification.NotificationService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.oauth.AccountManagementAction +import io.element.android.libraries.matrix.api.paths.SessionPaths import io.element.android.libraries.matrix.api.pusher.PushersService import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -66,10 +67,12 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope +import java.io.File import java.util.Optional class FakeMatrixClient( override val sessionId: SessionId = A_SESSION_ID, + override val sessionPaths: SessionPaths = SessionPaths(fileDirectory = File("files"), cacheDirectory = File("cache")), override val deviceId: DeviceId = A_DEVICE_ID, override val sessionCoroutineScope: CoroutineScope = TestScope(), private val userDisplayName: String? = A_USER_NAME, @@ -114,6 +117,7 @@ class FakeMatrixClient( private val getRecentEmojisLambda: () -> Result> = { Result.success(emptyList()) }, private val addRecentEmojiLambda: (String) -> Result = { Result.success(Unit) }, private val markRoomAsFullyReadResult: (RoomId, EventId) -> Result = { _, _ -> lambdaError() }, + private val markAllRoomsAsReadResult: () -> Result = { Result.success(Unit) }, private val performDatabaseVacuumLambda: () -> Result = { lambdaError() }, private val getMapStyleUrlResult: () -> Result = { lambdaError() }, private val getDatabaseSizesLambda: () -> Result = { lambdaError() }, @@ -370,6 +374,10 @@ class FakeMatrixClient( return markRoomAsFullyReadResult(roomId, eventId) } + override suspend fun markAllRoomsAsRead(): Result { + return markAllRoomsAsReadResult() + } + override suspend fun performDatabaseVacuum(): Result { return performDatabaseVacuumLambda() } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeEncryptionService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeEncryptionService.kt index 04e3779298..e090319821 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeEncryptionService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeEncryptionService.kt @@ -28,7 +28,8 @@ class FakeEncryptionService( private val pinUserIdentityResult: (UserId) -> Result = { lambdaError() }, private val withdrawVerificationResult: (UserId) -> Result = { lambdaError() }, private val getUserIdentityResult: (UserId) -> Result = { lambdaError() }, - private val enableRecoveryLambda: (Boolean) -> Result = { lambdaError() }, + private val enableRecoveryLambda: (Boolean, String?) -> Result = { _, _ -> lambdaError() }, + private val resetRecoveryKeyLambda: () -> Result = { Result.success(FAKE_RECOVERY_KEY) }, ) : EncryptionService { private var disableRecoveryFailure: Exception? = null override val backupStateStateFlow: MutableStateFlow = MutableStateFlow(BackupState.UNKNOWN) @@ -90,11 +91,11 @@ class FakeEncryptionService( } override suspend fun resetRecoveryKey(): Result = simulateLongTask { - return Result.success(FAKE_RECOVERY_KEY) + return resetRecoveryKeyLambda() } - override suspend fun enableRecovery(waitForBackupsToUpload: Boolean): Result = simulateLongTask { - return enableRecoveryLambda(waitForBackupsToUpload) + override suspend fun enableRecovery(waitForBackupsToUpload: Boolean, passphrase: String?): Result = simulateLongTask { + return enableRecoveryLambda(waitForBackupsToUpload, passphrase) } fun givenWaitForBackupUploadSteadyStateFlow(flow: Flow) { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt index 5ea2de888b..8f5d626b13 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt @@ -186,10 +186,6 @@ class FakeBaseRoom( membersStateFlow.value = state } - override suspend fun clearEventCacheStorage(): Result { - return Result.success(Unit) - } - override suspend fun reportRoom(reason: String?) = reportRoomResult(reason) override suspend fun declineCall(notificationEventId: EventId): Result { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt index b4425ddd4b..dd8acacb23 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt @@ -92,6 +92,7 @@ class FakeJoinedRoom( private val startLiveLocationShareResult: (Long) -> Result = { lambdaError() }, private val stopLiveLocationShareResult: () -> Result = { lambdaError() }, private val sendLiveLocationResult: (String) -> Result = { lambdaError() }, + private val setOwnMemberDisplayNameResult: (String) -> Result = { lambdaError() }, ) : JoinedRoom, BaseRoom by baseRoom { private val sendQueueUpdates = MutableSharedFlow(extraBufferCapacity = 10) @@ -255,6 +256,10 @@ class FakeJoinedRoom( sendLiveLocationResult(geoUri) } + override suspend fun setOwnMemberDisplayName(displayName: String): Result = simulateLongTask { + setOwnMemberDisplayNameResult(displayName) + } + private suspend fun simulateSendMediaProgress(progressCallback: ProgressCallback?) { progressCallbackValues.forEach { (current, total) -> progressCallback?.onProgress(current, total) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt index fcc7057dbe..d13ac06bd3 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeTimeline.kt @@ -13,6 +13,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo +import io.element.android.libraries.matrix.api.media.GalleryItemInfo import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo @@ -293,6 +294,29 @@ class FakeTimeline( ) } + var sendGalleryLambda: ( + items: List, + caption: String?, + formattedCaption: String?, + inReplyToEventId: EventId?, + ) -> Result = { _, _, _, _ -> + Result.success(FakeMediaUploadHandler()) + } + + override suspend fun sendGallery( + items: List, + caption: String?, + formattedCaption: String?, + inReplyToEventId: EventId?, + ): Result = simulateLongTask { + sendGalleryLambda( + items, + caption, + formattedCaption, + inReplyToEventId, + ) + } + var sendLocationLambda: ( body: String, geoUri: String, @@ -436,6 +460,9 @@ class FakeTimeline( override suspend fun loadReplyDetails(eventId: EventId) = loadReplyDetailsLambda(eventId) + var isEventLoadedLambda: (eventId: EventId) -> Boolean = { false } + override suspend fun isEventLoaded(eventId: EventId): Boolean = isEventLoadedLambda(eventId) + var pinEventLambda: (eventId: EventId) -> Result = { lambdaError() } override suspend fun pinEvent(eventId: EventId): Result { return pinEventLambda(eventId) diff --git a/libraries/matrixmedia/impl/src/test/kotlin/io/element/android/libraries/matrix/ui/media/DefaultImageLoaderHolderTest.kt b/libraries/matrixmedia/impl/src/test/kotlin/io/element/android/libraries/matrix/ui/media/DefaultImageLoaderHolderTest.kt index dd9127a4ae..2bb1ddcae4 100644 --- a/libraries/matrixmedia/impl/src/test/kotlin/io/element/android/libraries/matrix/ui/media/DefaultImageLoaderHolderTest.kt +++ b/libraries/matrixmedia/impl/src/test/kotlin/io/element/android/libraries/matrix/ui/media/DefaultImageLoaderHolderTest.kt @@ -19,13 +19,11 @@ import io.element.android.libraries.sessionstorage.test.observer.FakeSessionObse import io.element.android.libraries.sessionstorage.test.observer.NoOpSessionObserver import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultImageLoaderHolderTest { +class DefaultImageLoaderHolderTest : RobolectricTest() { @Test fun `get - returns the same ImageLoader for the same client`() { val context = InstrumentationRegistry.getInstrumentation().context diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt index 880a7a9df6..5a9e56829c 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt @@ -18,7 +18,8 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -47,8 +48,9 @@ fun AvatarActionBottomSheet( modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() - val sheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true + val sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), ) BackHandler(enabled = isVisible) { @@ -104,7 +106,7 @@ private fun AvatarActionBottomSheetContent( leadingContent = ListItemContent.Icon(IconSource.Resource(action.iconResourceId)), style = when { action.destructive -> ListItemStyle.Destructive - else -> ListItemStyle.Primary + else -> ListItemStyle.Default } ) } @@ -113,7 +115,7 @@ private fun AvatarActionBottomSheetContent( @PreviewsDayNight @Composable -internal fun AvatarActionBottomSheetPreview() = ElementPreview { +internal fun AvatarActionBottomSheetPreview() = ElementPreview(fillMaxSize = true) { AvatarActionBottomSheet( actions = persistentListOf(AvatarAction.TakePhoto, AvatarAction.ChoosePhoto, AvatarAction.Remove), isVisible = true, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt index d663177ee6..598d7f2ca7 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt @@ -17,8 +17,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.SheetValue import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.rememberBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -75,7 +76,10 @@ fun CreateDmConfirmationBottomSheet( ModalBottomSheet( modifier = modifier, onDismissRequest = onDismiss, - sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + sheetState = rememberBottomSheetState( + initialValue = SheetValue.Hidden, + enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded), + ), scrollable = false, ) { Column( @@ -156,7 +160,7 @@ internal fun CreateDmConfirmationBottomSheetPreview( @PreviewParameter( CreateDmConfirmationBottomSheetStateProvider::class ) state: CreateDmConfirmationBottomSheetState -) = ElementPreview { +) = ElementPreview(fillMaxSize = true) { CreateDmConfirmationBottomSheet( matrixUser = state.matrixUser, isUserIdentityUnknown = state.isUserIdentityUnknown, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt index 4d79018e88..d3824f9eec 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt @@ -78,7 +78,7 @@ fun SpaceRoomItemView( indication = ripple(), interactionSource = remember { MutableInteractionSource() } ) - .onKeyboardContextMenuAction { onLongClick } + .onKeyboardContextMenuAction(onLongClick) Column( modifier = modifier .then(clickModifier) diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt index 098117af74..f09447a083 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.BaseRoom @@ -42,10 +43,8 @@ fun getRoomMemberAsState(roomMembersState: RoomMembersState, userId: UserId): St @Composable fun BaseRoom.getDirectRoomMember(roomMembersState: RoomMembersState): State { val roomInfo by roomInfoFlow.collectAsState() - return remember { - derivedStateOf { - roomMembersState.getDirectRoomMember(roomInfo, sessionId) - } + return remember(roomInfo.isDm) { + mutableStateOf(roomMembersState.getDirectRoomMember(roomInfo, sessionId)) } } diff --git a/libraries/matrixui/src/main/res/values-el/translations.xml b/libraries/matrixui/src/main/res/values-el/translations.xml index 9e9f195464..a1d8da5a56 100644 --- a/libraries/matrixui/src/main/res/values-el/translations.xml +++ b/libraries/matrixui/src/main/res/values-el/translations.xml @@ -3,5 +3,7 @@ "Αποστολή πρόσκλησης" "Θα θέλατε να ξεκινήσετε μια συνομιλία με τον χρήστη %1$s;" "Αποστολή πρόσκλησης;" + "Προς το παρόν δεν έχετε καμία συνομιλία με αυτό το άτομο. Επιβεβαιώστε την πρόσκλησή του πριν συνεχίσετε." + "Έναρξη συνομιλίας με αυτήν τη νέα επαφή;" "%1$s (%2$s) σέ προσκάλεσε" diff --git a/libraries/matrixui/src/main/res/values-ko/translations.xml b/libraries/matrixui/src/main/res/values-ko/translations.xml index 09d831e348..b36a61cf9b 100644 --- a/libraries/matrixui/src/main/res/values-ko/translations.xml +++ b/libraries/matrixui/src/main/res/values-ko/translations.xml @@ -3,5 +3,7 @@ "초대장 보내기" "%1$s 와 채팅을 시작하시겠습니까?" "초대장을 보내시겠습니까?" + "이 사용자와의 대화 내역이 없습니다. 계속하려면 먼저 초대를 확인해 주세요." + "이 사용자와 대화를 시작하시겠습니까?" "%1$s (%2$s) 당신을 초대했습니다" diff --git a/libraries/matrixui/src/main/res/values-ru/translations.xml b/libraries/matrixui/src/main/res/values-ru/translations.xml index 8f01b9ee7f..77b3c6454e 100644 --- a/libraries/matrixui/src/main/res/values-ru/translations.xml +++ b/libraries/matrixui/src/main/res/values-ru/translations.xml @@ -5,5 +5,5 @@ "Отправить приглашение?" "У Вас нет других чатов с этим пользователем. Подтвердите, что это действительно кого Вы хотите пригласить, прежде чем продолжить." "Начать чат с этим новым контактом?" - "%1$s (%2$s) пригласил(а) вас" + "%1$s (%2$s) пригласил(а) Вас" diff --git a/libraries/matrixui/src/main/res/values-uk/translations.xml b/libraries/matrixui/src/main/res/values-uk/translations.xml index 4d2063fbd2..8217097cd2 100644 --- a/libraries/matrixui/src/main/res/values-uk/translations.xml +++ b/libraries/matrixui/src/main/res/values-uk/translations.xml @@ -3,7 +3,7 @@ "Надіслати запрошення" "Хочете розпочати бесіду з %1$s?" "Надіслати запрошення?" - "Наразі у вас немає чатів із цим користувачем. Підтвердьте запрошення, перш ніж продовжити." - "Розпочати чат із цим новим контактом?" + "Наразі у вас немає бесід з цим користувачем. Підтвердьте запрошення, перш ніж продовжити." + "Розпочати бесіду з цим новим контактом?" "%1$s (%2$s) запрошує вас" diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocumentTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocumentTest.kt index ad427999e2..ae336cd0d0 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocumentTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocumentTest.kt @@ -16,12 +16,10 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class ToHtmlDocumentTest { +class ToHtmlDocumentTest : RobolectricTest() { @Test fun `toHtmlDocument - returns null if format is not HTML`() { val body = FormattedBody( diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt index ce0ef4cf31..b1031176e7 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt @@ -13,13 +13,11 @@ import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.jsoup.Jsoup import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class ToPlainTextTest { +class ToPlainTextTest : RobolectricTest() { @Test fun `Document toPlainText - returns a plain text version of the document`() { val document = Jsoup.parse( diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt index 5c7fdfaac8..0847315867 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.matrix.ui.messages.reply -import androidx.test.ext.junit.runners.AndroidJUnit4 import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test @@ -47,14 +46,13 @@ import io.element.android.libraries.matrix.test.timeline.item.event.aRoomMembers import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.withConfigurationAndContext import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith import kotlin.time.Duration.Companion.minutes -@RunWith(AndroidJUnit4::class) -class InReplyToMetadataKtTest { +class InReplyToMetadataKtTest : RobolectricTest() { @Test fun `any message content`() = runTest { moleculeFlow(RecompositionMode.Immediate) { diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/MatrixUserExtensionsTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/MatrixUserExtensionsTest.kt index dd9d801210..035548a4ec 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/MatrixUserExtensionsTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/MatrixUserExtensionsTest.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.matrix.ui.model -import androidx.test.ext.junit.runners.AndroidJUnit4 import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test @@ -18,14 +17,13 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.withConfigurationAndContext import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class MatrixUserExtensionsTest { +class MatrixUserExtensionsTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt index 7ae35e8218..1bab693609 100644 --- a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt +++ b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerProvider.kt @@ -23,12 +23,23 @@ interface PickerProvider { onResult: (Uri?) -> Unit ): PickerLauncher + @Composable + fun registerGalleryMultiPicker( + onResult: (uris: List) -> Unit + ): PickerLauncher> + @Composable fun registerFilePicker( mimeType: String, onResult: (uri: Uri?, mimeType: String?) -> Unit, ): PickerLauncher + @Composable + fun registerFileMultiPicker( + mimeType: String, + onResult: (uris: List) -> Unit, + ): PickerLauncher, List> + @Composable fun registerCameraPhotoPicker(onResult: (Uri?) -> Unit): PickerLauncher diff --git a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt index 9c69e6448b..da84a66f49 100644 --- a/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt +++ b/libraries/mediapickers/api/src/main/kotlin/io/element/android/libraries/mediapickers/api/PickerType.kt @@ -15,6 +15,9 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Immutable import io.element.android.libraries.core.mimetype.MimeTypes +// As per MSC4274, the recommended item cap is 60. +private const val MAX_GALLERY_ITEMS = 60 + @Immutable sealed interface PickerType { fun getContract(): ActivityResultContract @@ -34,6 +37,13 @@ sealed interface PickerType { } } + data object ImageAndVideoMulti : PickerType> { + override fun getContract() = ActivityResultContracts.PickMultipleVisualMedia(MAX_GALLERY_ITEMS) + override fun getDefaultRequest(): PickVisualMediaRequest { + return PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo) + } + } + object Camera { data class Photo(val destUri: Uri) : PickerType { override fun getContract() = ActivityResultContracts.TakePicture() @@ -56,4 +66,13 @@ sealed interface PickerType { return mimeType } } + + data class FileMulti(val mimeType: String = MimeTypes.Any) : PickerType, List> { + override fun getContract(): ActivityResultContract, List> { + return ActivityResultContracts.OpenMultipleDocuments() + } + override fun getDefaultRequest(): Array { + return arrayOf(mimeType) + } + } } diff --git a/libraries/mediapickers/api/src/test/kotlin/io/element/android/libraries/mediapickers/PickerTypeTest.kt b/libraries/mediapickers/api/src/test/kotlin/io/element/android/libraries/mediapickers/PickerTypeTest.kt index 6c7dbb7db7..752398f7c4 100644 --- a/libraries/mediapickers/api/src/test/kotlin/io/element/android/libraries/mediapickers/PickerTypeTest.kt +++ b/libraries/mediapickers/api/src/test/kotlin/io/element/android/libraries/mediapickers/PickerTypeTest.kt @@ -13,12 +13,10 @@ import androidx.activity.result.contract.ActivityResultContracts import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.mediapickers.api.PickerType +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class PickerTypeTest { +class PickerTypeTest : RobolectricTest() { @Test fun `ImageAndVideo - assert types`() { val pickerType = PickerType.ImageAndVideo diff --git a/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/DefaultPickerProvider.kt b/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/DefaultPickerProvider.kt index 1b3df9c426..45ac408d42 100644 --- a/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/DefaultPickerProvider.kt +++ b/libraries/mediapickers/impl/src/main/kotlin/io/element/android/libraries/mediapickers/impl/DefaultPickerProvider.kt @@ -80,6 +80,23 @@ class DefaultPickerProvider( } } + /** + * Remembers and returns a [PickerLauncher] for selecting multiple gallery items (images/videos). + * [onResult] will be called with the list of selected file [Uri]s. + */ + @Composable + override fun registerGalleryMultiPicker( + onResult: (uris: List) -> Unit + ): PickerLauncher> { + return if (LocalInspectionMode.current) { + NoOpPickerLauncher { onResult(emptyList()) } + } else { + rememberPickerLauncher(type = PickerType.ImageAndVideoMulti) { uris -> + onResult(uris) + } + } + } + /** * Remembers and returns a [PickerLauncher] for a file of a certain [mimeType] (any type of file, by default). * [onResult] will be called with either the selected file's [Uri] or `null` if nothing was selected. @@ -100,6 +117,24 @@ class DefaultPickerProvider( } } + /** + * Remembers and returns a [PickerLauncher] for selecting multiple files of a certain [mimeType]. + * [onResult] will be called with the list of selected file URIs. + */ + @Composable + override fun registerFileMultiPicker( + mimeType: String, + onResult: (uris: List) -> Unit, + ): PickerLauncher, List> { + return if (LocalInspectionMode.current) { + NoOpPickerLauncher { onResult(emptyList()) } + } else { + rememberPickerLauncher(type = PickerType.FileMulti(mimeType)) { uris -> + onResult(uris) + } + } + } + /** * Remembers and returns a [PickerLauncher] for taking a photo with a camera app. * @param [onResult] will be called with either the photo's [Uri] or `null` if nothing was selected. @@ -113,7 +148,6 @@ class DefaultPickerProvider( val tmpFile = remember { getTemporaryFile("photo.jpg") } val tmpFileUri = remember(tmpFile) { getTemporaryUri(tmpFile) } rememberPickerLauncher(type = PickerType.Camera.Photo(tmpFileUri)) { success -> - // Execute callback onResult(if (success) tmpFileUri else null) } } @@ -125,7 +159,6 @@ class DefaultPickerProvider( */ @Composable override fun registerCameraVideoPicker(onResult: (Uri?) -> Unit): PickerLauncher { - // Tests and UI preview can't handle Context or FileProviders, so we might as well disable the whole picker return if (LocalInspectionMode.current) { NoOpPickerLauncher { onResult(null) } } else { diff --git a/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt b/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt index 98cbcec1ea..5d3be8acd1 100644 --- a/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt +++ b/libraries/mediapickers/test/src/main/kotlin/io/element/android/libraries/mediapickers/test/FakePickerProvider.kt @@ -30,11 +30,21 @@ class FakePickerProvider : PickerProvider { return NoOpPickerLauncher { onResult(result) } } + @Composable + override fun registerGalleryMultiPicker(onResult: (uris: List) -> Unit): PickerLauncher> { + return NoOpPickerLauncher { onResult(result?.let { listOf(it) } ?: emptyList()) } + } + @Composable override fun registerFilePicker(mimeType: String, onResult: (Uri?, String?) -> Unit): PickerLauncher { return NoOpPickerLauncher { onResult(result, this.mimeType) } } + @Composable + override fun registerFileMultiPicker(mimeType: String, onResult: (uris: List) -> Unit): PickerLauncher, List> { + return NoOpPickerLauncher { onResult(result?.let { listOf(it) } ?: emptyList()) } + } + @Composable override fun registerCameraPhotoPicker(onResult: (Uri?) -> Unit): PickerLauncher { return NoOpPickerLauncher { onResult(result) } diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt index 628e760c1e..6cca73935e 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt @@ -61,5 +61,12 @@ interface MediaSender { inReplyToEventId: EventId? = null, ): Result + suspend fun sendGallery( + mediaUploadInfos: List, + caption: String?, + formattedCaption: String?, + inReplyToEventId: EventId?, + ): Result + fun cleanUp() } diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt index f0082a4d1b..29adab2baf 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaUploadInfo.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.mediaupload.api import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo +import io.element.android.libraries.matrix.api.media.GalleryItemInfo import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.VideoInfo import java.io.File @@ -31,3 +32,30 @@ fun MediaUploadInfo.allFiles(): List { (this@allFiles as? MediaUploadInfo.Video)?.thumbnailFile, ) } + +fun MediaUploadInfo.toGalleryItemInfo(): GalleryItemInfo { + return when (this) { + is MediaUploadInfo.Image -> GalleryItemInfo.Image( + file = file, + imageInfo = imageInfo, + thumbnailFile = thumbnailFile, + ) + is MediaUploadInfo.Video -> GalleryItemInfo.Video( + file = file, + videoInfo = videoInfo, + thumbnailFile = thumbnailFile, + ) + is MediaUploadInfo.Audio -> GalleryItemInfo.Audio( + file = file, + audioInfo = audioInfo, + ) + is MediaUploadInfo.VoiceMessage -> GalleryItemInfo.Audio( + file = file, + audioInfo = audioInfo, + ) + is MediaUploadInfo.AnyFile -> GalleryItemInfo.MediaFile( + file = file, + fileInfo = fileInfo, + ) + } +} diff --git a/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSender.kt b/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSender.kt index ea2cac2951..37f77d11f8 100644 --- a/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSender.kt +++ b/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSender.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.mediaupload.api.MediaSender import io.element.android.libraries.mediaupload.api.MediaSenderFactory import io.element.android.libraries.mediaupload.api.MediaSenderRoomFactory import io.element.android.libraries.mediaupload.api.MediaUploadInfo +import io.element.android.libraries.mediaupload.api.toGalleryItemInfo import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import timber.log.Timber @@ -167,6 +168,29 @@ class DefaultMediaSender( .handleSendResult(mediaId(uri)) } + override suspend fun sendGallery( + mediaUploadInfos: List, + caption: String?, + formattedCaption: String?, + inReplyToEventId: EventId?, + ): Result { + val galleryLogId = "gallery[${mediaUploadInfos.size} items]" + Timber.d("Sending $galleryLogId") + return getTimeline().flatMap { timeline -> + val galleryItems = mediaUploadInfos.map { it.toGalleryItemInfo() } + timeline.sendGallery( + items = galleryItems, + caption = caption, + formattedCaption = formattedCaption, + inReplyToEventId = inReplyToEventId, + ) + } + .flatMapCatching { uploadHandler -> + uploadHandler.await() + } + .handleSendResult(galleryLogId) + } + private fun Result.handleSendResult(mediaId: String) = this .onFailure { error -> val job = ongoingUploadJobs.remove(Job) diff --git a/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/AndroidMediaPreProcessorTest.kt b/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/AndroidMediaPreProcessorTest.kt index 57726ac5a2..5a06781aaa 100644 --- a/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/AndroidMediaPreProcessorTest.kt +++ b/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/AndroidMediaPreProcessorTest.kt @@ -29,20 +29,18 @@ import io.element.android.libraries.preferences.api.store.VideoCompressionPreset import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider import io.element.android.tests.testutils.fake.FakeTemporaryUriDeleter import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Ignore import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import java.io.File import java.io.FileNotFoundException import java.io.IOException import kotlin.time.Duration -@RunWith(RobolectricTestRunner::class) -class AndroidMediaPreProcessorTest { +class AndroidMediaPreProcessorTest : RobolectricTest() { @Test fun `orientedImageDimensions swaps width and height for 90 degree exif orientation`() { val (width, height) = orientedImageDimensions( diff --git a/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSenderTest.kt b/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSenderTest.kt index 139042804f..cfa3585629 100644 --- a/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSenderTest.kt +++ b/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaSenderTest.kt @@ -25,18 +25,16 @@ import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import io.element.android.libraries.preferences.api.store.VideoCompressionPreset import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import java.io.File -@RunWith(RobolectricTestRunner::class) -class DefaultMediaSenderTest { +class DefaultMediaSenderTest : RobolectricTest() { private val mediaOptimizationConfig = MediaOptimizationConfig( compressImages = true, videoCompressionPreset = VideoCompressionPreset.STANDARD, diff --git a/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/VideoCompressorConfigFactoryTest.kt b/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/VideoCompressorConfigFactoryTest.kt index 041d05ae1e..6af0956541 100644 --- a/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/VideoCompressorConfigFactoryTest.kt +++ b/libraries/mediaupload/impl/src/test/kotlin/io/element/android/libraries/mediaupload/impl/VideoCompressorConfigFactoryTest.kt @@ -11,13 +11,10 @@ package io.element.android.libraries.mediaupload.impl import androidx.media3.transformer.VideoEncoderSettings import com.google.common.truth.Truth.assertThat import io.element.android.libraries.preferences.api.store.VideoCompressionPreset +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner - @Suppress("NOTHING_TO_INLINE") -@RunWith(RobolectricTestRunner::class) -class VideoCompressorConfigFactoryTest { +class VideoCompressorConfigFactoryTest : RobolectricTest() { @Test fun `if we don't have metadata the video will be resized`() { // Given diff --git a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaSender.kt b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaSender.kt index 1713f7b5ea..6ef8da4ab6 100644 --- a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaSender.kt +++ b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaSender.kt @@ -19,6 +19,7 @@ class FakeMediaSender( private val sendPreProcessedMediaResult: () -> Result = { lambdaError() }, private val sendMediaResult: () -> Result = { lambdaError() }, private val sendVoiceMessageResult: () -> Result = { lambdaError() }, + private val sendGalleryResult: () -> Result = { lambdaError() }, private val cleanUpResult: () -> Unit = { lambdaError() }, ) : MediaSender { override suspend fun preProcessMedia( @@ -58,6 +59,15 @@ class FakeMediaSender( return sendVoiceMessageResult() } + override suspend fun sendGallery( + mediaUploadInfos: List, + caption: String?, + formattedCaption: String?, + inReplyToEventId: EventId?, + ): Result { + return sendGalleryResult() + } + override fun cleanUp() { cleanUpResult() } diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/GalleryItemData.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/GalleryItemData.kt new file mode 100644 index 0000000000..3a2f2321db --- /dev/null +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/GalleryItemData.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.api + +import android.os.Parcelable +import io.element.android.libraries.matrix.api.media.MediaSource +import kotlinx.parcelize.Parcelize + +@Parcelize +data class GalleryItemData( + val filename: String, + val mimeType: String, + val mediaSource: MediaSource, + val thumbnailSource: MediaSource?, + val type: Type, +) : Parcelable { + enum class Type { + Image, + Video, + Audio, + File, + } +} diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt index fedf376a60..6d70747a07 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaInfo.kt @@ -13,6 +13,23 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.core.UserId import kotlinx.parcelize.Parcelize +@Parcelize +data class GalleryInfo( + val caption: String?, + val formattedCaption: CharSequence? = null, + val senderId: UserId?, + val senderName: String?, + val senderAvatar: String?, + val dateSent: String?, + val dateSentFull: String?, + val initialIndex: Int, +) : Parcelable + +@Parcelize +data class AvatarInfo( + val filename: String, +) : Parcelable + @Parcelize data class MediaInfo( val filename: String, @@ -103,6 +120,30 @@ fun aPdfMediaInfo( duration = null, ) +fun aZipMediaInfo( + filename: String = "a zip file.zip", + caption: String? = null, + formattedCaption: CharSequence? = null, + senderName: String? = null, + dateSent: String? = null, + dateSentFull: String? = null, +): MediaInfo = MediaInfo( + filename = filename, + fileSize = 12 * 1024 * 1024, + caption = caption, + formattedCaption = formattedCaption, + mimeType = MimeTypes.Pdf, + formattedFileSize = "45MB", + fileExtension = "zip", + senderId = UserId("@alice:server.org"), + senderName = senderName, + senderAvatar = null, + dateSent = dateSent, + dateSentFull = dateSentFull, + waveform = null, + duration = null, +) + fun anApkMediaInfo( senderId: UserId? = UserId("@alice:server.org"), senderName: String? = null, diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt index 536930b968..f6de6cf839 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt @@ -35,18 +35,32 @@ interface MediaViewerEntryPoint : FeatureEntryPoint { fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) } - data class Params( - val mode: MediaViewerMode, - val eventId: EventId?, - val mediaInfo: MediaInfo, - val mediaSource: MediaSource, - val thumbnailSource: MediaSource?, - val canShowInfo: Boolean, - ) : NodeInputs + sealed interface Params : NodeInputs { + data class RoomMedia( + val mode: MediaViewerMode, + val eventId: EventId?, + val mediaInfo: MediaInfo, + val mediaSource: MediaSource, + val thumbnailSource: MediaSource?, + ) : Params + + data class EventGallery( + val eventId: EventId?, + val galleryInfo: GalleryInfo, + val galleryItems: List, + val fromPinnedMessages: Boolean, + ) : Params + + data class Avatar( + val avatarInfo: AvatarInfo, + val mediaSource: MediaSource, + val thumbnailSource: MediaSource?, + ) : Params + } sealed interface MediaViewerMode : Parcelable { @Parcelize - data object SingleMedia : MediaViewerMode + data class EventGallery(val fromPinnedMessages: Boolean) : MediaViewerMode @Parcelize data class TimelineImagesAndVideos(val timelineMode: Timeline.Mode) : MediaViewerMode diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/helper/FileExtensionAndSizeFormatter.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/helper/FileExtensionAndSizeFormatter.kt index fc40bca8dd..e546f50565 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/helper/FileExtensionAndSizeFormatter.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/helper/FileExtensionAndSizeFormatter.kt @@ -12,8 +12,8 @@ fun formatFileExtensionAndSize(extension: String, size: String?): String { return buildString { append(extension.uppercase()) if (size != null) { - append(' ') - append("($size)") + append(" • ") + append(size) } } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt index 138f6382d2..10858c76c8 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt @@ -13,40 +13,20 @@ import com.bumble.appyx.core.node.Node import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import io.element.android.libraries.architecture.createNode -import io.element.android.libraries.core.mimetype.MimeTypes -import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.AvatarInfo import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.impl.viewer.MediaViewerNode @ContributesBinding(AppScope::class) class DefaultMediaViewerEntryPoint : MediaViewerEntryPoint { override fun createParamsForAvatar(filename: String, avatarUrl: String): MediaViewerEntryPoint.Params { - // We need to fake the MimeType here for the viewer to work. - val mimeType = MimeTypes.Images - return MediaViewerEntryPoint.Params( - mode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia, - eventId = null, - mediaInfo = MediaInfo( + return MediaViewerEntryPoint.Params.Avatar( + avatarInfo = AvatarInfo( filename = filename, - fileSize = null, - caption = null, - formattedCaption = null, - mimeType = mimeType, - formattedFileSize = "", - fileExtension = "", - senderId = UserId("@dummy:server.org"), - senderName = null, - senderAvatar = null, - dateSent = null, - dateSentFull = null, - waveform = null, - duration = null, ), mediaSource = MediaSource(url = avatarUrl), thumbnailSource = null, - canShowInfo = false, ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactory.kt index 898a29aa7a..05d5dd4022 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactory.kt @@ -13,6 +13,7 @@ import io.element.android.libraries.androidutils.filesize.FileSizeFormatter import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatterMode import io.element.android.libraries.dateformatter.api.toHumanReadableDuration +import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent @@ -20,6 +21,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageT import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInviteContent import io.element.android.libraries.matrix.api.timeline.item.event.LiveLocationContent @@ -54,7 +57,7 @@ class EventItemFactory( ) { fun create( currentTimelineItem: MatrixTimelineItem.Event, - ): MediaItem.Event? { + ): List { val event = currentTimelineItem.event val dateSent = dateFormatter.format( currentTimelineItem.event.timestamp, @@ -79,7 +82,7 @@ class EventItemFactory( is LiveLocationContent, UnknownContent -> { Timber.w("Should not happen: ${content.javaClass.simpleName}") - null + emptyList() } is MessageContent -> { when (val type = content.type) { @@ -89,9 +92,93 @@ class EventItemFactory( is LocationMessageType, is TextMessageType -> { Timber.w("Should not happen: ${content.type}") - null + emptyList() } - is AudioMessageType -> MediaItem.Audio( + is GalleryMessageType -> { + val baseId = currentTimelineItem.uniqueId.value + type.items.mapIndexedNotNull { index, galleryItem -> + val id = UniqueId("${baseId}_$index") + when (galleryItem) { + is GalleryItemType.Image -> { + val c = galleryItem.content + MediaItem.Image( + id = id, + eventId = currentTimelineItem.eventId, + mediaInfo = createMediaInfo( + filename = c.filename, + fileSize = c.info?.size, + caption = c.caption, + mimeType = c.info?.mimetype.orEmpty(), + fileExtension = c.filename, + event = event, + dateSent = dateSent, + dateSentFull = dateSentFull, + ), + mediaSource = c.source, + thumbnailSource = c.info?.thumbnailSource, + ) + } + is GalleryItemType.Video -> { + val c = galleryItem.content + MediaItem.Video( + id = id, + eventId = currentTimelineItem.eventId, + mediaInfo = createMediaInfo( + filename = c.filename, + fileSize = c.info?.size, + caption = c.caption, + mimeType = c.info?.mimetype.orEmpty(), + fileExtension = c.filename, + event = event, + dateSent = dateSent, + dateSentFull = dateSentFull, + duration = c.info?.duration?.inWholeMilliseconds?.toHumanReadableDuration(), + ), + mediaSource = c.source, + thumbnailSource = c.info?.thumbnailSource, + ) + } + is GalleryItemType.Audio -> { + val c = galleryItem.content + MediaItem.Audio( + id = id, + eventId = currentTimelineItem.eventId, + mediaInfo = createMediaInfo( + filename = c.filename, + fileSize = c.info?.size, + caption = c.caption, + mimeType = c.info?.mimetype.orEmpty(), + fileExtension = c.filename, + event = event, + dateSent = dateSent, + dateSentFull = dateSentFull, + ), + mediaSource = c.source, + ) + } + is GalleryItemType.File -> { + val c = galleryItem.content + MediaItem.File( + id = id, + eventId = currentTimelineItem.eventId, + mediaInfo = createMediaInfo( + filename = c.filename, + fileSize = c.info?.size, + caption = c.caption, + mimeType = c.info?.mimetype.orEmpty(), + fileExtension = c.filename, + event = event, + dateSent = dateSent, + dateSentFull = dateSentFull, + ), + mediaSource = c.source, + ) + } + is GalleryItemType.Other -> null + } + } + } + is AudioMessageType -> listOf(MediaItem.Audio( id = currentTimelineItem.uniqueId, eventId = currentTimelineItem.eventId, mediaInfo = MediaInfo( @@ -111,8 +198,8 @@ class EventItemFactory( duration = null, ), mediaSource = type.source, - ) - is FileMessageType -> MediaItem.File( + )) + is FileMessageType -> listOf(MediaItem.File( id = currentTimelineItem.uniqueId, eventId = currentTimelineItem.eventId, mediaInfo = MediaInfo( @@ -133,8 +220,8 @@ class EventItemFactory( ), mediaSource = type.source, // TODO We may want to add a thumbnailSource and set it to type.info?.thumbnailSource - ) - is ImageMessageType -> MediaItem.Image( + )) + is ImageMessageType -> listOf(MediaItem.Image( id = currentTimelineItem.uniqueId, eventId = currentTimelineItem.eventId, mediaInfo = MediaInfo( @@ -155,8 +242,8 @@ class EventItemFactory( ), mediaSource = type.source, thumbnailSource = type.info?.thumbnailSource, - ) - is StickerMessageType -> MediaItem.Image( + )) + is StickerMessageType -> listOf(MediaItem.Image( id = currentTimelineItem.uniqueId, eventId = currentTimelineItem.eventId, mediaInfo = MediaInfo( @@ -177,8 +264,8 @@ class EventItemFactory( ), mediaSource = type.source, thumbnailSource = type.info?.thumbnailSource, - ) - is VideoMessageType -> MediaItem.Video( + )) + is VideoMessageType -> listOf(MediaItem.Video( id = currentTimelineItem.uniqueId, eventId = currentTimelineItem.eventId, mediaInfo = MediaInfo( @@ -199,8 +286,8 @@ class EventItemFactory( ), mediaSource = type.source, thumbnailSource = type.info?.thumbnailSource, - ) - is VoiceMessageType -> MediaItem.Voice( + )) + is VoiceMessageType -> listOf(MediaItem.Voice( id = currentTimelineItem.uniqueId, eventId = currentTimelineItem.eventId, mediaInfo = MediaInfo( @@ -220,9 +307,36 @@ class EventItemFactory( duration = type.info?.duration?.inWholeMilliseconds?.toHumanReadableDuration(), ), mediaSource = type.source, - ) + )) } } } } + + private fun createMediaInfo( + filename: String, + fileSize: Long?, + caption: String?, + mimeType: String, + fileExtension: String, + event: io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem, + dateSent: String, + dateSentFull: String, + waveform: List? = null, + duration: String? = null, + ) = MediaInfo( + filename = filename, + fileSize = fileSize, + caption = caption, + mimeType = mimeType, + formattedFileSize = fileSize?.let { fileSizeFormatter.format(it) }.orEmpty(), + fileExtension = fileExtensionExtractor.extractFromName(fileExtension), + senderId = event.sender, + senderName = event.senderProfile.getDisambiguatedDisplayName(event.sender), + senderAvatar = event.senderProfile.getAvatarUrl(), + dateSent = dateSent, + dateSentFull = dateSentFull, + waveform = waveform, + duration = duration, + ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaItemsFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaItemsFactory.kt index d2f78a7249..1c96e0f44b 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaItemsFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaItemsFactory.kt @@ -9,10 +9,8 @@ package io.element.android.libraries.mediaviewer.impl.datasource import dev.zacsweers.metro.Inject -import io.element.android.libraries.androidutils.diff.DefaultDiffCacheInvalidator -import io.element.android.libraries.androidutils.diff.DiffCacheUpdater -import io.element.android.libraries.androidutils.diff.MutableListDiffCache import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.mediaviewer.impl.model.MediaItem import kotlinx.collections.immutable.ImmutableList @@ -32,18 +30,8 @@ class TimelineMediaItemsFactory( ) { private val _timelineItems = MutableSharedFlow>(replay = 1) private val lock = Mutex() - private val diffCache = MutableListDiffCache() - private val diffCacheUpdater = DiffCacheUpdater( - diffCache = diffCache, - detectMoves = false, - cacheInvalidator = DefaultDiffCacheInvalidator() - ) { old, new -> - if (old is MatrixTimelineItem.Event && new is MatrixTimelineItem.Event) { - old.uniqueId == new.uniqueId - } else { - false - } - } + private val cache = mutableMapOf>() + private var previousTimelineItems: List = emptyList() val timelineItems: Flow> = _timelineItems.distinctUntilChanged() @@ -51,39 +39,41 @@ class TimelineMediaItemsFactory( timelineItems: List, ) = withContext(dispatchers.computation) { lock.withLock { - diffCacheUpdater.updateWith(timelineItems) - buildAndEmitTimelineItemStates(timelineItems) - } - } - - private suspend fun buildAndEmitTimelineItemStates( - timelineItems: List, - ) { - val newTimelineItemStates = ArrayList() - for (index in diffCache.indices().reversed()) { - val cacheItem = diffCache.get(index) - if (cacheItem == null) { - buildAndCacheItem(timelineItems, index)?.also { timelineItemState -> - newTimelineItemStates.add(timelineItemState) + val newTimelineItemStates = ArrayList() + for (index in timelineItems.indices.reversed()) { + when (val currentTimelineItem = timelineItems[index]) { + is MatrixTimelineItem.Event -> { + val cachedItems = cache[currentTimelineItem.uniqueId] + val items = if (cachedItems != null && currentTimelineItem.isUnchanged(previousTimelineItems)) { + cachedItems + } else { + eventItemFactory.create(currentTimelineItem).also { newItems -> + cache[currentTimelineItem.uniqueId] = newItems + } + } + newTimelineItemStates.addAll(items.asReversed()) + } + is MatrixTimelineItem.Virtual -> { + virtualItemFactory.create(currentTimelineItem)?.also { + newTimelineItemStates.add(it) + } + } + MatrixTimelineItem.Other -> Unit } - } else { - newTimelineItemStates.add(cacheItem) } + previousTimelineItems = timelineItems + _timelineItems.emit(newTimelineItemStates.toImmutableList()) } - _timelineItems.emit(newTimelineItemStates.toImmutableList()) - } - - private fun buildAndCacheItem( - timelineItems: List, - index: Int, - ): MediaItem? { - val timelineItem = - when (val currentTimelineItem = timelineItems[index]) { - is MatrixTimelineItem.Event -> eventItemFactory.create(currentTimelineItem) - is MatrixTimelineItem.Virtual -> virtualItemFactory.create(currentTimelineItem) - MatrixTimelineItem.Other -> null - } - diffCache[index] = timelineItem - return timelineItem } } + +private fun MatrixTimelineItem.Event.isUnchanged( + previousItems: List, +): Boolean { + val previousItem = previousItems + .find { (it as? MatrixTimelineItem.Event)?.uniqueId == uniqueId } + as? MatrixTimelineItem.Event + return previousItem != null && + previousItem.event.eventId == event.eventId && + previousItem.event.timestamp == event.timestamp +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetState.kt index 722126fac6..245e3a14b8 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetState.kt @@ -16,6 +16,7 @@ sealed interface MediaBottomSheetState { data object Hidden : MediaBottomSheetState data class Details( + val fromGallery: Boolean, val eventId: EventId?, val canDelete: Boolean, val mediaInfo: MediaInfo, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetStateDetailsProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetStateDetailsProvider.kt index 99a6925b9d..7540d49b8a 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetStateDetailsProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaBottomSheetStateDetailsProvider.kt @@ -29,10 +29,14 @@ open class MediaBottomSheetStateDetailsProvider : PreviewParameterProvider @@ -148,16 +114,45 @@ fun MediaDetailsBottomSheet( ListItem( leadingContent = icon, headlineContent = { Text(wording) }, - style = ListItemStyle.Primary, onClick = { onOpenWith(state.eventId) } ) + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.VisibilityOn())), + headlineContent = { Text(stringResource(CommonStrings.action_view_in_timeline)) }, + onClick = { + onViewInTimeline(state.eventId) + } + ) + if (state.fromGallery) { + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.ShareAndroid())), + headlineContent = { Text(stringResource(CommonStrings.action_share)) }, + onClick = { + onShare(state.eventId) + } + ) + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Download())), + headlineContent = { Text(stringResource(CommonStrings.action_download)) }, + onClick = { + onDownload(state.eventId) + } + ) + } + ListItem( + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Forward())), + headlineContent = { Text(stringResource(CommonStrings.action_forward)) }, + onClick = { + onForward(state.eventId) + } + ) if (state.canDelete) { HorizontalDivider() ListItem( leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Delete())), - headlineContent = { Text(stringResource(CommonStrings.action_delete)) }, + headlineContent = { Text(stringResource(CommonStrings.action_delete_file)) }, style = ListItemStyle.Destructive, onClick = { onDelete(state.eventId) @@ -221,16 +216,14 @@ private fun SenderRow( } @Composable -private fun ColumnScope.Title() { +private fun Title() { Text( modifier = Modifier - .align(Alignment.CenterHorizontally) .padding(top = 16.dp, bottom = 8.dp, start = 16.dp, end = 16.dp) .semantics { heading() }, text = stringResource(R.string.screen_media_details_title), - textAlign = TextAlign.Center, style = ElementTheme.typography.fontBodyLgMedium, color = ElementTheme.colors.textPrimary, ) @@ -274,7 +267,7 @@ private fun SectionText( @Composable internal fun MediaDetailsBottomSheetPreview( @PreviewParameter(MediaBottomSheetStateDetailsProvider::class) state: MediaBottomSheetState.Details, -) = ElementPreview { +) = ElementPreview(fillMaxSize = true) { MediaDetailsBottomSheet( state = state, onViewInTimeline = {}, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt index 2c2fb31020..25e27330b4 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt @@ -129,6 +129,7 @@ class MediaGalleryPresenter( } is MediaGalleryEvent.OpenInfo -> coroutineScope.launch { mediaBottomSheetState = MediaBottomSheetState.Details( + fromGallery = true, eventId = event.mediaItem.eventId(), canDelete = when (event.mediaItem.mediaInfo().senderId) { null -> false diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryFlowNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryFlowNode.kt index 5d6a48c25b..611d619d52 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryFlowNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryFlowNode.kt @@ -128,13 +128,12 @@ class MediaGalleryFlowNode( mediaViewerEntryPoint.createNode( parentNode = this, buildContext = buildContext, - params = MediaViewerEntryPoint.Params( + params = MediaViewerEntryPoint.Params.RoomMedia( mode = navTarget.mode, eventId = navTarget.eventId, mediaInfo = navTarget.mediaInfo, mediaSource = navTarget.mediaSource, thumbnailSource = navTarget.thumbnailSource, - canShowInfo = true, ), callback = callback, ) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt index c7a01ea494..071e0dba64 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActions.kt @@ -100,7 +100,11 @@ class AndroidLocalMediaActions( override suspend fun share(localMedia: LocalMedia): Result = withContext(coroutineDispatchers.io) { require(localMedia.uri.scheme == ContentResolver.SCHEME_FILE) runCatchingExceptions { - val shareableUri = localMedia.toShareableUri() + // Make a copy of the shared file in the cache directory, otherwise the original file will be gone once this screen is dismissed + // and will prevent sharing the media to another room inside the app. + val copiedFile = localMedia.uri.toFile() + .copyTo(File(context.cacheDir, "temp/media/" + (localMedia.uri.lastPathSegment ?: "shared_file")), true) + val shareableUri = copiedFile.toShareableUri() val shareMediaIntent = Intent(Intent.ACTION_SEND) .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .putExtra(Intent.EXTRA_STREAM, shareableUri) @@ -157,10 +161,13 @@ class AndroidLocalMediaActions( } } - private fun LocalMedia.toShareableUri(): Uri { - val mediaAsFile = this.toFile() + private fun File.toShareableUri(): Uri { val authority = "${buildMeta.applicationId}.fileprovider" - return FileProvider.getUriForFile(context, authority, mediaAsFile).normalizeScheme() + return FileProvider.getUriForFile(context, authority, this).normalizeScheme() + } + + private fun LocalMedia.toShareableUri(): Uri { + return this.toFile().toShareableUri() } @RequiresApi(Build.VERSION_CODES.Q) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt index 96450d99bf..f7564aec31 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt @@ -40,7 +40,9 @@ class DefaultLocalMediaRenderer( localMediaViewState = localMediaViewState, textFileViewer = textFileViewer, audioFocus = audioFocus, + forPreview = true, onClick = {}, + onOpenWith = null, ) } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt index cc276b52c8..01b44f1246 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt @@ -31,7 +31,9 @@ fun LocalMediaView( bottomPaddingInPixels: Int, audioFocus: AudioFocus?, onClick: () -> Unit, + onOpenWith: (() -> Unit)?, textFileViewer: TextFileViewer, + forPreview: Boolean, modifier: Modifier = Modifier, isDisplayed: Boolean = true, isUserSelected: Boolean = false, @@ -44,6 +46,7 @@ fun LocalMediaView( localMediaViewState = localMediaViewState, localMedia = localMedia, modifier = modifier, + forPreview = forPreview, onClick = onClick, ) mimeType.isMimeTypeVideo() -> MediaVideoView( @@ -53,6 +56,7 @@ fun LocalMediaView( localMedia = localMedia, autoplay = isUserSelected, audioFocus = audioFocus, + forPreview = forPreview, modifier = modifier, ) mimeType == MimeTypes.PlainText -> TextFileView( @@ -80,7 +84,7 @@ fun LocalMediaView( uri = localMedia?.uri, info = mediaInfo, modifier = modifier, - onClick = onClick, + onOpenWith = onOpenWith, ) } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt index 912ea88e99..a1c57ef272 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaFileView.kt @@ -9,23 +9,16 @@ package io.element.android.libraries.mediaviewer.impl.local.file import android.net.Uri -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.rotate +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewParameter @@ -33,55 +26,54 @@ import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.core.bool.orFalse +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio +import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.ButtonSize +import io.element.android.libraries.designsystem.theme.components.IconSource +import io.element.android.libraries.designsystem.theme.components.OutlinedButton import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAndSize +import io.element.android.libraries.mediaviewer.impl.R import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState +import io.element.android.libraries.ui.strings.CommonStrings +/** + * Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=3361-16623 + */ @Composable fun MediaFileView( localMediaViewState: LocalMediaViewState, uri: Uri?, info: MediaInfo?, - onClick: () -> Unit, + onOpenWith: (() -> Unit)?, modifier: Modifier = Modifier, ) { val isAudio = info?.mimeType.isMimeTypeAudio().orFalse() localMediaViewState.isReady = uri != null - - val interactionSource = remember { MutableInteractionSource() } Box( modifier = modifier - .padding(horizontal = 8.dp) - .clickable( - onClick = onClick, - interactionSource = interactionSource, - indication = null - ), + .padding(horizontal = 8.dp), contentAlignment = Alignment.Center ) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - Box( - modifier = Modifier - .size(72.dp) - .clip(CircleShape) - .background(ElementTheme.colors.iconPrimary), - contentAlignment = Alignment.Center, - ) { - Icon( - imageVector = if (isAudio) CompoundIcons.Audio() else CompoundIcons.Attachment(), - contentDescription = null, - tint = ElementTheme.colors.iconOnSolidPrimary, - modifier = Modifier - .size(32.dp) - .rotate(if (isAudio) 0f else -45f), - ) + val isApk = info?.mimeType == MimeTypes.Apk + val icon = when { + isAudio -> CompoundIcons.Audio() + isApk -> CompoundIcons.Bug() + else -> CompoundIcons.Files() } + BigIcon( + modifier = Modifier.align(Alignment.CenterHorizontally), + style = BigIcon.Style.Default( + vectorIcon = icon, + usePrimaryTint = true, + ), + ) if (info != null) { Spacer(modifier = Modifier.height(20.dp)) Text( @@ -100,6 +92,20 @@ fun MediaFileView( overflow = TextOverflow.Ellipsis, color = ElementTheme.colors.textPrimary ) + if (onOpenWith != null) { + val (icon, textResId) = if (isApk) { + IconSource.Resource(R.drawable.ic_apk_install) to CommonStrings.common_install_apk_android + } else { + IconSource.Vector(CompoundIcons.PopOut()) to CommonStrings.action_open_with + } + OutlinedButton( + modifier = Modifier.padding(top = 24.dp), + size = ButtonSize.Small, + leadingIcon = icon, + onClick = onOpenWith, + text = stringResource(id = textResId), + ) + } } } } @@ -115,6 +121,6 @@ internal fun MediaFileViewPreview( localMediaViewState = rememberLocalMediaViewState(), uri = null, info = info, - onClick = {}, + onOpenWith = {}, ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt index 8e41a4809a..3214236253 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/file/MediaInfoFileProvider.kt @@ -10,11 +10,15 @@ package io.element.android.libraries.mediaviewer.impl.local.file import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.mediaviewer.api.MediaInfo -import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo +import io.element.android.libraries.mediaviewer.api.aZipMediaInfo +import io.element.android.libraries.mediaviewer.api.anApkMediaInfo +import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo open class MediaInfoFileProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - aPdfMediaInfo(), + aZipMediaInfo(), + anAudioMediaInfo(), + anApkMediaInfo(), ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt index 4c73dd215d..c935b17b85 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt @@ -30,6 +30,7 @@ import me.saket.telephoto.zoomable.rememberZoomableImageState fun MediaImageView( localMediaViewState: LocalMediaViewState, localMedia: LocalMedia?, + forPreview: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier, ) { @@ -42,11 +43,16 @@ fun MediaImageView( } else { val zoomableImageState = rememberZoomableImageState(localMediaViewState.zoomableState) localMediaViewState.isReady = zoomableImageState.isImageDisplayed + val imageDescription = if (forPreview) { + stringResource(CommonStrings.a11y_photo_preview) + } else { + stringResource(CommonStrings.common_image) + } ZoomableAsyncImage( modifier = modifier, state = zoomableImageState, model = localMedia?.uri, - contentDescription = stringResource(id = CommonStrings.common_image), + contentDescription = imageDescription, contentScale = ContentScale.Fit, onClick = { onClick() } ) @@ -60,6 +66,7 @@ internal fun MediaImageViewPreview() = ElementPreview { modifier = Modifier.fillMaxSize(), localMediaViewState = rememberLocalMediaViewState(), localMedia = null, + forPreview = false, onClick = {}, ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerForPreview.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerForPreview.kt index 11f99a3ca8..4da8433cd1 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerForPreview.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/ExoPlayerForPreview.kt @@ -258,7 +258,7 @@ class ExoPlayerForPreview( override fun setPriorityTaskManager(priorityTaskManager: PriorityTaskManager?) {} override fun isSleepingForOffload(): Boolean = throw NotImplementedError() override fun isTunnelingEnabled(): Boolean = throw NotImplementedError() - override fun isReleased(): Boolean = throw NotImplementedError() + override fun isReleased(): Boolean = false override fun setImageOutput(imageOutput: ImageOutput?) {} override fun setAudioCodecParameters(codecParameters: CodecParameters) {} override fun addAudioCodecParametersChangeListener(listener: CodecParametersChangeListener, keys: List) {} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt index d89762b72e..d6484cd5a4 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt @@ -30,13 +30,17 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.res.stringResource import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.Lifecycle import androidx.media3.common.MediaItem +import androidx.media3.common.ParserException +import androidx.media3.common.PlaybackException import androidx.media3.common.Player import androidx.media3.common.Player.STATE_READY import androidx.media3.common.Timeline import androidx.media3.common.util.UnstableApi +import androidx.media3.exoplayer.ExoPlaybackException import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.PlayerView @@ -57,6 +61,7 @@ import io.element.android.libraries.mediaviewer.impl.local.player.rememberExoPla import io.element.android.libraries.mediaviewer.impl.local.player.seekToEnsurePlaying import io.element.android.libraries.mediaviewer.impl.local.player.togglePlay import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState +import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import kotlinx.coroutines.delay import me.saket.telephoto.zoomable.zoomable @@ -72,6 +77,7 @@ fun MediaVideoView( localMedia: LocalMedia?, autoplay: Boolean, audioFocus: AudioFocus?, + forPreview: Boolean, modifier: Modifier = Modifier, ) { val exoPlayer = rememberExoPlayer(forAudioOnly = false) @@ -83,6 +89,7 @@ fun MediaVideoView( localMedia = localMedia, autoplay = autoplay, audioFocus = audioFocus, + forPreview = forPreview, modifier = modifier, ) } @@ -97,6 +104,7 @@ private fun ExoPlayerMediaVideoView( localMedia: LocalMedia?, autoplay: Boolean, audioFocus: AudioFocus?, + forPreview: Boolean, modifier: Modifier = Modifier, ) { var mediaPlayerControllerState: MediaPlayerControllerState by remember { @@ -158,6 +166,19 @@ private fun ExoPlayerMediaVideoView( isReady = playbackState == STATE_READY, ) } + + override fun onPlayerError(error: PlaybackException) { + super.onPlayerError(error) + Timber.w(error, "Player error") + if (error is ExoPlaybackException && error.cause is ParserException) { + // The cause can be: + // androidx.media3.common.ParserException: Invalid NAL length {contentIsMalformed=true, dataType=1} + // This has been observed when the user wants to play a second time a recorded video. + // Workaround the issue #6956, start the playback again + exoPlayer.prepare() + exoPlayer.play() + } + } } } @@ -202,6 +223,11 @@ private fun ExoPlayerMediaVideoView( text = "A Video Player will render here", ) } else { + val videoDescription = if (forPreview) { + stringResource(CommonStrings.a11y_video_preview) + } else { + stringResource(CommonStrings.common_video) + } AndroidView( modifier = Modifier .fillMaxSize() @@ -220,6 +246,7 @@ private fun ExoPlayerMediaVideoView( resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) useController = false + contentDescription = videoDescription } }, onRelease = { playerView -> @@ -339,5 +366,6 @@ internal fun MediaVideoViewPreview() = ElementPreview { localMedia = null, audioFocus = null, autoplay = false, + forPreview = false, ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/GalleryMediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/GalleryMediaGalleryDataSource.kt new file mode 100644 index 0000000000..2dfb11a89f --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/GalleryMediaGalleryDataSource.kt @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.viewer + +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.UniqueId +import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.mediaviewer.api.GalleryInfo +import io.element.android.libraries.mediaviewer.api.GalleryItemData +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.flowOf + +class GalleryMediaGalleryDataSource( + private val data: GroupedMediaItems, +) : MediaGalleryDataSource { + override val isReady: Boolean = true + override fun start(coroutineScope: CoroutineScope) = Unit + override fun groupedMediaItemsFlow() = flowOf(AsyncData.Success(data)) + override fun getLastData(): AsyncData = AsyncData.Success(data) + override suspend fun loadMore(direction: Timeline.PaginationDirection) = Unit + override suspend fun deleteItem(eventId: EventId) = Unit + + companion object { + fun createFrom( + eventId: EventId?, + galleryItems: List, + galleryInfo: GalleryInfo, + ): GalleryMediaGalleryDataSource { + val mixedItems = mutableListOf() + galleryItems.forEachIndexed { index, galleryItem -> + val itemMediaInfo = MediaInfo( + filename = galleryItem.filename, + fileSize = null, + caption = galleryInfo.caption, + mimeType = galleryItem.mimeType, + formattedFileSize = "", + fileExtension = galleryItem.filename.substringAfterLast('.', ""), + senderId = galleryInfo.senderId, + senderName = galleryInfo.senderName, + senderAvatar = galleryInfo.senderAvatar, + dateSent = galleryInfo.dateSent, + dateSentFull = galleryInfo.dateSentFull, + waveform = null, + duration = null, + ) + val id = UniqueId("${eventId?.value ?: "gallery"}_$index") + val mediaItem: MediaItem.Event = when (galleryItem.type) { + GalleryItemData.Type.Video -> MediaItem.Video( + id = id, + eventId = eventId, + mediaInfo = itemMediaInfo, + mediaSource = galleryItem.mediaSource, + thumbnailSource = galleryItem.thumbnailSource, + ) + GalleryItemData.Type.Audio -> MediaItem.Audio( + id = id, + eventId = eventId, + mediaInfo = itemMediaInfo, + mediaSource = galleryItem.mediaSource, + ) + GalleryItemData.Type.File -> MediaItem.File( + id = id, + eventId = eventId, + mediaInfo = itemMediaInfo, + mediaSource = galleryItem.mediaSource, + ) + GalleryItemData.Type.Image -> MediaItem.Image( + id = id, + eventId = eventId, + mediaInfo = itemMediaInfo, + mediaSource = galleryItem.mediaSource, + thumbnailSource = galleryItem.thumbnailSource, + ) + } + mixedItems.add(mediaItem) + } + return GalleryMediaGalleryDataSource( + data = GroupedMediaItems( + imageAndVideoItems = mixedItems.toImmutableList(), + fileItems = persistentListOf(), + ) + ) + } + } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt index 6feb3c7d53..7cbeafa0b2 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt @@ -62,9 +62,9 @@ class MediaViewerDataSource( private val mediaFiles: ConcurrentHashMap = ConcurrentHashMap() private val galleryMode = when (mode) { - MediaViewerMode.SingleMedia, is MediaViewerMode.TimelineImagesAndVideos -> MediaGalleryMode.Images is MediaViewerMode.TimelineFilesAndAudios -> MediaGalleryMode.Files + is MediaViewerMode.EventGallery -> MediaGalleryMode.Images } // Map of sourceUrl to local media state @@ -98,9 +98,12 @@ class MediaViewerDataSource( /** * Find the index of the page corresponding to the given eventId, or null if not found. */ - fun findEventIndex(eventId: EventId?): Int? { + fun findEventIndex(eventId: EventId?, mediaSource: MediaSource? = null): Int? { if (eventId == null) return null - return dataFlow.value.indexOfFirst { (it as? MediaViewerPageData.MediaViewerData)?.eventId == eventId }.takeIf { it >= 0 } + return dataFlow.value.indexOfFirst { + val pageData = it as? MediaViewerPageData.MediaViewerData + pageData?.eventId == eventId && (mediaSource == null || pageData.mediaSource == mediaSource) + }.takeIf { it >= 0 } } @VisibleForTesting diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt index e594daeb41..2298981543 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt @@ -74,42 +74,51 @@ class MediaViewerNode( callback.onDone() } - private val mediaGallerySource = if (inputs.mode == MediaViewerEntryPoint.MediaViewerMode.SingleMedia) { - SingleMediaGalleryDataSource.createFrom(inputs) - } else { - val eventId = inputs.eventId - if (eventId == null) { - // Should not happen - timelineMediaGalleryDataSource - } else { - // Can we use a specific timeline? - val timelineMode = inputs.mode.getTimelineMode() - when (timelineMode) { - null -> timelineMediaGalleryDataSource - Timeline.Mode.Live, - is Timeline.Mode.FocusedOnEvent, - is Timeline.Mode.Thread -> { - // Does timelineMediaGalleryDataSource knows the eventId? - val lastData = timelineMediaGalleryDataSource.getLastData().dataOrNull() - val isEventKnown = lastData?.hasEvent(eventId) == true - if (isEventKnown) { - timelineMediaGalleryDataSource - } else { + private val mediaGallerySource = when (inputs) { + is MediaViewerEntryPoint.Params.Avatar -> + SingleMediaGalleryDataSource.createFrom(inputs) + is MediaViewerEntryPoint.Params.EventGallery -> + GalleryMediaGalleryDataSource.createFrom( + eventId = inputs.eventId, + galleryItems = inputs.galleryItems, + galleryInfo = inputs.galleryInfo, + ) + is MediaViewerEntryPoint.Params.RoomMedia -> { + val eventId = inputs.eventId + if (eventId == null) { + // Should not happen + timelineMediaGalleryDataSource + } else { + // Can we use a specific timeline? + val timelineMode = inputs.mode.getTimelineMode() + when (timelineMode) { + Timeline.Mode.Live, + is Timeline.Mode.FocusedOnEvent, + is Timeline.Mode.Thread -> { + // Does timelineMediaGalleryDataSource knows the eventId? + val lastData = timelineMediaGalleryDataSource.getLastData().dataOrNull() + val isEventKnown = lastData?.hasEvent(eventId) == true + if (isEventKnown) { + timelineMediaGalleryDataSource + } else { + focusedTimelineMediaGalleryDataSourceFactory.createFor( + eventId = eventId, + mediaItem = inputs.toMediaItem(), + onlyPinnedEvents = false, + ) + } + } + Timeline.Mode.PinnedEvents -> { focusedTimelineMediaGalleryDataSourceFactory.createFor( eventId = eventId, mediaItem = inputs.toMediaItem(), - onlyPinnedEvents = false, + onlyPinnedEvents = true, ) } + Timeline.Mode.Media -> timelineMediaGalleryDataSource + // null should not happen, input should be MediaViewerEntryPoint.Params.EventGallery in this case + null -> timelineMediaGalleryDataSource } - Timeline.Mode.PinnedEvents -> { - focusedTimelineMediaGalleryDataSourceFactory.createFor( - eventId = eventId, - mediaItem = inputs.toMediaItem(), - onlyPinnedEvents = true, - ) - } - Timeline.Mode.Media -> timelineMediaGalleryDataSource } } } @@ -118,7 +127,14 @@ class MediaViewerNode( inputs = inputs, navigator = this, dataSource = MediaViewerDataSource( - mode = inputs.mode, + mode = when (inputs) { + is MediaViewerEntryPoint.Params.Avatar -> + MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(Timeline.Mode.Media) + is MediaViewerEntryPoint.Params.EventGallery -> + MediaViewerEntryPoint.MediaViewerMode.EventGallery(fromPinnedMessages = inputs.fromPinnedMessages) + is MediaViewerEntryPoint.Params.RoomMedia -> + inputs.mode + }, coroutineScope = lifecycleScope, dispatcher = coroutineDispatchers.computation, galleryDataSource = mediaGallerySource, @@ -153,6 +169,6 @@ internal fun MediaViewerEntryPoint.MediaViewerMode.getTimelineMode(): Timeline.M return when (this) { is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> timelineMode is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> timelineMode - else -> null + is MediaViewerEntryPoint.MediaViewerMode.EventGallery -> null } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt index 296f20ef4c..eaea61b5a5 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt @@ -67,20 +67,31 @@ class MediaViewerPresenter( // Use a local snackbarDispatcher because this presenter is used in an Overlay Node private val snackbarDispatcher = SnackbarDispatcher() + private val eventId = inputs.eventId() + private val mediaSource = inputs.mediaSource() + @Composable override fun present(): MediaViewerState { val coroutineScope = rememberCoroutineScope() - val currentIndex = remember { mutableIntStateOf(dataSource.findEventIndex(inputs.eventId) ?: 0) } + val currentIndex = remember { + val firstIndex = if (inputs is MediaViewerEntryPoint.Params.EventGallery) { + // Order is reversed so we have to reverse the index + inputs.galleryItems.lastIndex - inputs.galleryInfo.initialIndex + } else { + dataSource.findEventIndex(eventId, mediaSource) ?: 0 + } + mutableIntStateOf(firstIndex) + } val data = dataSource.produceState { flow -> flow.collectLatest { new -> val existingItem = value.getOrNull(currentIndex.intValue) val newItem = new.getOrNull(currentIndex.intValue) - if (existingItem is MediaViewerPageData.MediaViewerData && existingItem.eventId == inputs.eventId && newItem != existingItem) { - currentIndex.intValue = dataSource.findEventIndex(inputs.eventId) ?: 0 + if (existingItem is MediaViewerPageData.MediaViewerData && existingItem.eventId == eventId && newItem != existingItem) { + currentIndex.intValue = dataSource.findEventIndex(eventId, mediaSource) ?: 0 } else if (currentIndex.intValue > 0 && value.firstOrNull() is MediaViewerPageData.Loading && new.firstOrNull() !is MediaViewerPageData.Loading) { // Restore index based on the eventId after the initial items have been loaded - currentIndex.intValue = dataSource.findEventIndex(inputs.eventId) ?: 0 + currentIndex.intValue = dataSource.findEventIndex(eventId, mediaSource) ?: 0 } value = new } @@ -140,11 +151,20 @@ class MediaViewerPresenter( mediaBottomSheetState = MediaBottomSheetState.Hidden navigator.onForwardClick( eventId = event.eventId, - fromPinnedEvents = inputs.mode.getTimelineMode() == Timeline.Mode.PinnedEvents, + fromPinnedEvents = when (inputs) { + is MediaViewerEntryPoint.Params.RoomMedia -> when (val myMode = inputs.mode) { + is MediaViewerEntryPoint.MediaViewerMode.EventGallery -> myMode.fromPinnedMessages + is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> myMode.getTimelineMode() == Timeline.Mode.PinnedEvents + is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> myMode.getTimelineMode() == Timeline.Mode.PinnedEvents + } + is MediaViewerEntryPoint.Params.EventGallery -> inputs.fromPinnedMessages + is MediaViewerEntryPoint.Params.Avatar -> false + }, ) } is MediaViewerEvent.OpenInfo -> coroutineScope.launch { mediaBottomSheetState = MediaBottomSheetState.Details( + fromGallery = false, eventId = event.data.eventId, canDelete = when (event.data.mediaInfo.senderId) { null -> false @@ -175,11 +195,11 @@ class MediaViewerPresenter( } return MediaViewerState( - initiallySelectedEventId = inputs.eventId, + initiallySelectedEventId = eventId, listData = data.value, currentIndex = currentIndex.intValue, snackbarMessage = snackbarMessage, - canShowInfo = inputs.canShowInfo, + canShowInfo = inputs !is MediaViewerEntryPoint.Params.Avatar, mediaBottomSheetState = mediaBottomSheetState, eventSink = ::handleEvent, ) @@ -223,13 +243,16 @@ class MediaViewerPresenter( } private fun showNoMoreItemsSnackbar() { - val messageResId = when (inputs.mode) { - MediaViewerEntryPoint.MediaViewerMode.SingleMedia, - is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> R.string.screen_media_details_no_more_media_to_show - is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> R.string.screen_media_details_no_more_files_to_show + if (inputs is MediaViewerEntryPoint.Params.RoomMedia) { + val messageResId = when (inputs.mode) { + is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> R.string.screen_media_details_no_more_media_to_show + is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> R.string.screen_media_details_no_more_files_to_show + // Should not happen + is MediaViewerEntryPoint.MediaViewerMode.EventGallery -> R.string.screen_media_details_no_more_media_to_show + } + val message = SnackbarMessage(messageResId) + snackbarDispatcher.post(message) } - val message = SnackbarMessage(messageResId) - snackbarDispatcher.post(message) } private fun CoroutineScope.downloadMedia( @@ -291,3 +314,15 @@ class MediaViewerPresenter( } } } + +private fun MediaViewerEntryPoint.Params.eventId() = when (this) { + is MediaViewerEntryPoint.Params.Avatar -> null + is MediaViewerEntryPoint.Params.EventGallery -> eventId + is MediaViewerEntryPoint.Params.RoomMedia -> eventId +} + +private fun MediaViewerEntryPoint.Params.mediaSource() = when (this) { + is MediaViewerEntryPoint.Params.Avatar -> mediaSource + is MediaViewerEntryPoint.Params.EventGallery -> null + is MediaViewerEntryPoint.Params.RoomMedia -> mediaSource +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 3a7c006593..c981132b48 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -106,7 +106,7 @@ import me.saket.telephoto.zoomable.OverzoomEffect import me.saket.telephoto.zoomable.ZoomSpec import me.saket.telephoto.zoomable.rememberZoomableState -val topAppBarHeight = 88.dp +val topAppBarHeight = 112.dp /** * Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=3361-16623 @@ -239,6 +239,9 @@ fun MediaViewerView( onRetry = { state.eventSink(MediaViewerEvent.LoadMedia(dataForPage)) }, + onOpenWith = { + state.eventSink(MediaViewerEvent.OpenWith(dataForPage)) + }, onDismissError = { state.eventSink(MediaViewerEvent.ClearLoadingError(dataForPage)) }, @@ -277,6 +280,7 @@ fun MediaViewerView( state.eventSink(MediaViewerEvent.ViewInTimeline(it)) }, onShare = { + // Note: share action is not rendered when the bottom sheet is opened from the media viewer (currentData as? MediaViewerPageData.MediaViewerData)?.let { state.eventSink(MediaViewerEvent.Share(currentData)) } @@ -285,6 +289,7 @@ fun MediaViewerView( state.eventSink(MediaViewerEvent.Forward(it)) }, onDownload = { + // Note: download action is not rendered when the bottom sheet is opened from the media viewer (currentData as? MediaViewerPageData.MediaViewerData)?.let { state.eventSink(MediaViewerEvent.SaveOnDisk(currentData)) } @@ -333,6 +338,7 @@ private fun MediaViewerPage( isUserSelected: Boolean, onDismiss: () -> Unit, onRetry: () -> Unit, + onOpenWith: () -> Unit, onDismissError: () -> Unit, onShowOverlayChange: (Boolean) -> Unit, audioFocus: AudioFocus?, @@ -387,8 +393,10 @@ private fun MediaViewerPage( currentOnShowOverlayChange(!currentShowOverlay) } }, + onOpenWith = onOpenWith, isUserSelected = isUserSelected, audioFocus = audioFocus, + forPreview = false, ) if (showThumbnail) { ThumbnailView( diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt index a2234143af..b8de20a41d 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt @@ -11,6 +11,7 @@ package io.element.android.libraries.mediaviewer.impl.viewer import dev.zacsweers.metro.Inject import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.mediaviewer.impl.model.eventId +import io.element.android.libraries.mediaviewer.impl.model.mediaSource /** * x and y are loading items. @@ -50,31 +51,32 @@ class PagerKeysHandler { if (cachedData.mediaItems.isEmpty()) { cachedData = Data(mediaItems, 0) } else { - // Search a common item in both lists, i.e. an item with the same eventId - val itemInCacheIndex = cachedData.mediaItems.indexOfFirst { mediaItem -> - mediaItem is MediaItem.Event && mediaItems + // Search a common item in both lists using eventId + mediaSource to handle gallery items + val itemInCacheIndex = cachedData.mediaItems.indexOfFirst { cachedItem -> + cachedItem is MediaItem.Event && mediaItems .filterIsInstance() - .any { mediaItem.eventId() == it.eventId() } + .any { newItem -> + cachedItem.eventId() == newItem.eventId() && + cachedItem.mediaSource().safeUrl == newItem.mediaSource().safeUrl + } } cachedData = if (itemInCacheIndex == -1) { - // If the item is not found, start with a new cache Data(mediaItems, 0) } else { val cachedItem = cachedData.mediaItems[itemInCacheIndex] val eventId = (cachedItem as? MediaItem.Event)?.eventId() - if (eventId == null) { - // Should not happen, but in this case, start with a new cache + val cachedSourceUrl = (cachedItem as? MediaItem.Event)?.mediaSource()?.safeUrl + if (eventId == null || cachedSourceUrl == null) { Data(mediaItems, 0) } else { - // Search the index of the item in the new list val itemIndex = mediaItems.indexOfFirst { mediaItem -> - mediaItem is MediaItem.Event && mediaItem.eventId() == eventId + mediaItem is MediaItem.Event && + mediaItem.eventId() == eventId && + mediaItem.mediaSource().safeUrl == cachedSourceUrl } if (itemIndex == -1) { - // If the item is not found, start with a new cache Data(mediaItems, 0) } else { - // Update the cache with the new list and the new offset Data(mediaItems, cachedData.keyOffset + itemInCacheIndex - itemIndex.toLong()) } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSource.kt index 146ace8620..6809f6b685 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSource.kt @@ -9,12 +9,14 @@ package io.element.android.libraries.mediaviewer.impl.viewer import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeImage import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems @@ -36,17 +38,40 @@ class SingleMediaGalleryDataSource( override suspend fun deleteItem(eventId: EventId) = Unit companion object { - fun createFrom(params: MediaViewerEntryPoint.Params) = SingleMediaGalleryDataSource( + fun createFrom(params: MediaViewerEntryPoint.Params.Avatar) = SingleMediaGalleryDataSource( data = GroupedMediaItems( // Always use imageAndVideoItems, in Single mode, this is the data that will be used - imageAndVideoItems = persistentListOf(params.toMediaItem()), + imageAndVideoItems = persistentListOf( + MediaItem.Image( + id = UniqueId("dummy"), + eventId = null, + mediaInfo = MediaInfo( + filename = params.avatarInfo.filename, + caption = null, + formattedCaption = null, + mimeType = MimeTypes.Images, + fileSize = null, + formattedFileSize = "", + fileExtension = "", + senderId = null, + senderName = null, + senderAvatar = null, + dateSent = null, + dateSentFull = null, + waveform = null, + duration = null, + ), + mediaSource = params.mediaSource, + thumbnailSource = params.thumbnailSource, + ) + ), fileItems = persistentListOf(), ) ) } } -fun MediaViewerEntryPoint.Params.toMediaItem() = when { +fun MediaViewerEntryPoint.Params.RoomMedia.toMediaItem() = when { mediaInfo.mimeType.isMimeTypeImage() -> { MediaItem.Image( id = UniqueId("dummy"), diff --git a/libraries/mediaviewer/impl/src/main/res/values-be/translations.xml b/libraries/mediaviewer/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..9dc6e13043 --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,4 @@ + + + "Інфармацыя пра файл" + diff --git a/libraries/mediaviewer/impl/src/main/res/values-ko/translations.xml b/libraries/mediaviewer/impl/src/main/res/values-ko/translations.xml index 3362171d27..0a14586e6c 100644 --- a/libraries/mediaviewer/impl/src/main/res/values-ko/translations.xml +++ b/libraries/mediaviewer/impl/src/main/res/values-ko/translations.xml @@ -16,6 +16,7 @@ "파일 명" "더 이상 표시할 파일이 없습니다" "더 이상 보여줄 미디어가 없습니다" + "파일 정보" "에 의해 업로드됨" "에 업로드됨" diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPointTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPointTest.kt index e7d45f433a..9cd134b843 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPointTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPointTest.kt @@ -13,14 +13,12 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.bumble.appyx.core.modality.BuildContext import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.test.FakeEnterpriseService -import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader import io.element.android.libraries.mediaplayer.test.FakeAudioFocus -import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.api.AvatarInfo import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.impl.datasource.createTimelineMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.viewer.MediaViewerNode @@ -128,7 +126,7 @@ class DefaultMediaViewerEntryPointTest { override fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean) = lambdaError() } val params = entryPoint.createParamsForAvatar( - filename = "fn", + filename = "avatar.png", avatarUrl = "avatarUrl", ) val result = entryPoint.createNode( @@ -139,27 +137,10 @@ class DefaultMediaViewerEntryPointTest { ) assertThat(result).isInstanceOf(MediaViewerNode::class.java) assertThat(result.plugins).contains( - MediaViewerEntryPoint.Params( - mode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia, - eventId = null, - mediaInfo = MediaInfo( - filename = "fn", - fileSize = null, - caption = null, - mimeType = MimeTypes.Images, - formattedFileSize = "", - fileExtension = "", - senderId = UserId("@dummy:server.org"), - senderName = null, - senderAvatar = null, - dateSent = null, - dateSentFull = null, - waveform = null, - duration = null, - ), + MediaViewerEntryPoint.Params.Avatar( + avatarInfo = AvatarInfo(filename = "avatar.png"), mediaSource = MediaSource(url = "avatarUrl"), thumbnailSource = null, - canShowInfo = false, ) ) assertThat(result.plugins).contains(callback) diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultEventItemFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactoryTest.kt similarity index 54% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultEventItemFactoryTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactoryTest.kt index ab3ffa98c7..7d0018f120 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultEventItemFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactoryTest.kt @@ -12,6 +12,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.dateformatter.test.FakeDateFormatter +import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.media.AudioDetails import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo @@ -26,6 +27,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageT import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInviteContent import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType @@ -57,7 +60,8 @@ import kotlinx.collections.immutable.toImmutableList import org.junit.Test import kotlin.time.Duration.Companion.seconds -class DefaultEventItemFactoryTest { +@Suppress("LargeClass") +class EventItemFactoryTest { @Test fun `create check all null cases`() { val factory = createEventItemFactory() @@ -97,7 +101,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isNull() + assertThat(result).isEmpty() } } @@ -122,7 +126,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isNull() + assertThat(result).isEmpty() } } @@ -150,7 +154,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isEqualTo( + assertThat(result).containsExactly( MediaItem.File( id = A_UNIQUE_ID, eventId = AN_EVENT_ID, @@ -201,7 +205,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isEqualTo( + assertThat(result).containsExactly( MediaItem.Image( id = A_UNIQUE_ID, eventId = AN_EVENT_ID, @@ -249,7 +253,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isEqualTo( + assertThat(result).containsExactly( MediaItem.Audio( id = A_UNIQUE_ID, eventId = AN_EVENT_ID, @@ -301,7 +305,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isEqualTo( + assertThat(result).containsExactly( MediaItem.Video( id = A_UNIQUE_ID, eventId = AN_EVENT_ID, @@ -353,7 +357,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isEqualTo( + assertThat(result).containsExactly( MediaItem.Voice( id = A_UNIQUE_ID, eventId = AN_EVENT_ID, @@ -377,6 +381,321 @@ class DefaultEventItemFactoryTest { ) } + @Test + fun `create for GalleryMessageType with image item`() { + val factory = createEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = "caption", + formattedCaption = null, + source = MediaSource("image_url"), + info = ImageInfo( + mimetype = MimeTypes.Jpeg, + size = 123L, + thumbnailInfo = null, + thumbnailSource = MediaSource("thumbnail_url"), + height = 1L, + width = 2L, + blurhash = null, + ) + ) + ) + ) + ) + ) + ) + ) + ) + assertThat(result).containsExactly( + MediaItem.Image( + id = UniqueId("aUniqueId_0"), + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Jpeg, + filename = "image.jpg", + fileSize = 123L, + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "jpg", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "0 Day false", + dateSentFull = "0 Full false", + waveform = null, + duration = null, + ), + mediaSource = MediaSource("image_url"), + thumbnailSource = MediaSource("thumbnail_url"), + ) + ) + } + + @Test + fun `create for GalleryMessageType with video item`() { + val factory = createEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Video( + content = VideoMessageType( + filename = "video.mp4", + caption = "caption", + formattedCaption = null, + source = MediaSource("video_url"), + info = VideoInfo( + mimetype = MimeTypes.Mp4, + size = 123L, + thumbnailInfo = null, + duration = 123.seconds, + height = 1L, + width = 2L, + thumbnailSource = MediaSource("thumbnail_url"), + blurhash = null, + ) + ) + ) + ) + ) + ) + ) + ) + ) + assertThat(result).containsExactly( + MediaItem.Video( + id = UniqueId("aUniqueId_0"), + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Mp4, + filename = "video.mp4", + fileSize = 123L, + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "mp4", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "0 Day false", + dateSentFull = "0 Full false", + waveform = null, + duration = "2:03", + ), + mediaSource = MediaSource("video_url"), + thumbnailSource = MediaSource("thumbnail_url"), + ) + ) + } + + @Test + fun `create for GalleryMessageType with audio item`() { + val factory = createEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Audio( + content = AudioMessageType( + filename = "audio.mp3", + caption = "caption", + formattedCaption = null, + source = MediaSource("audio_url"), + info = AudioInfo( + mimetype = MimeTypes.Mp3, + size = 123L, + duration = 456.seconds, + ) + ) + ) + ) + ) + ) + ) + ) + ) + assertThat(result).containsExactly( + MediaItem.Audio( + id = UniqueId("aUniqueId_0"), + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Mp3, + filename = "audio.mp3", + fileSize = 123L, + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "mp3", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "0 Day false", + dateSentFull = "0 Full false", + waveform = null, + duration = null, + ), + mediaSource = MediaSource("audio_url"), + ) + ) + } + + @Test + fun `create for GalleryMessageType with file item`() { + val factory = createEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.File( + content = FileMessageType( + filename = "document.pdf", + caption = "caption", + formattedCaption = null, + source = MediaSource("file_url"), + info = FileInfo( + mimetype = MimeTypes.Pdf, + size = 456L, + thumbnailInfo = null, + thumbnailSource = null, + ) + ) + ) + ) + ) + ) + ) + ) + ) + assertThat(result).containsExactly( + MediaItem.File( + id = UniqueId("aUniqueId_0"), + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Pdf, + filename = "document.pdf", + fileSize = 456L, + caption = "caption", + formattedFileSize = "456 Bytes", + fileExtension = "pdf", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "0 Day false", + dateSentFull = "0 Full false", + waveform = null, + duration = null, + ), + mediaSource = MediaSource("file_url"), + ) + ) + } + + @Test + fun `create for GalleryMessageType with Other item returns empty list`() { + val factory = createEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Other(itemType = "unknown_type", body = "Some body") + ) + ) + ) + ) + ) + ) + assertThat(result).isEmpty() + } + + @Test + fun `create for GalleryMessageType with multiple items produces indexed IDs`() { + val factory = createEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = GalleryMessageType( + body = "Gallery body", + formatted = null, + items = listOf( + GalleryItemType.Image( + content = ImageMessageType( + filename = "image.jpg", + caption = null, + formattedCaption = null, + source = MediaSource("image_url"), + info = ImageInfo( + mimetype = MimeTypes.Jpeg, + size = 123L, + thumbnailInfo = null, + thumbnailSource = null, + height = 1L, + width = 2L, + blurhash = null, + ) + ) + ), + GalleryItemType.Video( + content = VideoMessageType( + filename = "video.mp4", + caption = null, + formattedCaption = null, + source = MediaSource("video_url"), + info = VideoInfo( + mimetype = MimeTypes.Mp4, + size = 456L, + thumbnailInfo = null, + duration = null, + height = 1L, + width = 2L, + thumbnailSource = null, + blurhash = null, + ) + ) + ), + GalleryItemType.Other(itemType = "unknown_type", body = "ignored"), + ) + ) + ) + ) + ) + ) + assertThat(result).hasSize(2) + assertThat(result[0]).isInstanceOf(MediaItem.Image::class.java) + assertThat((result[0] as MediaItem.Image).id).isEqualTo(UniqueId("aUniqueId_0")) + assertThat(result[1]).isInstanceOf(MediaItem.Video::class.java) + assertThat((result[1] as MediaItem.Video).id).isEqualTo(UniqueId("aUniqueId_1")) + } + @Test fun `create for StickerMessageType`() { val factory = createEventItemFactory() @@ -404,7 +723,7 @@ class DefaultEventItemFactoryTest { ) ) ) - assertThat(result).isEqualTo( + assertThat(result).containsExactly( MediaItem.Image( id = A_UNIQUE_ID, eventId = AN_EVENT_ID, diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheetTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheetTest.kt index 3f4c3aa6c3..a9fbae9eec 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheetTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheetTest.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -23,12 +22,11 @@ import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnceWithParam +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class MediaDeleteConfirmationBottomSheetTest { +class MediaDeleteConfirmationBottomSheetTest : RobolectricTest() { @Test fun `clicking on Cancel invokes expected callback`() = runAndroidComposeUiTest { val state = aMediaBottomSheetStateDeleteConfirmation() diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheetTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheetTest.kt index 5b0f105aea..4ad348a847 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheetTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheetTest.kt @@ -15,20 +15,18 @@ import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnceWithParam +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class MediaDetailsBottomSheetTest { +class MediaDetailsBottomSheetTest : RobolectricTest() { @Test @Config(qualifiers = "h1024dp") fun `clicking on View in timeline invokes expected callback`() = runAndroidComposeUiTest { @@ -45,7 +43,9 @@ class MediaDetailsBottomSheetTest { @Test @Config(qualifiers = "h1024dp") fun `clicking on Share invokes expected callback`() = runAndroidComposeUiTest { - val state = aMediaBottomSheetStateDetails() + val state = aMediaBottomSheetStateDetails( + fromGallery = true, + ) ensureCalledOnceWithParam(state.eventId) { callback -> setMediaDetailsBottomSheet( state = state, @@ -55,6 +55,15 @@ class MediaDetailsBottomSheetTest { } } + @Test + @Config(qualifiers = "h1024dp") + fun `item Share is not displayed when opened from the media viewer`() = runAndroidComposeUiTest { + setMediaDetailsBottomSheet( + state = aMediaBottomSheetStateDetails(), + ) + onNodeWithText(activity!!.getString(CommonStrings.action_share)).assertDoesNotExist() + } + @Test @Config(qualifiers = "h1024dp") fun `clicking on Forward invokes expected callback`() = runAndroidComposeUiTest { @@ -71,7 +80,9 @@ class MediaDetailsBottomSheetTest { @Test @Config(qualifiers = "h1024dp") fun `clicking on Download invokes expected callback`() = runAndroidComposeUiTest { - val state = aMediaBottomSheetStateDetails() + val state = aMediaBottomSheetStateDetails( + fromGallery = true, + ) ensureCalledOnceWithParam(state.eventId) { callback -> setMediaDetailsBottomSheet( state = state, @@ -81,6 +92,15 @@ class MediaDetailsBottomSheetTest { } } + @Test + @Config(qualifiers = "h1024dp") + fun `item Download is not displayed when opened from the media viewer`() = runAndroidComposeUiTest { + setMediaDetailsBottomSheet( + state = aMediaBottomSheetStateDetails(), + ) + onNodeWithText(activity!!.getString(CommonStrings.action_download)).assertDoesNotExist() + } + @Config(qualifiers = "h1024dp") @Test fun `clicking on Delete invokes expected callback`() = runAndroidComposeUiTest { @@ -90,8 +110,8 @@ class MediaDetailsBottomSheetTest { state = state, onDelete = callback, ) - onNodeWithText(activity!!.getString(CommonStrings.action_delete)).assertExists() - clickOn(CommonStrings.action_delete) + onNodeWithText(activity!!.getString(CommonStrings.action_delete_file)).assertExists() + clickOn(CommonStrings.action_delete_file) } } diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt index 929f2a970e..3ab95f2703 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt @@ -137,6 +137,7 @@ class MediaGalleryPresenterTest { val state = awaitItem() assertThat(state.mediaBottomSheetState).isEqualTo( MediaBottomSheetState.Details( + fromGallery = true, eventId = AN_EVENT_ID, canDelete = canDeleteOwn, mediaInfo = item.mediaInfo, @@ -184,6 +185,7 @@ class MediaGalleryPresenterTest { val state = awaitItem() assertThat(state.mediaBottomSheetState).isEqualTo( MediaBottomSheetState.Details( + fromGallery = true, eventId = AN_EVENT_ID, canDelete = canDeleteOther, mediaInfo = item.mediaInfo, diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActionsTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActionsTest.kt index cd7b7003af..cdc5f7220d 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActionsTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaActionsTest.kt @@ -18,16 +18,14 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.mediaviewer.test.viewer.aLocalMedia +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment -@RunWith(RobolectricTestRunner::class) -class AndroidLocalMediaActionsTest { +class AndroidLocalMediaActionsTest : RobolectricTest() { @Test fun `present - AndroidLocalMediaAction configure`() = runTest { val sut = createAndroidLocalMediaActions() diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt index 26f9087b39..246ae50b4d 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/local/AndroidLocalMediaFactoryTest.kt @@ -20,15 +20,13 @@ import io.element.android.libraries.matrix.test.media.FakeMediaFile import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.anImageMediaInfo import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import java.io.File import java.io.FileOutputStream -@RunWith(RobolectricTestRunner::class) -class AndroidLocalMediaFactoryTest { +class AndroidLocalMediaFactoryTest : RobolectricTest() { private val context = RuntimeEnvironment.getApplication() @Test diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidationTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidationTest.kt index 3c5c91589c..6f0d85894a 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidationTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/util/FileExtensionExtractorWithValidationTest.kt @@ -9,12 +9,10 @@ package io.element.android.libraries.mediaviewer.impl.util import com.google.common.truth.Truth.assertThat +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class FileExtensionExtractorWithValidationTest { +class FileExtensionExtractorWithValidationTest : RobolectricTest() { @Test fun `test FileExtensionExtractor with validation OK`() { val sut = FileExtensionExtractorWithValidation() diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/GalleryMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/GalleryMediaGalleryDataSourceTest.kt new file mode 100644 index 0000000000..710aaff1ab --- /dev/null +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/GalleryMediaGalleryDataSourceTest.kt @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.viewer + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.core.mimetype.MimeTypes +import io.element.android.libraries.matrix.api.core.UniqueId +import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.mediaviewer.api.GalleryInfo +import io.element.android.libraries.mediaviewer.api.GalleryItemData +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.impl.gallery.aGroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemFile +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage +import io.element.android.tests.testutils.WarmUpRule +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test + +class GalleryMediaGalleryDataSourceTest { + @get:Rule + val warmUpRule = WarmUpRule() + + @Test + fun `isReady is true`() { + val sut = GalleryMediaGalleryDataSource(aGroupedMediaItems()) + assertThat(sut.isReady).isTrue() + } + + @Test + fun `function start is no op`() = runTest { + val sut = GalleryMediaGalleryDataSource(aGroupedMediaItems()) + sut.start(backgroundScope) + } + + @Test + fun `function loadMore is no op`() = runTest { + val sut = GalleryMediaGalleryDataSource(aGroupedMediaItems()) + sut.loadMore(Timeline.PaginationDirection.BACKWARDS) + sut.loadMore(Timeline.PaginationDirection.FORWARDS) + } + + @Test + fun `function deleteItem is no op`() = runTest { + val sut = GalleryMediaGalleryDataSource(aGroupedMediaItems()) + sut.deleteItem(AN_EVENT_ID) + } + + @Test + fun `getLastData should return the data`() { + val data = aGroupedMediaItems( + imageAndVideoItems = listOf(aMediaItemImage()), + fileItems = listOf(aMediaItemFile()), + ) + val sut = GalleryMediaGalleryDataSource(data) + assertThat(sut.getLastData()).isEqualTo(AsyncData.Success(data)) + } + + @Test + fun `groupedMediaItemsFlow emits a single item`() = runTest { + val data = aGroupedMediaItems( + imageAndVideoItems = listOf(aMediaItemImage()), + fileItems = listOf(aMediaItemFile()), + ) + val sut = GalleryMediaGalleryDataSource(data) + sut.groupedMediaItemsFlow().test { + assertThat(awaitItem()).isEqualTo(AsyncData.Success(data)) + awaitComplete() + } + } + + @Test + fun `createFrom with image item creates MediaItem Image in imageAndVideoItems`() { + val result = GalleryMediaGalleryDataSource.createFrom( + eventId = AN_EVENT_ID, + galleryItems = listOf( + GalleryItemData( + filename = "image.jpg", + mimeType = MimeTypes.Jpeg, + mediaSource = MediaSource("image_url"), + thumbnailSource = MediaSource("thumbnail_url"), + type = GalleryItemData.Type.Image, + ) + ), + galleryInfo = aGalleryInfo(), + ) + val data = (result.getLastData() as AsyncData.Success).data + assertThat(data.fileItems).isEmpty() + assertThat(data.imageAndVideoItems).containsExactly( + MediaItem.Image( + id = UniqueId("${AN_EVENT_ID.value}_0"), + eventId = AN_EVENT_ID, + mediaInfo = expectedMediaInfo("image.jpg", MimeTypes.Jpeg), + mediaSource = MediaSource("image_url"), + thumbnailSource = MediaSource("thumbnail_url"), + ) + ) + } + + @Test + fun `createFrom with video item creates MediaItem Video in imageAndVideoItems`() { + val result = GalleryMediaGalleryDataSource.createFrom( + eventId = AN_EVENT_ID, + galleryItems = listOf( + GalleryItemData( + filename = "video.mp4", + mimeType = MimeTypes.Mp4, + mediaSource = MediaSource("video_url"), + thumbnailSource = MediaSource("thumbnail_url"), + type = GalleryItemData.Type.Video, + ) + ), + galleryInfo = aGalleryInfo(), + ) + val data = (result.getLastData() as AsyncData.Success).data + assertThat(data.fileItems).isEmpty() + assertThat(data.imageAndVideoItems).containsExactly( + MediaItem.Video( + id = UniqueId("${AN_EVENT_ID.value}_0"), + eventId = AN_EVENT_ID, + mediaInfo = expectedMediaInfo("video.mp4", MimeTypes.Mp4), + mediaSource = MediaSource("video_url"), + thumbnailSource = MediaSource("thumbnail_url"), + ) + ) + } + + @Test + fun `createFrom with audio item creates MediaItem Audio in imageAndVideoItems`() { + val result = GalleryMediaGalleryDataSource.createFrom( + eventId = AN_EVENT_ID, + galleryItems = listOf( + GalleryItemData( + filename = "audio.mp3", + mimeType = MimeTypes.Mp3, + mediaSource = MediaSource("audio_url"), + thumbnailSource = null, + type = GalleryItemData.Type.Audio, + ) + ), + galleryInfo = aGalleryInfo(), + ) + val data = (result.getLastData() as AsyncData.Success).data + assertThat(data.fileItems).isEmpty() + assertThat(data.imageAndVideoItems).containsExactly( + MediaItem.Audio( + id = UniqueId("${AN_EVENT_ID.value}_0"), + eventId = AN_EVENT_ID, + mediaInfo = expectedMediaInfo("audio.mp3", MimeTypes.Mp3), + mediaSource = MediaSource("audio_url"), + ) + ) + } + + @Test + fun `createFrom with file item creates MediaItem File in imageAndVideoItems`() { + val result = GalleryMediaGalleryDataSource.createFrom( + eventId = AN_EVENT_ID, + galleryItems = listOf( + GalleryItemData( + filename = "document.pdf", + mimeType = MimeTypes.Pdf, + mediaSource = MediaSource("file_url"), + thumbnailSource = null, + type = GalleryItemData.Type.File, + ) + ), + galleryInfo = aGalleryInfo(), + ) + val data = (result.getLastData() as AsyncData.Success).data + assertThat(data.fileItems).isEmpty() + assertThat(data.imageAndVideoItems).containsExactly( + MediaItem.File( + id = UniqueId("${AN_EVENT_ID.value}_0"), + eventId = AN_EVENT_ID, + mediaInfo = expectedMediaInfo("document.pdf", MimeTypes.Pdf), + mediaSource = MediaSource("file_url"), + ) + ) + } + + @Test + fun `createFrom uses gallery prefix when eventId is null`() { + val result = GalleryMediaGalleryDataSource.createFrom( + eventId = null, + galleryItems = listOf( + GalleryItemData( + filename = "image.jpg", + mimeType = MimeTypes.Jpeg, + mediaSource = MediaSource("image_url"), + thumbnailSource = null, + type = GalleryItemData.Type.Image, + ) + ), + galleryInfo = aGalleryInfo(), + ) + val data = (result.getLastData() as AsyncData.Success).data + val item = data.imageAndVideoItems.single() as MediaItem.Image + assertThat(item.id).isEqualTo(UniqueId("gallery_0")) + assertThat(item.eventId).isNull() + } + + @Test + fun `createFrom with multiple items produces indexed IDs and all go to imageAndVideoItems`() { + val result = GalleryMediaGalleryDataSource.createFrom( + eventId = AN_EVENT_ID, + galleryItems = listOf( + GalleryItemData( + filename = "image.jpg", + mimeType = MimeTypes.Jpeg, + mediaSource = MediaSource("image_url"), + thumbnailSource = null, + type = GalleryItemData.Type.Image, + ), + GalleryItemData( + filename = "document.pdf", + mimeType = MimeTypes.Pdf, + mediaSource = MediaSource("file_url"), + thumbnailSource = null, + type = GalleryItemData.Type.File, + ), + GalleryItemData( + filename = "video.mp4", + mimeType = MimeTypes.Mp4, + mediaSource = MediaSource("video_url"), + thumbnailSource = null, + type = GalleryItemData.Type.Video, + ), + ), + galleryInfo = aGalleryInfo(), + ) + val data = (result.getLastData() as AsyncData.Success).data + assertThat(data.fileItems).isEmpty() + assertThat(data.imageAndVideoItems).hasSize(3) + assertThat((data.imageAndVideoItems[0] as MediaItem.Image).id).isEqualTo(UniqueId("${AN_EVENT_ID.value}_0")) + assertThat((data.imageAndVideoItems[1] as MediaItem.File).id).isEqualTo(UniqueId("${AN_EVENT_ID.value}_1")) + assertThat((data.imageAndVideoItems[2] as MediaItem.Video).id).isEqualTo(UniqueId("${AN_EVENT_ID.value}_2")) + } + + private fun aGalleryInfo() = GalleryInfo( + caption = "A caption", + formattedCaption = null, + senderId = A_USER_ID, + senderName = "Alice", + senderAvatar = null, + dateSent = "Today", + dateSentFull = "Today at 12:00", + initialIndex = 0, + ) + + private fun expectedMediaInfo(filename: String, mimeType: String) = MediaInfo( + filename = filename, + fileSize = null, + caption = "A caption", + mimeType = mimeType, + formattedFileSize = "", + fileExtension = filename.substringAfterLast('.', ""), + senderId = A_USER_ID, + senderName = "Alice", + senderAvatar = null, + dateSent = "Today", + dateSentFull = "Today at 12:00", + waveform = null, + duration = null, + ) +} diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index 459d30b8d5..f917e8e0d1 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions import io.element.android.libraries.matrix.test.timeline.FakeTimeline +import io.element.android.libraries.mediaviewer.api.AvatarInfo import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.api.anApkMediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory @@ -109,7 +110,11 @@ class MediaViewerPresenterTest { fun `present - initial state cannot show info`() = runTest { val presenter = createMediaViewerPresenter( localMediaFactory = localMediaFactory, - canShowInfo = false, + inputs = MediaViewerEntryPoint.Params.Avatar( + avatarInfo = AvatarInfo(filename = "avatar.png"), + mediaSource = aMediaSource(), + thumbnailSource = null, + ), room = FakeJoinedRoom( baseRoom = FakeBaseRoom( roomPermissions = FakeRoomPermissions( @@ -639,7 +644,7 @@ class MediaViewerPresenterTest { } ) ) - skipItems(2) + skipItems(1) val stateWithSnackbar = awaitItem() assertThat(stateWithSnackbar.snackbarMessage!!.messageResId).isEqualTo(expectedSnackbarResId) } @@ -932,29 +937,31 @@ class MediaViewerPresenterTest { internal fun TestScope.createMediaViewerPresenter( localMediaFactory: LocalMediaFactory, + inputs: MediaViewerEntryPoint.Params? = null, eventId: EventId? = null, - mode: MediaViewerEntryPoint.MediaViewerMode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia, + mode: MediaViewerEntryPoint.MediaViewerMode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(Timeline.Mode.Media), matrixMediaLoader: FakeMatrixMediaLoader = FakeMatrixMediaLoader(), localMediaActions: FakeLocalMediaActions = FakeLocalMediaActions(), mediaGalleryDataSource: MediaGalleryDataSource = FakeMediaGalleryDataSource( startLambda = { }, ), - canShowInfo: Boolean = true, mediaViewerNavigator: MediaViewerNavigator = FakeMediaViewerNavigator(), room: JoinedRoom = FakeJoinedRoom( liveTimeline = FakeTimeline(), ), ): MediaViewerPresenter { + val actualInputs = inputs ?: createMediaViewerEntryPointParams(eventId = eventId, mode = mode) + val actualMode = when (actualInputs) { + is MediaViewerEntryPoint.Params.Avatar -> MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(Timeline.Mode.Media) + is MediaViewerEntryPoint.Params.EventGallery -> MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(Timeline.Mode.Media) + is MediaViewerEntryPoint.Params.RoomMedia -> actualInputs.mode + } return MediaViewerPresenter( - inputs = createMediaViewerEntryPointParams( - eventId = eventId, - mode = mode, - canShowInfo = canShowInfo, - ), + inputs = actualInputs, navigator = mediaViewerNavigator, dataSource = MediaViewerDataSource( coroutineScope = backgroundScope, - mode = mode, + mode = actualMode, dispatcher = testCoroutineDispatchers().computation, galleryDataSource = mediaGalleryDataSource, mediaLoader = matrixMediaLoader, @@ -969,13 +976,11 @@ internal fun TestScope.createMediaViewerPresenter( internal fun createMediaViewerEntryPointParams( eventId: EventId? = null, - mode: MediaViewerEntryPoint.MediaViewerMode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia, - canShowInfo: Boolean = true, -) = MediaViewerEntryPoint.Params( + mode: MediaViewerEntryPoint.MediaViewerMode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode = Timeline.Mode.Media), +) = MediaViewerEntryPoint.Params.RoomMedia( mode = mode, eventId = eventId, mediaInfo = TESTED_MEDIA_INFO, mediaSource = aMediaSource(), thumbnailSource = null, - canShowInfo = canShowInfo, ) diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerViewTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerViewTest.kt index 6521f450f5..d2780bb408 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerViewTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerViewTest.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipeDown import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.mediaviewer.impl.details.aMediaBottomSheetStateDetails @@ -37,16 +36,15 @@ import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.setSafeContent import io.mockk.mockk import kotlinx.coroutines.delay import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config import kotlin.time.Duration.Companion.milliseconds -@RunWith(AndroidJUnit4::class) -class MediaViewerViewTest { +class MediaViewerViewTest : RobolectricTest() { private val mockMediaUrl: Uri = mockk("localMediaUri") @Test @@ -135,28 +133,6 @@ class MediaViewerViewTest { ) } - @Test - @Config(qualifiers = "h1024dp") - fun `clicking on download emits expected Event`() { - val data = aMediaViewerPageData() - testBottomSheetAction( - data, - CommonStrings.action_download, - MediaViewerEvent.SaveOnDisk(data), - ) - } - - @Test - @Config(qualifiers = "h1024dp") - fun `clicking on share emits expected Event`() { - val data = aMediaViewerPageData() - testBottomSheetAction( - data, - CommonStrings.action_share, - MediaViewerEvent.Share(data), - ) - } - @Config(qualifiers = "h1024dp") @Test fun `clicking on open in emits expected Event`() { diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt index 8c0a7c05d0..a869690907 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt @@ -160,23 +160,20 @@ class SingleMediaGalleryDataSourceTest { private fun testFactory( mediaInfo: MediaInfo, - expectedResult: (MediaViewerEntryPoint.Params) -> MediaItem, + expectedResult: (MediaViewerEntryPoint.Params.RoomMedia) -> MediaItem, ) { val params = aMediaViewerEntryPointParams(mediaInfo) - val result = SingleMediaGalleryDataSource.createFrom(params) - val resultData = result.getLastData().dataOrNull() - assertThat(resultData!!.imageAndVideoItems.first()).isEqualTo(expectedResult(params)) - assertThat(resultData.fileItems).isEmpty() + val result = params.toMediaItem() + assertThat(result).isEqualTo(expectedResult(params)) } internal fun aMediaViewerEntryPointParams( mediaInfo: MediaInfo, - ) = MediaViewerEntryPoint.Params( - mode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia, + ) = MediaViewerEntryPoint.Params.RoomMedia( + mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(Timeline.Mode.Media), eventId = AN_EVENT_ID, mediaInfo = mediaInfo, mediaSource = aMediaSource(url = "aUrl"), thumbnailSource = aMediaSource(url = "aThumbnailUrl"), - canShowInfo = true, ) } diff --git a/libraries/network/build.gradle.kts b/libraries/network/build.gradle.kts index 72e7eb05f2..20f75091d9 100644 --- a/libraries/network/build.gradle.kts +++ b/libraries/network/build.gradle.kts @@ -24,6 +24,7 @@ android { setupDependencyInjection() dependencies { + implementation(libs.coroutines.core) implementation(projects.libraries.androidutils) implementation(projects.libraries.core) implementation(projects.libraries.di) diff --git a/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/OAuthUrlParser.kt b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/OAuthUrlParser.kt index e62dea696f..7e2c4d03f5 100644 --- a/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/OAuthUrlParser.kt +++ b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/OAuthUrlParser.kt @@ -12,6 +12,7 @@ import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider import io.element.android.libraries.oauth.api.OAuthAction +import timber.log.Timber fun interface OAuthUrlParser { fun parse(url: String): OAuthAction? @@ -38,7 +39,8 @@ class DefaultOAuthUrlParser( if (url.contains("error=access_denied")) return OAuthAction.GoBack() if (url.contains("code=")) return OAuthAction.Success(url) - // Other case not supported, let's crash the app for now - error("Not supported: $url") + // Other cases are not supported, log an error and return null + Timber.w("Unsupported OAuth url") + return null } } diff --git a/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolverTest.kt b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolverTest.kt index ff34ae8220..a93debd46a 100644 --- a/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolverTest.kt +++ b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolverTest.kt @@ -13,14 +13,11 @@ import androidx.core.net.toUri import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider import io.element.android.libraries.oauth.api.OAuthAction -import org.junit.Assert.assertThrows +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment -@RunWith(RobolectricTestRunner::class) -class DefaultOAuthIntentResolverTest { +class DefaultOAuthIntentResolverTest : RobolectricTest() { @Test fun `test resolve OAuth go back`() { val sut = createDefaultOAuthIntentResolver() @@ -54,9 +51,8 @@ class DefaultOAuthIntentResolverTest { action = Intent.ACTION_VIEW data = "io.element.android:/invalid".toUri() } - assertThrows(IllegalStateException::class.java) { - sut.resolve(intent) - } + val result = sut.resolve(intent) + assertThat(result).isNull() } private fun createDefaultOAuthIntentResolver(): DefaultOAuthIntentResolver { diff --git a/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthUrlParserTest.kt b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthUrlParserTest.kt index 6377414862..7dde7356d4 100644 --- a/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthUrlParserTest.kt +++ b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthUrlParserTest.kt @@ -11,7 +11,6 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.auth.FAKE_REDIRECT_URL import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider import io.element.android.libraries.oauth.api.OAuthAction -import org.junit.Assert import org.junit.Test class DefaultOAuthUrlParserTest { @@ -45,9 +44,7 @@ class DefaultOAuthUrlParserTest { fun `test unknown url`() { val sut = createDefaultOAuthUrlParser() val anUnknownUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&goat=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" - Assert.assertThrows(IllegalStateException::class.java) { - assertThat(sut.parse(anUnknownUrl)) - } + assertThat(sut.parse(anUnknownUrl)).isNull() } private fun createDefaultOAuthUrlParser(): DefaultOAuthUrlParser { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt index 64583bd1d4..2f3fa9b0b7 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt @@ -41,6 +41,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageT import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.EventType import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType @@ -344,6 +345,7 @@ class DefaultNotifiableEventResolver( is TextMessageType -> messageType.toPlainText(permalinkParser = permalinkParser) is VideoMessageType -> messageType.bestDescription is LocationMessageType -> messageType.body + is GalleryMessageType -> messageType.body is OtherMessageType -> messageType.body } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt index e328c46209..b6d15dac4e 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt @@ -11,6 +11,7 @@ package io.element.android.libraries.push.impl.notifications import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.SingleIn +import io.element.android.features.lockscreen.api.LockScreenService import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.EventId @@ -37,6 +38,7 @@ import io.element.android.services.appnavstate.api.currentRoomId import io.element.android.services.appnavstate.api.currentSessionId import io.element.android.services.appnavstate.api.currentThreadId import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch /** @@ -55,6 +57,7 @@ class DefaultNotificationDrawerManager( private val matrixClientProvider: MatrixClientProvider, private val imageLoaderHolder: ImageLoaderHolder, private val activeNotificationsProvider: ActiveNotificationsProvider, + private val lockScreenService: LockScreenService, sessionObserver: SessionObserver, ) : NotificationCleaner { // TODO EAx add a setting per user for this @@ -197,6 +200,8 @@ class DefaultNotificationDrawerManager( it.sessionId } + val isAppLocked = lockScreenService.isPinSetup().first() + for ((sessionId, notifiableEvents) in eventsForSessions) { val client = matrixClientProvider.getOrRestore(sessionId).getOrThrow() val imageLoader = imageLoaderHolder.get(client) @@ -207,7 +212,25 @@ class DefaultNotificationDrawerManager( } else { client.getUserProfile().getOrNull() ?: MatrixUser(sessionId) } - notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents, imageLoader) + if (isAppLocked) { + // When the app is locked, show a single fallback notification with event count + // instead of per-room notifications with message content/sender info. + clearAllMessagesEvents(sessionId) + val fallbackEvents = notifiableEvents.mapNotNull { it.toFallbackNotifiableEvent() } + notificationRenderer.render( + currentUser = currentUser, + useCompleteNotificationFormat = false, + eventsToProcess = fallbackEvents, + imageLoader = imageLoader, + ) + } else { + notificationRenderer.render( + currentUser = currentUser, + useCompleteNotificationFormat = useCompleteNotificationFormat, + eventsToProcess = notifiableEvents, + imageLoader = imageLoader, + ) + } } } } @@ -238,3 +261,29 @@ private fun AppNavigationState.shouldIgnoreEvent(event: NotifiableEvent): Boolea } } } + +/** + * Convert a [NotifiableEvent] into a [FallbackNotifiableEvent], stripping all content and sender info. + * Used when notification content should be hidden (app locked with PIN). + */ +private fun NotifiableEvent.toFallbackNotifiableEvent(): FallbackNotifiableEvent? { + val timestamp = when (this) { + is NotifiableMessageEvent -> timestamp + is InviteNotifiableEvent -> timestamp + is SimpleNotifiableEvent -> timestamp + is FallbackNotifiableEvent -> timestamp + is NotifiableRingingCallEvent -> return null + } + return FallbackNotifiableEvent( + sessionId = sessionId, + roomId = roomId, + eventId = eventId, + editedEventId = null, + description = null, + canBeReplaced = false, + isRedacted = false, + isUpdated = false, + timestamp = timestamp, + cause = null, + ) +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/RoomGroupMessageCreator.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/RoomGroupMessageCreator.kt index 150f4a9a2d..d814fcaeb2 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/RoomGroupMessageCreator.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/RoomGroupMessageCreator.kt @@ -67,7 +67,7 @@ class DefaultRoomGroupMessageCreator( val roomIsDm = !roomIsGroup return notificationCreator.createMessagesListNotification( notificationAccountParams = notificationAccountParams, - RoomEventGroupInfo( + roomInfo = RoomEventGroupInfo( sessionId = notificationAccountParams.user.userId, roomId = roomId, roomDisplayName = roomName, diff --git a/libraries/push/impl/src/main/res/values-in/translations.xml b/libraries/push/impl/src/main/res/values-in/translations.xml index 4baa46d5a9..0d6dc613ac 100644 --- a/libraries/push/impl/src/main/res/values-in/translations.xml +++ b/libraries/push/impl/src/main/res/values-in/translations.xml @@ -48,6 +48,8 @@ "Sinkronisasi latar belakang" "Layanan Google" "Tidak ditemukan Layanan Google Play yang valid. Pemberitahuan mungkin tidak berfungsi dengan baik." + "Memeriksa pengguna yang diblokir" + "Tidak ada pengguna yang diblokir." "Pengguna yang diblokir" "Dapatkan nama penyedia saat ini." "Tidak ada penyedia notifikasi dorongan yang dipilih." diff --git a/libraries/push/impl/src/main/res/values-ru/translations.xml b/libraries/push/impl/src/main/res/values-ru/translations.xml index c0b597588b..2fe8645d82 100644 --- a/libraries/push/impl/src/main/res/values-ru/translations.xml +++ b/libraries/push/impl/src/main/res/values-ru/translations.xml @@ -15,8 +15,8 @@ "%d уведомления" "%d уведомлений" - "Не удалось зарегистрировать дистрибьютора уведомлений UnifiedPush, поэтому вы больше не будете получать уведомления. Проверьте настройки уведомлений в приложении и статус дистрибьютора push-уведомлений." - "У вас есть новые сообщения." + "Не удалось зарегистрировать дистрибьютора уведомлений UnifiedPush, поэтому Вы больше не будете получать уведомления. Проверьте настройки уведомлений в приложении и статус дистрибьютора push-уведомлений." + "У Вас есть новые сообщения." "У Вас %d новое сообщение." "У Вас %d новых сообщения." @@ -32,8 +32,8 @@ "%d приглашения" "%d приглашений" - "Пригласил(а) вас в чат" - "%1$s пригласил(а) вас в чат" + "Пригласил(а) Вас в чат" + "%1$s пригласил(а) Вас в чат" "Упомянул(а) вас: %1$s" "Новые сообщения" @@ -44,12 +44,12 @@ "Отреагировал(а) на %1$s" "Пометить как прочитанное" "Быстрый ответ" - "Пригласил(а) вас в комнату" - "%1$s пригласил(а) вас в комнату" + "Пригласил(а) Вас в комнату" + "%1$s пригласил(а) Вас в комнату" "Я" "%1$s упомянул(а) или ответил(а)" - "Пригласил(а) вас в пространство" - "%1$s пригласил(а) вас в пространство" + "Пригласил(а) Вас в пространство" + "%1$s пригласил(а) Вас в пространство" "Вы просматриваете уведомление! Нажмите на меня!" "Обсуждение в %1$s" "%1$s: %2$s" diff --git a/libraries/push/impl/src/main/res/values-uk/translations.xml b/libraries/push/impl/src/main/res/values-uk/translations.xml index 9c5f74605f..345fe6a7be 100644 --- a/libraries/push/impl/src/main/res/values-uk/translations.xml +++ b/libraries/push/impl/src/main/res/values-uk/translations.xml @@ -15,14 +15,14 @@ "%d сповіщення" "%d сповіщень" - "Розподільник сповіщень UnifiedPush не вдалося зареєструвати, тому ви більше не отримуватимете сповіщень. Перевірте налаштування сповіщень у додатку та статус розподільника push-сповіщень." + "Розподільник сповіщень UnifiedPush не вдалося зареєструвати, тому ви більше не отримуватимете сповіщень. Перевірте налаштування сповіщень у застосунку та стан розподільника push-сповіщень." "У вас є нові повідомлення." "У вас %d нове повідомлення." "У вас %d нових повідомлення." "У вас %d нових повідомлень." - "📞 Вхідний дзвінок" + "📞 Вхідний виклик" "📹 Вхідний виклик" "** Не вдалося надіслати - відкрийте кімнату" "Доєднатися" @@ -33,7 +33,7 @@ "%d запрошень" "Запрошує вас до бесіди" - "%1$s запросив вас до чату" + "%1$s запрошує вас до бесіди" "Вас згадує: %1$s" "Нові повідомлення" @@ -81,7 +81,7 @@ "Заблоковані користувачі" "Отримує назву поточного постачальника." "Постачальників push-сповіщень не вибрано." - "Поточний провайдер push-повідомлень: %1$s та поточний дистриб\'ютор: %2$s. Але дистриб\'ютор %3$s не знайдено. Можливо, додаток було видалено?" + "Поточний провайдер push-повідомлень: %1$s та поточний дистриб\'ютор: %2$s. Але дистриб\'ютора %3$s не знайдено. Можливо, застосунок було видалено?" "Поточний постачальник push-сповіщень: %1$s, але дистриб\'юторів не налаштовано." "Поточний постачальник: %1$s." "Поточний постачальник push-сповіщень: %1$s (%2$s)" diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt index dd1dd7b74d..b3358ba97f 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/battery/AndroidBatteryOptimizationTest.kt @@ -16,12 +16,10 @@ import com.google.common.truth.Truth.assertThat import io.element.android.services.toolbox.api.intent.ExternalIntentLauncher import io.element.android.services.toolbox.test.intent.FakeExternalIntentLauncher import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class AndroidBatteryOptimizationTest { +class AndroidBatteryOptimizationTest : RobolectricTest() { @Test fun `isIgnoringBatteryOptimizations should return false`() { val sut = createAndroidBatteryOptimization() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultActiveNotificationsProviderTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultActiveNotificationsProviderTest.kt index 04a65073f6..df9697b94f 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultActiveNotificationsProviderTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultActiveNotificationsProviderTest.kt @@ -19,14 +19,12 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID_2 import io.element.android.libraries.matrix.test.A_THREAD_ID import io.element.android.libraries.push.api.notifications.NotificationIdProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.mockk.every import io.mockk.mockk import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultActiveNotificationsProviderTest { +class DefaultActiveNotificationsProviderTest : RobolectricTest() { private val notificationIdProvider = NotificationIdProvider @Test diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt index 3caec04add..408063712a 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt @@ -31,18 +31,16 @@ import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiable import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider import io.element.android.services.toolbox.impl.strings.AndroidStringProvider import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment private const val A_ROOM_AVATAR = "mxc://roomAvatar" private const val A_USER_AVATAR_1 = "mxc://userAvatar1" private const val A_USER_AVATAR_2 = "mxc://userAvatar2" -@RunWith(RobolectricTestRunner::class) -class DefaultBaseRoomGroupMessageCreatorTest { +class DefaultBaseRoomGroupMessageCreatorTest : RobolectricTest() { @Test fun `test createRoomMessage with one Event`() = runTest { val sut = createRoomGroupMessageCreator() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt index 33634e1767..e196ddb0ec 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt @@ -59,16 +59,14 @@ import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEv import io.element.android.services.toolbox.impl.strings.AndroidStringProvider import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP import io.element.android.services.toolbox.test.systemclock.FakeSystemClock +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config @Suppress("LargeClass") -@RunWith(RobolectricTestRunner::class) -class DefaultNotifiableEventResolverTest { +class DefaultNotifiableEventResolverTest : RobolectricTest() { @Test fun `resolve event no session`() = runTest { val sut = createDefaultNotifiableEventResolver(notificationService = null) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt index 04da6ef556..4e2685e63a 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt @@ -13,6 +13,8 @@ import androidx.compose.ui.graphics.Color import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService +import io.element.android.features.lockscreen.api.LockScreenService +import io.element.android.features.lockscreen.test.FakeLockScreenService import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID_2 @@ -510,6 +512,7 @@ fun TestScope.createDefaultNotificationDrawerManager( enterpriseService: EnterpriseService = FakeEnterpriseService(), sessionObserver: SessionObserver = FakeSessionObserver(), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), + lockScreenService: LockScreenService = FakeLockScreenService(), ): DefaultNotificationDrawerManager { return DefaultNotificationDrawerManager( notificationDisplayer = notificationDisplayer, @@ -530,6 +533,7 @@ fun TestScope.createDefaultNotificationDrawerManager( matrixClientProvider = matrixClientProvider, imageLoaderHolder = FakeImageLoaderHolder(), activeNotificationsProvider = activeNotificationsProvider, + lockScreenService = lockScreenService, sessionObserver = sessionObserver, ) } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultSummaryGroupMessageCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultSummaryGroupMessageCreatorTest.kt index 0973ee69ce..f623214fc4 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultSummaryGroupMessageCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultSummaryGroupMessageCreatorTest.kt @@ -18,13 +18,11 @@ import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.nonNull +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultSummaryGroupMessageCreatorTest { +class DefaultSummaryGroupMessageCreatorTest : RobolectricTest() { @Test fun `process notifications`() = runTest { val notificationCreator = FakeNotificationCreator() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt index 2cf666d92a..fa77e2d761 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt @@ -49,6 +49,7 @@ import io.element.android.services.toolbox.test.systemclock.FakeSystemClock import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -56,12 +57,8 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner - @ExperimentalCoroutinesApi -@RunWith(RobolectricTestRunner::class) -class NotificationBroadcastReceiverHandlerTest { +class NotificationBroadcastReceiverHandlerTest : RobolectricTest() { private val actionIds = NotificationActionIds(aBuildMeta()) @Test diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDataFactoryTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDataFactoryTest.kt index f897388c66..1a46546db8 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDataFactoryTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDataFactoryTest.kt @@ -24,10 +24,9 @@ import io.element.android.libraries.push.impl.notifications.fixtures.aFallbackNo import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner private val MY_AVATAR_URL: String? = null @@ -36,8 +35,7 @@ private val A_SIMPLE_EVENT = aSimpleNotifiableEvent(eventId = AN_EVENT_ID) private val A_MESSAGE_EVENT = aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID) private val A_FALLBACK_EVENT = aFallbackNotifiableEvent() -@RunWith(RobolectricTestRunner::class) -class NotificationDataFactoryTest { +class NotificationDataFactoryTest : RobolectricTest() { private val notificationCreator = FakeNotificationCreator() private val fakeRoomGroupMessageCreator = FakeRoomGroupMessageCreator() private val fakeSummaryGroupMessageCreator = FakeSummaryGroupMessageCreator() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt index 6ca19b7acc..43991444fe 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt @@ -32,10 +32,9 @@ import io.element.android.libraries.sessionstorage.test.InMemorySessionStore import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner private const val MY_USER_DISPLAY_NAME = "display-name" private const val MY_USER_AVATAR_URL = "avatar-url" @@ -45,8 +44,7 @@ private val A_SUMMARY_NOTIFICATION = SummaryNotification.Update(A_NOTIFICATION) private val ONE_SHOT_NOTIFICATION = OneShotNotification(notification = A_NOTIFICATION, tag = "ignored", isNoisy = false, timestamp = -1) -@RunWith(RobolectricTestRunner::class) -class NotificationRendererTest { +class NotificationRendererTest : RobolectricTest() { private val notificationDisplayer = FakeNotificationDisplayer() private val notificationCreator = FakeNotificationCreator() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/channels/NotificationChannelsTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/channels/NotificationChannelsTest.kt index c53e98bc93..1df87232f5 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/channels/NotificationChannelsTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/channels/NotificationChannelsTest.kt @@ -21,19 +21,17 @@ import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.preferences.api.store.NotificationSound import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.services.toolbox.test.strings.FakeStringProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.mockk.every import io.mockk.mockk import io.mockk.slot import io.mockk.verify import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -@RunWith(RobolectricTestRunner::class) -class NotificationChannelsTest { +class NotificationChannelsTest : RobolectricTest() { @Test @Config(sdk = [Build.VERSION_CODES.TIRAMISU]) fun `init - creates notification channels and migrates old ones`() { diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/conversations/DefaultNotificationConversationServiceTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/conversations/DefaultNotificationConversationServiceTest.kt index d4d7713c2d..41e601c50d 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/conversations/DefaultNotificationConversationServiceTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/conversations/DefaultNotificationConversationServiceTest.kt @@ -26,18 +26,15 @@ import io.element.android.libraries.push.impl.notifications.factories.FakeIntent import io.element.android.libraries.push.impl.notifications.shortcut.createShortcutId import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader import io.element.android.libraries.sessionstorage.test.observer.FakeSessionObserver +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config - -@RunWith(RobolectricTestRunner::class) @Config(sdk = [Build.VERSION_CODES.TIRAMISU]) -class DefaultNotificationConversationServiceTest { +class DefaultNotificationConversationServiceTest : RobolectricTest() { @Test fun `onSendMessage adds a shortcut`() = runTest { val context = InstrumentationRegistry.getInstrumentation().context diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt index 53bea9e766..38b387a180 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/factories/DefaultNotificationCreatorTest.kt @@ -45,14 +45,12 @@ import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvid import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP import io.element.android.services.toolbox.test.systemclock.FakeSystemClock +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment -@RunWith(RobolectricTestRunner::class) -class DefaultNotificationCreatorTest { +class DefaultNotificationCreatorTest : RobolectricTest() { @Test fun `test createDiagnosticNotification`() { val sut = createNotificationCreator() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt index 33071ef1ac..a0c233bc39 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt @@ -57,7 +57,17 @@ class FakeNotificationCreator( events: List, ): Notification { return createMessagesListNotificationResult( - listOf(notificationAccountParams, roomInfo, threadId, largeIcon, lastMessageTimestamp, tickerText, existingNotification, imageLoader, events) + listOf( + notificationAccountParams, + roomInfo, + threadId, + largeIcon, + lastMessageTimestamp, + tickerText, + existingNotification, + imageLoader, + events, + ) ) } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/sound/DefaultNotificationSoundCopierTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/sound/DefaultNotificationSoundCopierTest.kt index b8d652bafe..e57829b218 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/sound/DefaultNotificationSoundCopierTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/sound/DefaultNotificationSoundCopierTest.kt @@ -10,14 +10,12 @@ package io.element.android.libraries.push.impl.notifications.sound import android.content.Context import com.google.common.truth.Truth.assertThat import io.element.android.libraries.push.api.notifications.sound.NotificationSoundCopier +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment -@RunWith(RobolectricTestRunner::class) -class DefaultNotificationSoundCopierTest { +class DefaultNotificationSoundCopierTest : RobolectricTest() { private val context: Context get() = RuntimeEnvironment.getApplication() @Test diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultFetchPushForegroundServiceManagerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultFetchPushForegroundServiceManagerTest.kt index 63307634f3..2c0ca8e854 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultFetchPushForegroundServiceManagerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultFetchPushForegroundServiceManagerTest.kt @@ -12,21 +12,19 @@ import android.content.ComponentName import android.content.Context.ACTIVITY_SERVICE import android.content.Context.POWER_SERVICE import android.os.PowerManager -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.google.common.truth.Truth.assertThat +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.async import kotlinx.coroutines.test.runTest import kotlinx.coroutines.withTimeout import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.Shadows import org.robolectric.shadows.ShadowActivityManager import org.robolectric.shadows.ShadowPowerManager import kotlin.time.Duration.Companion.seconds -@RunWith(AndroidJUnit4::class) -class DefaultFetchPushForegroundServiceManagerTest { +class DefaultFetchPushForegroundServiceManagerTest : RobolectricTest() { @Test fun `start should start the service if the device is not interactive`() { val manager = createDefaultFetchPushForegroundServiceManager() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultOnRedactedEventReceivedTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultOnRedactedEventReceivedTest.kt index 2bab4c14c2..8c7f9e0454 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultOnRedactedEventReceivedTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultOnRedactedEventReceivedTest.kt @@ -30,15 +30,13 @@ import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEv import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultOnRedactedEventReceivedTest { +class DefaultOnRedactedEventReceivedTest : RobolectricTest() { private val fakePerson = Person.Builder().setName(A_USER_NAME).setKey(A_USER_ID.value).build() private val fakeMessage = NotificationCompat.MessagingStyle.Message("A message", 0L, fakePerson).also { it.extras.putString(DefaultNotificationCreator.MESSAGE_EVENT_ID, AN_EVENT_ID.value) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/DefaultSyncPendingNotificationsRequestBuilderTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/DefaultSyncPendingNotificationsRequestBuilderTest.kt index e65bea20a9..49d0d12ec8 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/DefaultSyncPendingNotificationsRequestBuilderTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/DefaultSyncPendingNotificationsRequestBuilderTest.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.push.impl.workmanager import android.net.NetworkCapabilities -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.work.OneTimeWorkRequest import androidx.work.hasKeyWithValueOfType import com.google.common.truth.Truth.assertThat @@ -21,14 +20,13 @@ import io.element.android.libraries.workmanager.api.WorkManagerRequestType import io.element.android.libraries.workmanager.api.WorkManagerWorkerType import io.element.android.libraries.workmanager.api.workManagerTag import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config @Config(sdk = [33]) -@RunWith(AndroidJUnit4::class) -class DefaultSyncPendingNotificationsRequestBuilderTest { +class DefaultSyncPendingNotificationsRequestBuilderTest : RobolectricTest() { @Test fun `build - success API 33`() = runTest { val request = createSyncPendingNotificationsRequestBuilder( diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt index c0fa5d3442..889fb878d2 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/workmanager/FetchPendingNotificationWorkerTest.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.push.impl.workmanager -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import androidx.work.Data import androidx.work.ListenableWorker @@ -34,12 +33,12 @@ import io.element.android.libraries.workmanager.api.di.MetroWorkerFactory import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.toolbox.test.systemclock.FakeSystemClock import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith import java.util.UUID import java.util.concurrent.Executor import java.util.concurrent.Executors @@ -48,8 +47,7 @@ import kotlin.time.Duration.Companion.seconds import kotlin.time.Instant @OptIn(ExperimentalCoroutinesApi::class) -@RunWith(AndroidJUnit4::class) -class FetchPendingNotificationWorkerTest { +class FetchPendingNotificationWorkerTest : RobolectricTest() { @Test fun `test - success`() = runTest { var synced = false diff --git a/libraries/pushproviders/firebase/build.gradle.kts b/libraries/pushproviders/firebase/build.gradle.kts index ffa4e9fa70..1a8e73a4da 100644 --- a/libraries/pushproviders/firebase/build.gradle.kts +++ b/libraries/pushproviders/firebase/build.gradle.kts @@ -11,6 +11,8 @@ import config.BuildTimeConfig import extension.setupDependencyInjection import extension.testCommonDependencies +import org.gradle.kotlin.dsl.withType +import org.sonarqube.gradle.SonarResolverTask plugins { id("io.element.android-library") @@ -19,6 +21,10 @@ plugins { android { namespace = "io.element.android.libraries.pushproviders.firebase" + buildFeatures { + resValues = true + } + buildTypes { getByName("release") { consumerProguardFiles("consumer-proguard-rules.pro") @@ -47,6 +53,11 @@ android { } } +// Configure the SonarQube plugin to wait for the resource generation tasks to complete before running the analysis. +tasks.withType().configureEach { + dependsOn("generateDebugResValues", "generateDebugAndroidTestResValues") +} + setupDependencyInjection() dependencies { diff --git a/libraries/pushproviders/firebase/src/main/AndroidManifest.xml b/libraries/pushproviders/firebase/src/main/AndroidManifest.xml index 24bad30d77..9a6972e412 100644 --- a/libraries/pushproviders/firebase/src/main/AndroidManifest.xml +++ b/libraries/pushproviders/firebase/src/main/AndroidManifest.xml @@ -7,6 +7,10 @@ --> + + { - val pushKey = firebaseStore.getFcmToken() ?: return Result.failure( + val pushKey = firebaseStore.getInstallationId() ?: return Result.failure( IllegalStateException( "Unable to register pusher, Firebase token is not known." ) @@ -59,7 +59,7 @@ class FirebasePushProvider( override suspend fun getCurrentDistributor(sessionId: SessionId) = firebaseDistributor override suspend fun unregister(matrixClient: MatrixClient): Result { - val pushKey = firebaseStore.getFcmToken() + val pushKey = firebaseStore.getInstallationId() return if (pushKey == null) { Timber.tag(loggerTag.value).w("Unable to unregister pusher, Firebase token is not known.") Result.success(Unit) @@ -74,7 +74,7 @@ class FirebasePushProvider( override suspend fun onSessionDeleted(sessionId: SessionId) = Unit override suspend fun getPushConfig(sessionId: SessionId): Config? { - return firebaseStore.getFcmToken()?.let { fcmToken -> + return firebaseStore.getInstallationId()?.let { fcmToken -> Config( url = firebaseGatewayProvider.getFirebaseGateway(), pushKey = fcmToken @@ -85,7 +85,7 @@ class FirebasePushProvider( override fun canRotateToken(): Boolean = true override suspend fun rotateToken(): Result { - return firebaseTokenRotator.rotate() + return rotateFirebaseSession() } companion object { diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt index 1f6a4709cc..748d540a54 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt @@ -18,28 +18,28 @@ import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onStart /** - * This class store the Firebase token in SharedPrefs. + * This class stores the Firebase installationId in SharedPrefs. */ interface FirebaseStore { - fun getFcmToken(): String? - fun fcmTokenFlow(): Flow - fun storeFcmToken(token: String?) + fun getInstallationId(): String? + fun fcmInstallationIdFlow(): Flow + fun storeInstallationId(installationId: String?) } @ContributesBinding(AppScope::class) class SharedPreferencesFirebaseStore( private val sharedPreferences: SharedPreferences, ) : FirebaseStore { - override fun getFcmToken(): String? { - return sharedPreferences.getString(PREFS_KEY_FCM_TOKEN, null) + override fun getInstallationId(): String? { + return sharedPreferences.getString(PREFS_KEY_FCM_INSTALLATION_ID, null) } - override fun fcmTokenFlow(): Flow { - val flow = MutableStateFlow(getFcmToken()) + override fun fcmInstallationIdFlow(): Flow { + val flow = MutableStateFlow(getInstallationId()) val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, k -> - if (k == PREFS_KEY_FCM_TOKEN) { + if (k == PREFS_KEY_FCM_INSTALLATION_ID) { try { - flow.value = getFcmToken() + flow.value = getInstallationId() } catch (_: Exception) { flow.value = null } @@ -50,13 +50,13 @@ class SharedPreferencesFirebaseStore( .onCompletion { sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) } } - override fun storeFcmToken(token: String?) { + override fun storeInstallationId(installationId: String?) { sharedPreferences.edit { - putString(PREFS_KEY_FCM_TOKEN, token) + putString(PREFS_KEY_FCM_INSTALLATION_ID, installationId) } } companion object { - private const val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" + private const val PREFS_KEY_FCM_INSTALLATION_ID = "FCM_TOKEN" } } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenDeleter.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenDeleter.kt deleted file mode 100644 index 21fa189121..0000000000 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenDeleter.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2023-2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.pushproviders.firebase - -import com.google.firebase.messaging.FirebaseMessaging -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding -import timber.log.Timber -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -interface FirebaseTokenDeleter { - /** - * Deletes the current Firebase token. - */ - suspend fun delete() -} - -@ContributesBinding(AppScope::class) -class DefaultFirebaseTokenDeleter( - private val isPlayServiceAvailable: IsPlayServiceAvailable, -) : FirebaseTokenDeleter { - override suspend fun delete() { - // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' - isPlayServiceAvailable.checkAvailableOrThrow() - suspendCoroutine { continuation -> - try { - FirebaseMessaging.getInstance().deleteToken() - .addOnSuccessListener { - continuation.resume(Unit) - } - .addOnFailureListener { e -> - Timber.e(e, "## deleteFirebaseToken() : failed") - continuation.resumeWithException(e) - } - } catch (e: Throwable) { - Timber.e(e, "## deleteFirebaseToken() : failed") - continuation.resumeWithException(e) - } - } - } -} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenGetter.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenGetter.kt deleted file mode 100644 index 80fd9726d4..0000000000 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenGetter.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2023-2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.pushproviders.firebase - -import com.google.firebase.messaging.FirebaseMessaging -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding -import timber.log.Timber -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -interface FirebaseTokenGetter { - /** - * Read the current Firebase token from FirebaseMessaging. - * If the token does not exist, it will be generated. - */ - suspend fun get(): String -} - -@ContributesBinding(AppScope::class) -class DefaultFirebaseTokenGetter( - private val isPlayServiceAvailable: IsPlayServiceAvailable, -) : FirebaseTokenGetter { - override suspend fun get(): String { - // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' - isPlayServiceAvailable.checkAvailableOrThrow() - return suspendCoroutine { continuation -> - try { - FirebaseMessaging.getInstance().token - .addOnSuccessListener { token -> - continuation.resume(token) - } - .addOnFailureListener { e -> - Timber.e(e, "## retrievedFirebaseToken() : failed") - continuation.resumeWithException(e) - } - } catch (e: Throwable) { - Timber.e(e, "## retrievedFirebaseToken() : failed") - continuation.resumeWithException(e) - } - } - } -} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenRotator.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenRotator.kt deleted file mode 100644 index 78b33cbb08..0000000000 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTokenRotator.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2024, 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.pushproviders.firebase - -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.core.extensions.runCatchingExceptions - -interface FirebaseTokenRotator { - suspend fun rotate(): Result -} - -/** - * This class delete the Firebase token and generate a new one. - */ -@ContributesBinding(AppScope::class) -class DefaultFirebaseTokenRotator( - private val firebaseTokenDeleter: FirebaseTokenDeleter, - private val firebaseTokenGetter: FirebaseTokenGetter, -) : FirebaseTokenRotator { - override suspend fun rotate(): Result { - return runCatchingExceptions { - firebaseTokenDeleter.delete() - firebaseTokenGetter.get() - } - } -} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt index 78fce0338d..0e58133a60 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt @@ -10,7 +10,6 @@ package io.element.android.libraries.pushproviders.firebase import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.core.extensions.runCatchingExceptions interface FirebaseTroubleshooter { suspend fun troubleshoot(): Result @@ -21,13 +20,9 @@ interface FirebaseTroubleshooter { */ @ContributesBinding(AppScope::class) class DefaultFirebaseTroubleshooter( - private val newTokenHandler: FirebaseNewTokenHandler, - private val firebaseTokenGetter: FirebaseTokenGetter, + private val rotateFirebaseSession: RotateFirebaseSession, ) : FirebaseTroubleshooter { override suspend fun troubleshoot(): Result { - return runCatchingExceptions { - val token = firebaseTokenGetter.get() - newTokenHandler.handle(token) - } + return rotateFirebaseSession() } } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/RegisterFirebaseSession.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/RegisterFirebaseSession.kt new file mode 100644 index 0000000000..42604bd013 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/RegisterFirebaseSession.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2023-2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.pushproviders.firebase + +import com.google.firebase.messaging.FirebaseMessaging +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.pushproviders.firebase.util.runFirebaseTask +import timber.log.Timber + +fun interface RegisterFirebaseSession { + /** + * Register the device to Firebase Messaging. + */ + suspend operator fun invoke(): Result +} + +@ContributesBinding(AppScope::class) +class DefaultRegisterFirebaseSession( + private val isPlayServiceAvailable: IsPlayServiceAvailable, +) : RegisterFirebaseSession { + override suspend operator fun invoke(): Result { + // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' + isPlayServiceAvailable.checkAvailableOrThrow() + return runFirebaseTask { FirebaseMessaging.getInstance().register() } + .onFailure { Timber.e(it, "## registerFirebaseMessaging() : failed") } + // Change return type from Void! to Unit + .map {} + } +} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/RotateFirebaseSession.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/RotateFirebaseSession.kt new file mode 100644 index 0000000000..a6e51dafa2 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/RotateFirebaseSession.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2024, 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.pushproviders.firebase + +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.core.extensions.runCatchingExceptions + +fun interface RotateFirebaseSession { + suspend operator fun invoke(): Result +} + +/** + * This class deletes the Firebase installation id and generates a new one. + */ +@ContributesBinding(AppScope::class) +class DefaultRotateFirebaseSession( + private val registerFirebaseSession: RegisterFirebaseSession, + private val unregisterFirebaseSession: UnregisterFirebaseSession, +) : RotateFirebaseSession { + override suspend operator fun invoke(): Result { + return runCatchingExceptions { + // Stop the current session, which will also delete the existing installation id from Firebase + unregisterFirebaseSession().getOrThrow() + // Register again to get a new installation id + registerFirebaseSession().getOrThrow() + } + } +} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/UnregisterFirebaseSession.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/UnregisterFirebaseSession.kt new file mode 100644 index 0000000000..815f2d734c --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/UnregisterFirebaseSession.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2023-2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.pushproviders.firebase + +import com.google.firebase.installations.FirebaseInstallations +import com.google.firebase.messaging.FirebaseMessaging +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.pushproviders.firebase.util.runFirebaseTask +import timber.log.Timber + +fun interface UnregisterFirebaseSession { + /** + * Deletes the current Firebase token. + */ + suspend operator fun invoke(): Result +} + +@ContributesBinding(AppScope::class) +class DefaultUnregisterFirebaseSession( + private val isPlayServiceAvailable: IsPlayServiceAvailable, +) : UnregisterFirebaseSession { + override suspend operator fun invoke(): Result { + // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' + isPlayServiceAvailable.checkAvailableOrThrow() + return runFirebaseTask { + // Unregister the device from Firebase Messaging + FirebaseMessaging.getInstance().unregister() + // Also delete the existing installation id from Firebase + .continueWithTask { FirebaseInstallations.getInstance().delete() } + } + .onFailure { + Timber.e(it, "## unregisterFirebaseMessaging() : failed") + } + // Change return type from Void! to Unit + .map {} + } +} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt index 975a3c75ca..cd6ad3c8bc 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt @@ -24,7 +24,7 @@ import timber.log.Timber private val loggerTag = LoggerTag("VectorFirebaseMessagingService", LoggerTag.PushLoggerTag) class VectorFirebaseMessagingService : FirebaseMessagingService() { - @Inject lateinit var firebaseNewTokenHandler: FirebaseNewTokenHandler + @Inject lateinit var firebaseNewInstallationIdHandler: FirebaseNewInstallationIdHandler @Inject lateinit var pushParser: FirebasePushParser @Inject lateinit var pushHandler: PushHandler @Inject lateinit var fetchPushForegroundServiceManager: FetchPushForegroundServiceManager @@ -36,10 +36,12 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { bindings().inject(this) } - override fun onNewToken(token: String) { - Timber.tag(loggerTag.value).w("New Firebase token") + override fun onRegistered(installationId: String) { + super.onRegistered(installationId) + + Timber.tag(loggerTag.value).w("New Firebase installation id") coroutineScope.launch { - firebaseNewTokenHandler.handle(token) + firebaseNewInstallationIdHandler.handle(installationId) } } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt index 7ea7c6cee2..c3af8df542 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt @@ -49,7 +49,7 @@ class FirebaseTokenTest( override suspend fun run(coroutineScope: CoroutineScope) { currentJob?.cancel() delegate.start() - currentJob = firebaseStore.fcmTokenFlow() + currentJob = firebaseStore.fcmInstallationIdFlow() .onEach { token -> if (token != null) { delegate.updateState( diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/util/RunFirebaseTask.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/util/RunFirebaseTask.kt new file mode 100644 index 0000000000..0ddde69d1e --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/util/RunFirebaseTask.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.pushproviders.firebase.util + +import com.google.android.gms.tasks.Task +import io.element.android.libraries.core.extensions.runCatchingExceptions +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +suspend fun runFirebaseTaskWithResult(closure: () -> Task): Result { + return runCatchingExceptions { + suspendCancellableCoroutine { continuation -> + try { + closure().addOnSuccessListener { + continuation.resume(it) + }.addOnFailureListener { e -> + continuation.resumeWithException(e) + } + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } + } +} + +// Special case for `Void!` return type, which is not a valid Kotlin type. We convert it to `Unit` instead. +suspend fun runFirebaseTask(closure: () -> Task): Result { + return runFirebaseTaskWithResult { closure().continueWith {} } +} diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/DefaultFirebaseNewTokenHandlerTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/DefaultFirebaseNewInstallationIdHandlerTest.kt similarity index 96% rename from libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/DefaultFirebaseNewTokenHandlerTest.kt rename to libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/DefaultFirebaseNewInstallationIdHandlerTest.kt index 4db9ea667f..78d35fe2a5 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/DefaultFirebaseNewTokenHandlerTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/DefaultFirebaseNewInstallationIdHandlerTest.kt @@ -30,16 +30,16 @@ import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.test.runTest import org.junit.Test -class DefaultFirebaseNewTokenHandlerTest { +class DefaultFirebaseNewInstallationIdHandlerTest { @Test fun `when a new token is received it is stored in the firebase store`() = runTest { val firebaseStore = InMemoryFirebaseStore() - assertThat(firebaseStore.getFcmToken()).isNull() + assertThat(firebaseStore.getInstallationId()).isNull() val firebaseNewTokenHandler = createDefaultFirebaseNewTokenHandler( firebaseStore = firebaseStore, ) firebaseNewTokenHandler.handle("aToken") - assertThat(firebaseStore.getFcmToken()).isEqualTo("aToken") + assertThat(firebaseStore.getInstallationId()).isEqualTo("aToken") } @Test @@ -142,8 +142,8 @@ class DefaultFirebaseNewTokenHandlerTest { matrixClientProvider: MatrixClientProvider = FakeMatrixClientProvider(), firebaseStore: FirebaseStore = InMemoryFirebaseStore(), firebaseGatewayProvider: FirebaseGatewayProvider = FakeFirebaseGatewayProvider(), - ): FirebaseNewTokenHandler { - return DefaultFirebaseNewTokenHandler( + ): FirebaseNewInstallationIdHandler { + return DefaultFirebaseNewInstallationIdHandler( pusherSubscriber = pusherSubscriber, sessionStore = sessionStore, userPushStoreFactory = userPushStoreFactory, diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseNewTokenHandler.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseNewInstallationIdHandler.kt similarity index 71% rename from libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseNewTokenHandler.kt rename to libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseNewInstallationIdHandler.kt index 2fa9508103..b6b310fbb8 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseNewTokenHandler.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseNewInstallationIdHandler.kt @@ -10,10 +10,10 @@ package io.element.android.libraries.pushproviders.firebase import io.element.android.tests.testutils.lambda.lambdaError -class FakeFirebaseNewTokenHandler( +class FakeFirebaseNewInstallationIdHandler( private val handleResult: (String) -> Unit = { lambdaError() } -) : FirebaseNewTokenHandler { - override suspend fun handle(firebaseToken: String) { - handleResult(firebaseToken) +) : FirebaseNewInstallationIdHandler { + override suspend fun handle(installationId: String) { + handleResult(installationId) } } diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseTokenRotator.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeRotateFirebaseSession.kt similarity index 81% rename from libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseTokenRotator.kt rename to libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeRotateFirebaseSession.kt index d504aa32ae..34ae929af8 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseTokenRotator.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeRotateFirebaseSession.kt @@ -10,10 +10,10 @@ package io.element.android.libraries.pushproviders.firebase import io.element.android.tests.testutils.lambda.lambdaError -class FakeFirebaseTokenRotator( +class FakeRotateFirebaseSession( private val rotateWithResult: () -> Result = { lambdaError() } -) : FirebaseTokenRotator { - override suspend fun rotate(): Result { +) : RotateFirebaseSession { + override suspend fun invoke(): Result { return rotateWithResult() } } diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProviderTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProviderTest.kt index 312689da6e..a2737bc377 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProviderTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProviderTest.kt @@ -61,7 +61,7 @@ class FirebasePushProviderTest { val registerPusherResultLambda = lambdaRecorder> { _, _, _ -> Result.success(Unit) } val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = "aToken" + installationId = "aToken" ), pusherSubscriber = FakePusherSubscriber( registerPusherResult = registerPusherResultLambda @@ -78,7 +78,7 @@ class FirebasePushProviderTest { fun `register ko no token`() = runTest { val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = null + installationId = null ), pusherSubscriber = FakePusherSubscriber( registerPusherResult = { _, _, _ -> Result.success(Unit) } @@ -92,7 +92,7 @@ class FirebasePushProviderTest { fun `register ko error`() = runTest { val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = "aToken" + installationId = "aToken" ), pusherSubscriber = FakePusherSubscriber( registerPusherResult = { _, _, _ -> Result.failure(AN_EXCEPTION) } @@ -108,7 +108,7 @@ class FirebasePushProviderTest { val unregisterPusherResultLambda = lambdaRecorder> { _, _, _ -> Result.success(Unit) } val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = "aToken" + installationId = "aToken" ), pusherSubscriber = FakePusherSubscriber( unregisterPusherResult = unregisterPusherResultLambda @@ -125,7 +125,7 @@ class FirebasePushProviderTest { fun `unregister no token - in this case, the error is ignored`() = runTest { val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = null + installationId = null ), ) val result = firebasePushProvider.unregister(FakeMatrixClient()) @@ -136,7 +136,7 @@ class FirebasePushProviderTest { fun `unregister ko error`() = runTest { val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = "aToken" + installationId = "aToken" ), pusherSubscriber = FakePusherSubscriber( unregisterPusherResult = { _, _, _ -> Result.failure(AN_EXCEPTION) } @@ -150,7 +150,7 @@ class FirebasePushProviderTest { fun `getCurrentUserPushConfig no push ket`() = runTest { val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = null + installationId = null ) ) val result = firebasePushProvider.getPushConfig(A_SESSION_ID) @@ -161,7 +161,7 @@ class FirebasePushProviderTest { fun `getCurrentUserPushConfig ok`() = runTest { val firebasePushProvider = createFirebasePushProvider( firebaseStore = InMemoryFirebaseStore( - token = "aToken" + installationId = "aToken" ), ) val result = firebasePushProvider.getPushConfig(A_SESSION_ID) @@ -169,10 +169,10 @@ class FirebasePushProviderTest { } @Test - fun `rotateToken invokes the FirebaseTokenRotator`() = runTest { + fun `rotateToken invokes the FirebaseMessagingSessionRotator`() = runTest { val lambda = lambdaRecorder> { Result.success(Unit) } val firebasePushProvider = createFirebasePushProvider( - firebaseTokenRotator = FakeFirebaseTokenRotator(lambda), + rotateFirebaseSession = FakeRotateFirebaseSession(lambda), ) firebasePushProvider.rotateToken() lambda.assertions().isCalledOnce() @@ -194,14 +194,14 @@ class FirebasePushProviderTest { firebaseStore: FirebaseStore = InMemoryFirebaseStore(), pusherSubscriber: PusherSubscriber = FakePusherSubscriber(), isPlayServiceAvailable: IsPlayServiceAvailable = FakeIsPlayServiceAvailable(false), - firebaseTokenRotator: FirebaseTokenRotator = FakeFirebaseTokenRotator(), + rotateFirebaseSession: RotateFirebaseSession = FakeRotateFirebaseSession(), firebaseGatewayProvider: FirebaseGatewayProvider = FakeFirebaseGatewayProvider() ): FirebasePushProvider { return FirebasePushProvider( firebaseStore = firebaseStore, pusherSubscriber = pusherSubscriber, isPlayServiceAvailable = isPlayServiceAvailable, - firebaseTokenRotator = firebaseTokenRotator, + rotateFirebaseSession = rotateFirebaseSession, firebaseGatewayProvider = firebaseGatewayProvider, ) } diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt index 3e6292f445..9e55cdcb4d 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt @@ -12,13 +12,13 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf class InMemoryFirebaseStore( - private var token: String? = null + private var installationId: String? = null ) : FirebaseStore { - override fun getFcmToken(): String? = token + override fun getInstallationId(): String? = installationId - override fun fcmTokenFlow(): Flow = flowOf(token) + override fun fcmInstallationIdFlow(): Flow = flowOf(installationId) - override fun storeFcmToken(token: String?) { - this.token = token + override fun storeInstallationId(installationId: String?) { + this.installationId = installationId } } diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingServiceTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingServiceTest.kt index a04c961ebb..d640e3c858 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingServiceTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingServiceTest.kt @@ -21,17 +21,15 @@ import io.element.android.libraries.pushproviders.api.PushData import io.element.android.libraries.pushproviders.api.PushHandler import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class VectorFirebaseMessagingServiceTest { +class VectorFirebaseMessagingServiceTest : RobolectricTest() { @Test fun `test receiving invalid data`() = runTest { val lambda = lambdaRecorder { _, _ -> } @@ -173,22 +171,22 @@ class VectorFirebaseMessagingServiceTest { fun `test new token is forwarded to the handler`() = runTest { val lambda = lambdaRecorder { } val vectorFirebaseMessagingService = createVectorFirebaseMessagingService( - firebaseNewTokenHandler = FakeFirebaseNewTokenHandler(handleResult = lambda) + firebaseNewInstallationIdHandler = FakeFirebaseNewInstallationIdHandler(handleResult = lambda) ) - vectorFirebaseMessagingService.onNewToken("aToken") + vectorFirebaseMessagingService.onRegistered("installationId") advanceUntilIdle() lambda.assertions() .isCalledOnce() - .with(value("aToken")) + .with(value("installationId")) } private fun TestScope.createVectorFirebaseMessagingService( - firebaseNewTokenHandler: FirebaseNewTokenHandler = FakeFirebaseNewTokenHandler(), + firebaseNewInstallationIdHandler: FirebaseNewInstallationIdHandler = FakeFirebaseNewInstallationIdHandler(), pushHandler: PushHandler = FakePushHandler(), pushHandlingWakeLock: FakeFetchPushForegroundServiceManager = FakeFetchPushForegroundServiceManager(), ): VectorFirebaseMessagingService { return VectorFirebaseMessagingService().apply { - this.firebaseNewTokenHandler = firebaseNewTokenHandler + this.firebaseNewInstallationIdHandler = firebaseNewInstallationIdHandler this.pushParser = FirebasePushParser() this.pushHandler = pushHandler this.coroutineScope = this@createVectorFirebaseMessagingService diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt index 8f9721a17d..963a4352ec 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt @@ -45,7 +45,7 @@ class FirebaseTokenTestTest { firebaseStore = firebaseStore, firebaseTroubleshooter = FakeFirebaseTroubleshooter( troubleShootResult = { - firebaseStore.storeFcmToken(FAKE_TOKEN) + firebaseStore.storeInstallationId(FAKE_TOKEN) Result.success(Unit) } ), @@ -70,7 +70,7 @@ class FirebaseTokenTestTest { firebaseStore = firebaseStore, firebaseTroubleshooter = FakeFirebaseTroubleshooter( troubleShootResult = { - firebaseStore.storeFcmToken(FAKE_TOKEN) + firebaseStore.storeInstallationId(FAKE_TOKEN) Result.success(Unit) } ), diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/GuardServiceStarter.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/GuardServiceStarter.kt deleted file mode 100644 index 4a8eefe37f..0000000000 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/GuardServiceStarter.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2023-2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.pushproviders.unifiedpush - -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding - -interface GuardServiceStarter { - fun start() {} - fun stop() {} -} - -@ContributesBinding(AppScope::class) -class NoopGuardServiceStarter : GuardServiceStarter diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushGatewayUrlResolver.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushGatewayUrlResolver.kt index 78a569a211..1155293567 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushGatewayUrlResolver.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushGatewayUrlResolver.kt @@ -29,8 +29,9 @@ class DefaultUnifiedPushGatewayUrlResolver( ): String { return when (gatewayResult) { is UnifiedPushGatewayResolverResult.Error -> { - // Use previous gateway if any, or the provided one - unifiedPushStore.getPushGateway(instance) ?: gatewayResult.gateway + // Use previous gateway if any, or the default one + unifiedPushStore.getPushGateway(instance) + ?: defaultPushGatewayHttpUrlProvider.provide() } UnifiedPushGatewayResolverResult.ErrorInvalidUrl, UnifiedPushGatewayResolverResult.NoMatrixGateway -> { diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt index 4288f2b6b8..b1e9ba648b 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt @@ -31,7 +31,6 @@ private val loggerTag = LoggerTag("VectorUnifiedPushMessagingReceiver", LoggerTa class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { @Inject lateinit var pushParser: UnifiedPushParser @Inject lateinit var pushHandler: PushHandler - @Inject lateinit var guardServiceStarter: GuardServiceStarter @Inject lateinit var unifiedPushStore: UnifiedPushStore @Inject lateinit var unifiedPushGatewayResolver: UnifiedPushGatewayResolver @Inject lateinit var unifiedPushGatewayUrlResolver: UnifiedPushGatewayUrlResolver @@ -112,7 +111,6 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { ) ) } - guardServiceStarter.stop() } /** diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultRegisterUnifiedPushUseCaseTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultRegisterUnifiedPushUseCaseTest.kt index 1e77df79a2..fe7da75951 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultRegisterUnifiedPushUseCaseTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultRegisterUnifiedPushUseCaseTest.kt @@ -16,17 +16,15 @@ import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult import io.element.android.tests.testutils.fake.FakeAndroidKeyStore +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultRegisterUnifiedPushUseCaseTest { +class DefaultRegisterUnifiedPushUseCaseTest : RobolectricTest() { @Before fun setup() { FakeAndroidKeyStore.setup diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnifiedPushGatewayUrlResolverTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnifiedPushGatewayUrlResolverTest.kt index 3f437bdafa..664ff26d15 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnifiedPushGatewayUrlResolverTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnifiedPushGatewayUrlResolverTest.kt @@ -60,7 +60,7 @@ class DefaultUnifiedPushGatewayUrlResolverTest { } @Test - fun `resolve Error returns the url if no current url is available`() { + fun `resolve Error returns the default gateway url if no current url is available`() { val sut = createDefaultUnifiedPushGatewayUrlResolver( unifiedPushStore = FakeUnifiedPushStore( getPushGatewayResult = { instance -> @@ -73,7 +73,7 @@ class DefaultUnifiedPushGatewayUrlResolverTest { gatewayResult = UnifiedPushGatewayResolverResult.Error("aUrl"), instance = "instance", ) - assertThat(result).isEqualTo("aUrl") + assertThat(result).isEqualTo(FakeDefaultPushGatewayHttpUrlProvider().provide()) } private fun createDefaultUnifiedPushGatewayUrlResolver( diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnregisterUnifiedPushUseCaseTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnregisterUnifiedPushUseCaseTest.kt index ed2337c5bb..e6454406d5 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnregisterUnifiedPushUseCaseTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/DefaultUnregisterUnifiedPushUseCaseTest.kt @@ -18,13 +18,11 @@ import io.element.android.libraries.push.test.FakePusherSubscriber import io.element.android.libraries.pushproviders.api.PusherSubscriber import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class DefaultUnregisterUnifiedPushUseCaseTest { +class DefaultUnregisterUnifiedPushUseCaseTest : RobolectricTest() { @Test fun `test un registration successful`() = runTest { val lambda = lambdaRecorder { _: MatrixClient, _: String, _: String -> Result.success(Unit) } diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt index cb23289c85..6d86cb2b9d 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt @@ -27,21 +27,19 @@ import io.element.android.libraries.pushproviders.unifiedpush.registration.Regis import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner import org.unifiedpush.android.connector.FailedReason import org.unifiedpush.android.connector.data.PublicKeySet import org.unifiedpush.android.connector.data.PushEndpoint import org.unifiedpush.android.connector.data.PushMessage -@RunWith(RobolectricTestRunner::class) -class VectorUnifiedPushMessagingReceiverTest { +class VectorUnifiedPushMessagingReceiverTest : RobolectricTest() { @Test fun `onReceive does the binding`() = runTest { val context = InstrumentationRegistry.getInstrumentation().context @@ -268,7 +266,6 @@ class VectorUnifiedPushMessagingReceiverTest { return VectorUnifiedPushMessagingReceiver().apply { this.pushParser = unifiedPushParser this.pushHandler = pushHandler - this.guardServiceStarter = NoopGuardServiceStarter() this.unifiedPushStore = unifiedPushStore this.unifiedPushGatewayResolver = unifiedPushGatewayResolver this.unifiedPushGatewayUrlResolver = unifiedPushGatewayUrlResolver diff --git a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt index 8ad2d62b33..fe9494a2c8 100644 --- a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt +++ b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt @@ -56,7 +56,6 @@ class UserPushStoreDataStore( private val currentPushKey = stringPreferencesKey("currentPushKey") private val notificationEnabled = booleanPreferencesKey("notificationEnabled") private val ignoreRegistrationError = booleanPreferencesKey("ignoreRegistrationError") - override suspend fun getPushProviderName(): String? { return store.data.first()[pushProviderName] } diff --git a/libraries/pushstore/impl/src/test/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStoreTest.kt b/libraries/pushstore/impl/src/test/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStoreTest.kt index 9191ea4ab4..773a5e3430 100644 --- a/libraries/pushstore/impl/src/test/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStoreTest.kt +++ b/libraries/pushstore/impl/src/test/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStoreTest.kt @@ -14,14 +14,12 @@ import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID_2 import io.element.android.libraries.preferences.test.FakePreferenceDataStoreFactory +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class UserPushStoreDataStoreTest { +class UserPushStoreDataStoreTest : RobolectricTest() { @Test fun `test getPushProviderName`() = runTest { val sut = createUserPushStoreDataStore() diff --git a/libraries/roomselect/api/src/main/kotlin/io/element/android/libraries/roomselect/api/RoomSelectEntryPoint.kt b/libraries/roomselect/api/src/main/kotlin/io/element/android/libraries/roomselect/api/RoomSelectEntryPoint.kt index ba5ca79d40..3c5c5d5ac3 100644 --- a/libraries/roomselect/api/src/main/kotlin/io/element/android/libraries/roomselect/api/RoomSelectEntryPoint.kt +++ b/libraries/roomselect/api/src/main/kotlin/io/element/android/libraries/roomselect/api/RoomSelectEntryPoint.kt @@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.core.RoomId interface RoomSelectEntryPoint : FeatureEntryPoint { data class Params( val mode: RoomSelectMode, + val maxNumberOfRooms: Int, ) fun createNode( @@ -30,4 +31,8 @@ interface RoomSelectEntryPoint : FeatureEntryPoint { fun onRoomSelected(roomIds: List) fun onCancel() } + + companion object { + const val DEFAULT_MAX_NUMBER_OF_ROOMS = 10 + } } diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPoint.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPoint.kt index 4ca92663a9..ff3ba06f0d 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPoint.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPoint.kt @@ -26,7 +26,10 @@ class DefaultRoomSelectEntryPoint : RoomSelectEntryPoint { return parentNode.createNode( buildContext = buildContext, plugins = listOf( - RoomSelectNode.Inputs(mode = params.mode), + RoomSelectNode.Inputs( + mode = params.mode, + maxNumberOfRooms = params.maxNumberOfRooms, + ), callback, ) ) diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvent.kt similarity index 60% rename from libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt rename to libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvent.kt index a3512c419c..13c5bc5f8d 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvent.kt @@ -10,11 +10,8 @@ package io.element.android.libraries.roomselect.impl import io.element.android.libraries.matrix.ui.model.SelectRoomInfo -sealed interface RoomSelectEvents { - data class SetSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvents - - // TODO remove to restore multi-selection - data object RemoveSelectedRoom : RoomSelectEvents - data object ToggleSearchActive : RoomSelectEvents - data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvents +sealed interface RoomSelectEvent { + data class ToggleSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvent + data object ToggleSearchActive : RoomSelectEvent + data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvent } diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectNode.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectNode.kt index 943da643c6..0297f13066 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectNode.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectNode.kt @@ -35,10 +35,14 @@ class RoomSelectNode( ) : Node(buildContext, plugins = plugins) { data class Inputs( val mode: RoomSelectMode, + val maxNumberOfRooms: Int, ) : NodeInputs private val inputs: Inputs = inputs() - private val presenter = presenterFactory.create(inputs.mode) + private val presenter = presenterFactory.create( + mode = inputs.mode, + maxNumberOfRooms = inputs.maxNumberOfRooms, + ) private val stateFlow = launchMolecule { presenter.present() } private val callback: RoomSelectEntryPoint.Callback = callback() diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt index b7547b8a45..85ecfe5ba7 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt @@ -34,11 +34,15 @@ import kotlinx.coroutines.launch @AssistedInject class RoomSelectPresenter( @Assisted private val mode: RoomSelectMode, + @Assisted private val maxNumberOfRooms: Int, private val dataSourceFactory: RoomSelectSearchDataSource.Factory, ) : Presenter { @AssistedFactory fun interface Factory { - fun create(mode: RoomSelectMode): RoomSelectPresenter + fun create( + mode: RoomSelectMode, + maxNumberOfRooms: Int, + ): RoomSelectPresenter } @Composable @@ -67,21 +71,18 @@ class RoomSelectPresenter( } } - fun handleEvent(event: RoomSelectEvents) { + fun handleEvent(event: RoomSelectEvent) { when (event) { - is RoomSelectEvents.SetSelectedRoom -> { - selectedRooms = persistentListOf(event.room) - // Restore for multi-selection -// val index = selectedRooms.indexOfFirst { it.roomId == event.room.roomId } -// selectedRooms = if (index >= 0) { -// selectedRooms.removeAt(index) -// } else { -// selectedRooms.add(event.room) -// } + is RoomSelectEvent.ToggleSelectedRoom -> { + val index = selectedRooms.indexOfFirst { it.roomId == event.room.roomId } + selectedRooms = if (index >= 0) { + selectedRooms.removingAt(index) + } else { + selectedRooms.adding(event.room) + } } - RoomSelectEvents.RemoveSelectedRoom -> selectedRooms = persistentListOf() - RoomSelectEvents.ToggleSearchActive -> isSearchActive = !isSearchActive - is RoomSelectEvents.UpdateVisibleRange -> coroutineScope.launch { + RoomSelectEvent.ToggleSearchActive -> isSearchActive = !isSearchActive + is RoomSelectEvent.UpdateVisibleRange -> coroutineScope.launch { dataSource.updateVisibleRange(event.range) } } @@ -89,6 +90,7 @@ class RoomSelectPresenter( return RoomSelectState( mode = mode, + maxNumberOfRooms = maxNumberOfRooms, resultState = searchResults, searchQuery = queryState, isSearchActive = isSearchActive, diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt index 927a1c02d6..aadb7c10d1 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt @@ -16,9 +16,12 @@ import kotlinx.collections.immutable.ImmutableList data class RoomSelectState( val mode: RoomSelectMode, + val maxNumberOfRooms: Int, val resultState: SearchBarResultState>, val searchQuery: TextFieldState, val isSearchActive: Boolean, val selectedRooms: ImmutableList, - val eventSink: (RoomSelectEvents) -> Unit -) + val eventSink: (RoomSelectEvent) -> Unit, +) { + val canSelectMoreRooms = selectedRooms.size < maxNumberOfRooms +} diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt index b0d18659b6..131e35429e 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt @@ -40,18 +40,26 @@ open class RoomSelectStateProvider : PreviewParameterProvider { mode = RoomSelectMode.Share, resultState = SearchBarResultState.Results(aRoomSelectRoomList()), ), + aRoomSelectState( + mode = RoomSelectMode.Share, + resultState = SearchBarResultState.Results(aRoomSelectRoomList()), + selectedRooms = aRoomSelectRoomList().subList(0, 1), + maxNumberOfRooms = 1, + ), ) } internal fun aRoomSelectState( mode: RoomSelectMode = RoomSelectMode.Forward, + maxNumberOfRooms: Int = 10, resultState: SearchBarResultState> = SearchBarResultState.Initial(), searchQuery: String = "", isSearchActive: Boolean = false, selectedRooms: ImmutableList = persistentListOf(), - eventSink: (RoomSelectEvents) -> Unit = {}, + eventSink: (RoomSelectEvent) -> Unit = {}, ) = RoomSelectState( mode = mode, + maxNumberOfRooms = maxNumberOfRooms, resultState = resultState, searchQuery = TextFieldState(initialText = searchQuery), isSearchActive = isSearchActive, diff --git a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt index 69f091ddc4..508fcd4fc2 100644 --- a/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt +++ b/libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt @@ -44,8 +44,8 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarType import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.Checkbox import io.element.android.libraries.designsystem.theme.components.HorizontalDivider -import io.element.android.libraries.designsystem.theme.components.RadioButton import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.SearchBar import io.element.android.libraries.designsystem.theme.components.SearchBarResultState @@ -71,26 +71,30 @@ fun RoomSelectView( onSubmit: (List) -> Unit, modifier: Modifier = Modifier, ) { - @Suppress("UNUSED_PARAMETER") fun onRoomRemoved(roomInfo: SelectRoomInfo) { - // TODO toggle selection when multi-selection is enabled - state.eventSink(RoomSelectEvents.RemoveSelectedRoom) + state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomInfo)) } @Composable - fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList) { - if (isForwarding) return - SelectedRooms( - selectedRooms = selectedRooms, - onRemoveRoom = ::onRoomRemoved, - modifier = Modifier.padding(vertical = 16.dp) - ) + fun SelectedRoomsHelper( + selectedRooms: ImmutableList, + showVerticalSpace: Boolean, + ) { + if (selectedRooms.isNotEmpty()) { + SelectedRooms( + selectedRooms = selectedRooms, + onRemoveRoom = ::onRoomRemoved, + modifier = Modifier.padding(vertical = 16.dp) + ) + } else if (showVerticalSpace) { + Spacer(modifier = Modifier.height(20.dp)) + } } var canHandleBack by remember { mutableStateOf(true) } fun onBackButton(state: RoomSelectState) { if (state.isSearchActive) { - state.eventSink(RoomSelectEvents.ToggleSearchActive) + state.eventSink(RoomSelectEvent.ToggleSearchActive) } else if (canHandleBack) { canHandleBack = false onDismiss() @@ -104,7 +108,7 @@ fun RoomSelectView( val lazyListState = rememberLazyListState() OnVisibleRangeChangeEffect(lazyListState) { visibleRange -> - state.eventSink(RoomSelectEvents.UpdateVisibleRange(visibleRange)) + state.eventSink(RoomSelectEvent.UpdateVisibleRange(visibleRange)) } Scaffold( @@ -141,16 +145,15 @@ fun RoomSelectView( placeHolderTitle = stringResource(CommonStrings.action_search), queryState = state.searchQuery, active = state.isSearchActive, - onActiveChange = { state.eventSink(RoomSelectEvents.ToggleSearchActive) }, + onActiveChange = { state.eventSink(RoomSelectEvent.ToggleSearchActive) }, resultState = state.resultState, showBackButton = false, ) { summaries -> LazyColumn(state = lazyListState) { item { SelectedRoomsHelper( - // TODO state.isForwarding - isForwarding = false, - selectedRooms = state.selectedRooms + selectedRooms = state.selectedRooms, + showVerticalSpace = false, ) } items(summaries, key = { it.roomId.value }) { roomSummary -> @@ -159,8 +162,9 @@ fun RoomSelectView( roomSummary, isSelected = state.selectedRooms.any { it.roomId == roomSummary.roomId }, onSelection = { roomSummary -> - state.eventSink(RoomSelectEvents.SetSelectedRoom(roomSummary)) - } + state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomSummary)) + }, + canBeSelected = state.canSelectMoreRooms, ) HorizontalDivider(modifier = Modifier.fillMaxWidth()) } @@ -169,13 +173,10 @@ fun RoomSelectView( } if (!state.isSearchActive) { - // TODO restore for multi-selection -// SelectedRoomsHelper( -// isForwarding = state.isForwarding, -// selectedRooms = state.selectedRooms -// ) - Spacer(modifier = Modifier.height(20.dp)) - + SelectedRoomsHelper( + selectedRooms = state.selectedRooms, + showVerticalSpace = true, + ) if (state.resultState is SearchBarResultState.Results) { LazyColumn(state = lazyListState) { items(state.resultState.results, key = { it.roomId.value }) { roomSummary -> @@ -184,8 +185,9 @@ fun RoomSelectView( roomSummary, isSelected = state.selectedRooms.any { it.roomId == roomSummary.roomId }, onSelection = { roomSummary -> - state.eventSink(RoomSelectEvents.SetSelectedRoom(roomSummary)) - } + state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomSummary)) + }, + canBeSelected = state.canSelectMoreRooms, ) HorizontalDivider(modifier = Modifier.fillMaxWidth()) } @@ -218,6 +220,7 @@ private fun SelectedRooms( private fun RoomSummaryView( roomInfo: SelectRoomInfo, isSelected: Boolean, + canBeSelected: Boolean, onSelection: (SelectRoomInfo) -> Unit, ) { Row( @@ -262,7 +265,11 @@ private fun RoomSummaryView( ) } } - RadioButton(selected = isSelected, onClick = { onSelection(roomInfo) }) + Checkbox( + checked = isSelected, + enabled = isSelected || canBeSelected, + onCheckedChange = { onSelection(roomInfo) }, + ) } } diff --git a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPointTest.kt b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPointTest.kt index a99a0396c2..6863c1ce20 100644 --- a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPointTest.kt +++ b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/DefaultRoomSelectEntryPointTest.kt @@ -9,7 +9,6 @@ package io.element.android.libraries.roomselect.impl import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.bumble.appyx.core.modality.BuildContext import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.RoomId @@ -17,14 +16,13 @@ import io.element.android.libraries.roomselect.api.RoomSelectEntryPoint import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode +import io.element.android.tests.testutils.robolectric.RobolectricTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class DefaultRoomSelectEntryPointTest { +class DefaultRoomSelectEntryPointTest : RobolectricTest() { @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() @@ -33,13 +31,15 @@ class DefaultRoomSelectEntryPointTest { fun `test node builder`() = runTest { val entryPoint = DefaultRoomSelectEntryPoint() val testMode = RoomSelectMode.Share + val testMaxNumberOfRooms = 12 val parentNode = TestParentNode.create { buildContext, plugins -> RoomSelectNode( buildContext = buildContext, plugins = plugins, - presenterFactory = { mode -> + presenterFactory = { mode, maxNumberOfRooms -> assertThat(mode).isEqualTo(testMode) - createRoomSelectPresenter(mode) + assertThat(maxNumberOfRooms).isEqualTo(testMaxNumberOfRooms) + createRoomSelectPresenter(mode, maxNumberOfRooms) }, ) } @@ -47,7 +47,10 @@ class DefaultRoomSelectEntryPointTest { override fun onRoomSelected(roomIds: List) = lambdaError() override fun onCancel() = lambdaError() } - val params = RoomSelectEntryPoint.Params(testMode) + val params = RoomSelectEntryPoint.Params( + mode = testMode, + maxNumberOfRooms = testMaxNumberOfRooms, + ) val result = entryPoint.createNode( parentNode = parentNode, buildContext = BuildContext.root(null), @@ -55,7 +58,7 @@ class DefaultRoomSelectEntryPointTest { callback = callback, ) assertThat(result).isInstanceOf(RoomSelectNode::class.java) - assertThat(result.plugins).contains(RoomSelectNode.Inputs(params.mode)) + assertThat(result.plugins).contains(RoomSelectNode.Inputs(params.mode, params.maxNumberOfRooms)) assertThat(result.plugins).contains(callback) } } diff --git a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt index 67c1b52231..b5a4ccfd12 100644 --- a/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt +++ b/libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt @@ -9,9 +9,6 @@ package io.element.android.libraries.roomselect.impl import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd -import app.cash.molecule.RecompositionMode -import app.cash.molecule.moleculeFlow -import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.roomlist.RoomListFilter @@ -20,10 +17,12 @@ import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.roomlist.FakeDynamicRoomList import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo +import io.element.android.libraries.roomselect.api.RoomSelectEntryPoint import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.test import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope @@ -40,26 +39,24 @@ class RoomSelectPresenterTest { @Test fun `present - initial state`() = runTest { val presenter = createRoomSelectPresenter() - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() assertThat(initialState.selectedRooms).isEmpty() assertThat(initialState.resultState).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() + assertThat(initialState.maxNumberOfRooms).isEqualTo(10) + assertThat(initialState.canSelectMoreRooms).isTrue() } } @Test fun `present - toggle search active`() = runTest { val presenter = createRoomSelectPresenter() - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() - initialState.eventSink(RoomSelectEvents.ToggleSearchActive) + initialState.eventSink(RoomSelectEvent.ToggleSearchActive) assertThat(awaitItem().isSearchActive).isTrue() - initialState.eventSink(RoomSelectEvents.ToggleSearchActive) + initialState.eventSink(RoomSelectEvent.ToggleSearchActive) assertThat(awaitItem().isSearchActive).isFalse() } } @@ -76,15 +73,13 @@ class RoomSelectPresenterTest { val presenter = createRoomSelectPresenter( roomListService = roomListService ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() val expectedRoomInfo = roomSummary.toSelectRoomInfo() // Do not compare the lambda because they will be different. So copy the lambda from expectedRoomSummary to result val result = (awaitItem().resultState as SearchBarResultState.Results).results assertThat(result).isEqualTo(listOf(expectedRoomInfo)) - initialState.eventSink(RoomSelectEvents.ToggleSearchActive) + initialState.eventSink(RoomSelectEvent.ToggleSearchActive) skipItems(1) initialState.searchQuery.setTextAndPlaceCursorAtEnd("string not contained") assertThat( @@ -110,17 +105,22 @@ class RoomSelectPresenterTest { createRoomListLambda = { roomList } ) val presenter = createRoomSelectPresenter( + maxNumberOfRooms = 1, roomListService = roomListService, ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() val roomInfo = roomSummary.toSelectRoomInfo() - initialState.eventSink(RoomSelectEvents.SetSelectedRoom(roomInfo)) - assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(roomInfo)) - initialState.eventSink(RoomSelectEvents.RemoveSelectedRoom) - assertThat(awaitItem().selectedRooms).isEmpty() + initialState.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomInfo)) + awaitItem().let { + assertThat(it.selectedRooms).isEqualTo(persistentListOf(roomInfo)) + assertThat(it.canSelectMoreRooms).isFalse() + it.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomInfo)) + } + awaitItem().let { + assertThat(it.selectedRooms).isEmpty() + assertThat(it.canSelectMoreRooms).isTrue() + } cancel() } } @@ -136,9 +136,7 @@ class RoomSelectPresenterTest { createRoomListLambda = { roomList } ) val presenter = createRoomSelectPresenter(roomListService = roomListService) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() // Post some rooms to simulate loaded content val rooms = (1..10).map { aRoomSummary() } @@ -146,7 +144,7 @@ class RoomSelectPresenterTest { skipItems(1) // UpdateVisibleRange near end should trigger loadMore - initialState.eventSink(RoomSelectEvents.UpdateVisibleRange(IntRange(0, 9))) + initialState.eventSink(RoomSelectEvent.UpdateVisibleRange(IntRange(0, 9))) // Give time for the coroutine to complete testScheduler.advanceUntilIdle() @@ -157,9 +155,11 @@ class RoomSelectPresenterTest { internal fun TestScope.createRoomSelectPresenter( mode: RoomSelectMode = RoomSelectMode.Forward, + maxNumberOfRooms: Int = RoomSelectEntryPoint.DEFAULT_MAX_NUMBER_OF_ROOMS, roomListService: RoomListService = FakeRoomListService(), ) = RoomSelectPresenter( mode = mode, + maxNumberOfRooms = maxNumberOfRooms, dataSourceFactory = object : RoomSelectSearchDataSource.Factory { override fun create(coroutineScope: CoroutineScope): RoomSelectSearchDataSource { return RoomSelectSearchDataSource( diff --git a/libraries/rustls-tls/src/main/kotlin/org/rustls/platformverifier/CertificateVerifier.kt b/libraries/rustls-tls/src/main/kotlin/org/rustls/platformverifier/CertificateVerifier.kt index 38abed0d92..b70413ffe5 100644 --- a/libraries/rustls-tls/src/main/kotlin/org/rustls/platformverifier/CertificateVerifier.kt +++ b/libraries/rustls-tls/src/main/kotlin/org/rustls/platformverifier/CertificateVerifier.kt @@ -14,7 +14,6 @@ package org.rustls.platformverifier import android.annotation.SuppressLint import android.content.Context import android.net.http.X509TrustManagerExtensions -import android.os.Build import android.util.Log import java.io.ByteArrayInputStream import java.io.File @@ -22,18 +21,13 @@ import java.security.KeyStore import java.security.KeyStoreException import java.security.MessageDigest import java.security.PublicKey -import java.security.cert.CertPathValidator -import java.security.cert.CertPathValidatorException import java.security.cert.CertificateException import java.security.cert.CertificateExpiredException import java.security.cert.CertificateFactory import java.security.cert.CertificateNotYetValidException import java.security.cert.CertificateParsingException -import java.security.cert.PKIXBuilderParameters -import java.security.cert.PKIXRevocationChecker import java.security.cert.X509Certificate import java.util.Date -import java.util.EnumSet import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager import javax.security.auth.x500.X500Principal @@ -298,90 +292,14 @@ internal object CertificateVerifier { return VerificationResult(StatusCode.Ok) } - // Try to check the revocation status of the cert, if it is supported. + // ================================================================================================= + // IMPORTANT! DIFF WITH THE ORIGINAL SOURCES HERE: // - // This is supported at >= API 24, but we're supporting 22 (Android 5) for the best - // compatibility. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - // Note: - // - // 1. Android does not provide any way only to attempt to validate revocation from cached - // data like the other platforms do. This means it will always use the network for - // certificates which had no stapled response. - // - // 2: Likely because of 1, Android requires all issued certificates to have some form of - // revocation included in their authority information. This doesn't work universally as - // issuing certificates in use may omit authority access information (for example the - // Let's Encrypt R3 Intermediate Certificate). - // - // Given these constraints, the best option is to only check revocation information - // at the end-entity depth. We will prefer OCSP (to use stapled information if possible). - // If there is no stapled OCSP response, Android may use the network to attempt to fetch - // one. If OCSP checking fails, it may fall back to fetching CRLs. We allow "soft" - // failures, for example transient network errors. - // - // In the case of a non-public root, such as an internal CA or self-signed certificate, - // we opt to skip revocation checks entirely. The only exception is if the server - // provided stapled OCSP data, which is an explicit signal and won't introduce non-ideal - // platform behavior when attempting validation. - // - // This is because these are cases where a user or administrator has explicitly opted to - // trust a certificate they (at least believe) have control over. These certificates rarely - // contain revocation information as well, so these cases don't lose much. - // See https://github.com/rustls/rustls-platform-verifier/issues/69 as well. - if (ocspResponse == null && !isKnownRoot(validChain.last())) { - // Chain validation must have succeeded by this point. - return VerificationResult(StatusCode.Ok) - } - - val parameters = PKIXBuilderParameters(keystore, null) - - val validator = CertPathValidator.getInstance("PKIX") - val revocationChecker = validator.revocationChecker as PKIXRevocationChecker - - revocationChecker.options = EnumSet.of( - PKIXRevocationChecker.Option.SOFT_FAIL, - PKIXRevocationChecker.Option.ONLY_END_ENTITY - ) - - // Use the OCSP data `rustls` provided, if present. - // Its expected that the server only sends revocation data for its own leaf certificate. - // - // If this field is set, then Android will use it and skip any networking to - // attempt a fetch for that certificate. Otherwise, it will attempt to fetch it from the network. - // Ref: https://cs.android.com/android/platform/superproject/+/master:libcore/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java;l=694 - ocspResponse?.let { providedResponse -> - revocationChecker.ocspResponses = mapOf(endEntity to providedResponse) - } - - // Use the custom revocation definition. - // "Note that when a `PKIXRevocationChecker` is added to `PKIXParameters`, it clones the `PKIXRevocationChecker`; - // thus any subsequent modifications to the `PKIXRevocationChecker` have no effect." - // - https://developer.android.com/reference/java/security/cert/PKIXRevocationChecker - parameters.certPathCheckers = listOf(revocationChecker) - // "When supplying a revocation checker in this manner, it will be used to check revocation - // irrespective of the setting of the `RevocationEnabled` flag." - // - https://developer.android.com/reference/java/security/cert/PKIXRevocationChecker - parameters.isRevocationEnabled = false - - // Validate the revocation status of the end entity certificate. - try { - validator.validate(certFactory.generateCertPath(validChain), parameters) - } catch (e: CertPathValidatorException) { - // LetsEncrypt no longer include OCSP information (as OCSP is being deprecated) which Android is not - // happy with since it *only* tries OCSP by default. We aren't 100% decided on how to fix this yet for real - // (see https://github.com/rustls/rustls-platform-verifier/pull/179) so for now we implement an out for - // tests to allow regular maintenance to proceed. - if (BuildConfig.TEST && e.reason == CertPathValidatorException.BasicReason.UNSPECIFIED) { - return VerificationResult(StatusCode.Ok) - } - - return VerificationResult(StatusCode.Revoked, e.toString()) - } - } else { - // This is allowed to be skipped since revocation checking is best-effort. - Log.w(TAG, "did not attempt to validate OCSP due to Android version") - } + // We removed the cert revocation checks because Android won't do them by default + // and supporting them would be quite difficult given CRLs won't work out of the box. + // + // See https://github.com/rustls/rustls-platform-verifier/issues/221 for more info. + // ================================================================================================= return VerificationResult(StatusCode.Ok) } diff --git a/libraries/slashcommands/impl/build.gradle.kts b/libraries/slashcommands/impl/build.gradle.kts index 34dc2e42b2..8e10b09b71 100644 --- a/libraries/slashcommands/impl/build.gradle.kts +++ b/libraries/slashcommands/impl/build.gradle.kts @@ -18,6 +18,7 @@ android { setupDependencyInjection() dependencies { + implementation(libs.coroutines.core) implementation(projects.libraries.androidutils) implementation(projects.libraries.preferences.api) implementation(projects.libraries.core) diff --git a/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/Command.kt b/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/Command.kt index 0d9e1e8c72..5df871e361 100644 --- a/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/Command.kt +++ b/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/Command.kt @@ -109,7 +109,7 @@ enum class Command( parameters = "", description = R.string.slash_command_description_nick_for_room, isAllowedInThread = false, - isSupported = false, + isSupported = true, ), ROOM_AVATAR( command = "/roomavatar", diff --git a/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutor.kt b/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutor.kt index ad252cb224..01bac5825b 100644 --- a/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutor.kt +++ b/libraries/slashcommands/impl/src/main/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutor.kt @@ -47,7 +47,7 @@ class CommandExecutor( is SlashCommand.ChangeAvatar -> changeAvatar() is SlashCommand.ChangeAvatarForRoom -> changeAvatarForRoom() is SlashCommand.ChangeDisplayName -> changeDisplayName(slashCommand) - is SlashCommand.ChangeDisplayNameForRoom -> changeDisplayNameForRoom() + is SlashCommand.ChangeDisplayNameForRoom -> changeDisplayNameForRoom(slashCommand) is SlashCommand.ChangeRoomAvatar -> changeRoomAvatar() is SlashCommand.ChangeRoomName -> changeRoomName(slashCommand) is SlashCommand.ChangeTopic -> changeTopic(slashCommand) @@ -171,8 +171,8 @@ class CommandExecutor( return Result.failure(Exception("Not yet implemented")) } - private fun changeDisplayNameForRoom(): Result { - return Result.failure(Exception("Not yet implemented")) + private suspend fun changeDisplayNameForRoom(slashCommand: SlashCommand.ChangeDisplayNameForRoom): Result { + return joinedRoom.setOwnMemberDisplayName(slashCommand.displayName) } private suspend fun changeDisplayName(slashCommand: SlashCommand.ChangeDisplayName): Result { diff --git a/libraries/slashcommands/impl/src/test/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutorTest.kt b/libraries/slashcommands/impl/src/test/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutorTest.kt index 497f45c96f..c0f2ce89c2 100644 --- a/libraries/slashcommands/impl/src/test/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutorTest.kt +++ b/libraries/slashcommands/impl/src/test/kotlin/io/element/android/libraries/slashcommands/impl/CommandExecutorTest.kt @@ -14,7 +14,6 @@ import io.element.android.libraries.matrix.api.timeline.MsgType import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom @@ -185,10 +184,18 @@ class CommandExecutorTest { } @Test - fun `change display name for room is not supported`() = runTest { - val sut = createCommandExecutor() - val res = sut.proceedAdmin(SlashCommand.ChangeDisplayNameForRoom(A_USER_NAME)) - assertThat(res.isFailure).isTrue() + fun `change display name for room delegates to joined room`() = runTest { + var capturedDisplayName: String? = null + val joinedRoom = FakeJoinedRoom( + setOwnMemberDisplayNameResult = { displayName -> + capturedDisplayName = displayName + Result.success(Unit) + } + ) + val sut = createCommandExecutor(joinedRoom = joinedRoom) + val res = sut.proceedAdmin(SlashCommand.ChangeDisplayNameForRoom("room nick")) + assertThat(res.isSuccess).isTrue() + assertThat(capturedDisplayName).isEqualTo("room nick") } @Test diff --git a/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt b/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt index 4b3a0d6ffa..7fed08b3e9 100644 --- a/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt +++ b/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt @@ -29,6 +29,8 @@ object TestTags { * Verification screen. */ val recoveryKey = TestTag("verification-recovery_key") + val customRecoveryPassphrase = TestTag("verification-custom_recovery_passphrase") + val customRecoveryPassphraseConfirm = TestTag("verification-custom_recovery_passphrase_confirm") /** * Sign out screen. @@ -98,6 +100,12 @@ object TestTags { */ val floatingActionButton = TestTag("floating-action-button") + /** + * Timeline jump-to-position buttons (long-press exposes "Mark as read"). + */ + val jumpToUnreadButton = TestTag("jump-to-unread-button") + val jumpToBottomButton = TestTag("jump-to-bottom-button") + /** * Timeline. */ diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt index bec837664f..f9348dcdcf 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt @@ -71,7 +71,7 @@ fun CaptionWarningBottomSheet( @PreviewsDayNight @Composable -internal fun CaptionWarningBottomSheetPreview() = ElementPreview { +internal fun CaptionWarningBottomSheetPreview() = ElementPreview(fillMaxSize = true) { CaptionWarningBottomSheet( onDismiss = {}, ) diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt index bd6944d603..064ef03106 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt @@ -93,6 +93,7 @@ fun MarkdownTextInput( setText(text) setHint(placeholder) setHintTextColor(ColorStateList.valueOf(placeholderColor.toArgb())) + contentDescription = placeholder inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or InputType.TYPE_TEXT_FLAG_MULTI_LINE or @@ -129,6 +130,7 @@ fun MarkdownTextInput( } }, update = { editText -> + editText.contentDescription = placeholder editText.applyStyleInCompose(richTextEditorStyle) val text = state.text.value() mentionSpanUpdater.updateMentionSpans(text) diff --git a/libraries/textcomposer/impl/src/main/res/values-be/translations.xml b/libraries/textcomposer/impl/src/main/res/values-be/translations.xml index 7f5693b0a4..dae17ce795 100644 --- a/libraries/textcomposer/impl/src/main/res/values-be/translations.xml +++ b/libraries/textcomposer/impl/src/main/res/values-be/translations.xml @@ -4,7 +4,9 @@ "Пераключыць маркіраваны спіс" "Закрыць параметры фарматавання" "Пераключыць блок кода" + "Зашыфраванае паведамленне…" "Паведамленне…" + "Незашыфраванае паведамленне…" "Стварыць спасылку" "Рэдагаваць спасылку" "Ужыць тоўсты шрыфт" diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/components/markdown/MarkdownTextInputTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/components/markdown/MarkdownTextInputTest.kt index 4840569c0e..ba49428cae 100644 --- a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/components/markdown/MarkdownTextInputTest.kt +++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/components/markdown/MarkdownTextInputTest.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.v2.runAndroidComposeUiTest import androidx.core.text.getSpans -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.matrix.api.permalink.PermalinkData @@ -35,11 +34,10 @@ import io.element.android.libraries.textcomposer.model.SuggestionType import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState import io.element.android.tests.testutils.EnsureCalledOnceWithParam import io.element.android.tests.testutils.EventsRecorder +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class MarkdownTextInputTest { +class MarkdownTextInputTest : RobolectricTest() { @Test fun `when user types onTyping is triggered with value 'true'`() = runAndroidComposeUiTest { val state = aMarkdownTextEditorState(initialFocus = true) diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/IntentionalMentionSpanProviderTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/IntentionalMentionSpanProviderTest.kt index 7bac75cc75..0eec4805a9 100644 --- a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/IntentionalMentionSpanProviderTest.kt +++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/mentions/IntentionalMentionSpanProviderTest.kt @@ -17,13 +17,11 @@ import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.textcomposer.mentions.MentionType import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -@RunWith(RobolectricTestRunner::class) -class IntentionalMentionSpanProviderTest { +class IntentionalMentionSpanProviderTest : RobolectricTest() { @JvmField @Rule val warmUpRule = WarmUpRule() diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt index 6e57ce68cb..247a74a0eb 100644 --- a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt +++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt @@ -11,7 +11,6 @@ package io.element.android.libraries.textcomposer.impl.model import android.net.Uri import androidx.core.text.buildSpannedString import androidx.core.text.inSpans -import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.UserId @@ -31,11 +30,10 @@ import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion import io.element.android.libraries.textcomposer.model.Suggestion import io.element.android.libraries.textcomposer.model.SuggestionType import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class MarkdownTextEditorStateTest { +class MarkdownTextEditorStateTest : RobolectricTest() { @Test fun `insertMention - room alias - getMentions return empty list`() { val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true) diff --git a/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryView.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryView.kt index 9ae748d03a..9105653516 100644 --- a/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryView.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryView.kt @@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -44,6 +43,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.DropdownMenu import io.element.android.libraries.designsystem.theme.components.DropdownMenuItem +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.ListItem diff --git a/libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml index ff9e80f687..876811c861 100644 --- a/libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml +++ b/libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml @@ -7,6 +7,6 @@ "Выполните тесты, чтобы выявить проблемы в конфигурации, из-за которой уведомления могут работать не так, как ожидалось." "Попытаться исправить" "Все тесты прошли успешно." - "Уведомления об устранении неполадок" + "Устранение неполадок с уведомлениями" "Некоторые тесты требуют вашего внимания. Пожалуйста, проверьте подробности." diff --git a/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsViewTest.kt b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsViewTest.kt index 0244673ea5..ea98aeabc6 100644 --- a/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsViewTest.kt +++ b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsViewTest.kt @@ -16,17 +16,15 @@ import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.pressBack +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith import org.robolectric.annotation.Config -@RunWith(AndroidJUnit4::class) -class TroubleshootNotificationsViewTest { +class TroubleshootNotificationsViewTest : RobolectricTest() { @Test fun `press menu back invokes the expected callback`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) diff --git a/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryViewTest.kt b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryViewTest.kt index 94cde37452..b9f615d68e 100644 --- a/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryViewTest.kt +++ b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/history/PushHistoryViewTest.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_FORMATTED_DATE import io.element.android.libraries.matrix.test.A_ROOM_ID @@ -26,11 +25,10 @@ import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class PushHistoryViewTest { +class PushHistoryViewTest : RobolectricTest() { @Test fun `clicking on Reset sends a PushHistoryEvents`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/libraries/ui-strings/src/main/res/values-be/translations.xml b/libraries/ui-strings/src/main/res/values-be/translations.xml index f550ce1075..511581e672 100644 --- a/libraries/ui-strings/src/main/res/values-be/translations.xml +++ b/libraries/ui-strings/src/main/res/values-be/translations.xml @@ -13,6 +13,7 @@ "Поўны адрас будзе %1$s" "Дэталі шыфравання" "Схаваць пароль" + "Інфармацыя" "Далучыцца да выкліку" "Перайсці ўніз" "Толькі згадкі" @@ -72,12 +73,16 @@ "Дэактываваць уліковы запіс" "Адхіліць" "Адхіліць і заблакіраваць" + "Выдаліць" + "Выдаліць уліковы запіс" + "Выдаліць файл" "Выдаліць апытанне" "Зняць выбар з усіх" "Адключыць" "Адмяніць" "Aдхіліць" "Гатова" + "Спампаваць" "Рэдагаваць" "Рэдагаваць подпіс" "Рэдагаваць апытанне" @@ -119,6 +124,7 @@ "Рэакцыя" "Адхіліць" "Выдаліць" + "Выдаліць паведамленне" "Адказаць" "Адказаць у гутаркі" "Паскардзіцца" @@ -133,7 +139,7 @@ "Выбраць усё" "Адправіць" "Адправіць паведамленне" - "Падзяліцца" + "Абагуліць" "Абагуліць спасылку" "Паказаць" "Увайдзіце яшчэ раз" @@ -214,8 +220,10 @@ "Паведамленне выдалена" "Сучасны" "Адкл. гук" + "Імя" "Вынікаў няма" "Няма назвы пакоя" + "Не зашыфравана" "Па-за сеткай" "Ліцэнзіі з адкрытым зыходным кодам" "або" @@ -227,6 +235,7 @@ "Калі ласка, пачакайце…" "Вы ўпэўнены, што хочаце скончыць гэтае апытанне?" "Апытанне: %1$s" + "Апытанне" "Усяго галасоў: %1$s" "Вынікі будуць паказаны пасля завяршэння апытання" @@ -241,6 +250,7 @@ "Рэакцыі" "Ключ аднаўлення" "Абнаўленне…" + "Выдаленне…" "Адказвае на %1$s" "Паведаміць аб праблеме" "Скарга прынята" @@ -262,6 +272,7 @@ "Сервер не падтрымліваецца" "URL-адрас сервера" "Налады" + "Абагуліць прастору" "Абагулена месцазнаходжанне" "Выхад" "Нешта пайшло не так" @@ -315,6 +326,11 @@ "Гэй, пагавары са мной у %1$s: %2$s" "%1$s Android" "Паведаміць аб памылцы з дапамогай Rageshake" + "Здымак экрана" + "%1$s: %2$s" + "Параметры" + "Выдаліць %1$s" + "Налады" "Не ўдалося выбраць носьбіт, паўтарыце спробу." "Націсніце на паведамленне і абярыце «%1$s », каб уключыць сюды." "Замацуеце важныя паведамленні, каб іх можна было лёгка знайсці" @@ -335,8 +351,8 @@ "Загрузка паведамлення…" "Паглядзець усе" "Чат" - "Падзяліцца месцазнаходжаннем" - "Падзяліцца маім месцазнаходжаннем" + "Абагуліць месцазнаходжанне" + "Абагуліць мае месцазнаходжанне" "Адкрыць у Apple Maps" "Адкрыць у Google Maps" "Адкрыць у OpenStreetMap" diff --git a/libraries/ui-strings/src/main/res/values-cs/translations.xml b/libraries/ui-strings/src/main/res/values-cs/translations.xml index 1bf3802b12..5f45bea93b 100644 --- a/libraries/ui-strings/src/main/res/values-cs/translations.xml +++ b/libraries/ui-strings/src/main/res/values-cs/translations.xml @@ -50,12 +50,15 @@ "Avatar místnosti" "Odeslat soubory" "Poloha odesílatele" + "Odesláno %1$s v %2$s" "Vyžaduje se časově omezená akce, na ověření máte jednu minutu" "Nastavení, vyžaduje akci" "Zobrazit heslo" "Zahájit hovor" "Zahájit videohovor" "Zahájit hlasový hovor" + "Vlákno v %1$s" + "Vlákna v %1$s" "Místnost s náhrobkem" "Avatar uživatele" "Uživatelské menu" diff --git a/libraries/ui-strings/src/main/res/values-el/translations.xml b/libraries/ui-strings/src/main/res/values-el/translations.xml index ec14b73e04..927ab23afa 100644 --- a/libraries/ui-strings/src/main/res/values-el/translations.xml +++ b/libraries/ui-strings/src/main/res/values-el/translations.xml @@ -50,6 +50,7 @@ "Απαιτείται ενέργεια περιορισμένης χρονικής διάρκειας, έχετε ένα λεπτό για επαλήθευση." "Εμφάνιση κωδικού πρόσβασης" "Ξεκίνησε μια κλήση" + "Ξεκινήστε μια βιντεοκλήση" "Έναρξη φωνητικής κλήσης" "Θαμένη αίθουσα" "Άβαταρ χρήστη" @@ -462,6 +463,13 @@ "Επιλογές" "Αφαίρεση %1$s" "Ρυθμίσεις" + "Κανείς δεν μοιράζεται την τοποθεσία του" + "Κοινοποιείς την τοποθεσία σε πραγματικό χρόνο" + + "%1$d άτομο" + "%1$d άτομα" + + "Στον χάρτη" "Αποτυχία επιλογής πολυμέσου, δοκίμασε ξανά." "Πάτα σε ένα μήνυμα και επέλεξε «%1$s» για να συμπεριληφθεί εδώ." "Καρφίτσωσε σημαντικά μηνύματα, ώστε να μπορούν να εντοπιστούν εύκολα" @@ -486,6 +494,7 @@ "Μήνυμα στο %1$s" "Επέκταση" "Μείωση" + "Κοινοποιείς την τοποθεσία σε πραγματικό χρόνο" "Βλέπετε ήδη αυτήν την αίθουσα!" "%1$s από %2$s" "%1$s Καρφιτσωμένα μηνύματα" diff --git a/libraries/ui-strings/src/main/res/values-et/translations.xml b/libraries/ui-strings/src/main/res/values-et/translations.xml index f1c7d8d225..2a1d2504ff 100644 --- a/libraries/ui-strings/src/main/res/values-et/translations.xml +++ b/libraries/ui-strings/src/main/res/values-et/translations.xml @@ -1,9 +1,12 @@ + "Lisa tunnuspilt" "Reageeri: %1$s" "Aadress" "Tunnuspilt" "Vähenda tekstivälja" + "Vähenda kasutaja kohta lubatud hääletuskordi" + "Suurenda kasutaja kohta lubatud hääletuskordi" "Kustuta" "%1$d number sisestatud" @@ -18,6 +21,7 @@ "Teave" "Liitu kõnega" "Mine lõppu" + "Mine lugemata sõnumite juurde" "Nihuta kaart minu asukohta" "Ainult mainimised" "Summutatud" @@ -28,6 +32,7 @@ "%1$d. lehekülg" "Peata" "Häälsõnum, kestus:%1$s, praegune asukoht: %2$s" + "Foto eelvaade" "PIN-koodi väli" "Esiletõstetud asukoht" "Esita" @@ -62,6 +67,7 @@ "Lõpetatuks märgitud jututuba" "Kasutaja tunnuspilt" "Kasutajamenüü" + "Video eelvaade" "Vaata tunnuspilti" "Vaata üksikasju" "Häälsõnum, kestus:%1$s" @@ -98,6 +104,7 @@ "Keeldu ja blokeeri" "Kustuta" "Kustuta kasutajakonto" + "Kustuta fail" "Kustuta küsitlus" "Eemalda kõik valikud" "Lülita välja" @@ -189,9 +196,11 @@ "Tõlgi" "Proovi uuesti" "Eemalda esiletõstmine" + "Videokõne" "Vaata" "Vaata ajajoonel" "Vaata lähtekoodi" + "Häälkõne" "Jah" "Jah, proovi uuesti" "Sinu koduserver toetab uut ja kiiremat protokolli. Uuendamiseks logi korraks rakendusest välja ja siis tagasi. Mingil hetkel tulevikus vana protokoll eemaldatakse kasutusest ja tehes uuenduse nüüd, väldid hilisemat sundkorras uuendust." @@ -212,6 +221,7 @@ "Blokeeritud kasutajad" "Mullid" "Osapool keeldus kõnest" + "Kõne on pooleli" "Kõne algas" "Sa keeldusid kõnest" "Vestluse varukoopia" @@ -255,7 +265,9 @@ Põhjus: %1$s." "Fail on salvestatud kausta Allalaadimised" "Edasta sõnum" "Sagedasti kasutatud" + "Galerii" "GIF" + "Rühmakõne on pooleli" "Pilt" "Vastuseks kasutajale %1$s" "Paigalda APK-failist" @@ -303,6 +315,7 @@ Põhjus: %1$s." "Palun oota…" "Kas oled kindel, et soovid selle küsitluse lõpetada?" "Küsitlus: %1$s" + "Küsitlus" "Hääli kokku: %1$s" "Tulemused on näha peale küsitluse lõppemist" @@ -397,6 +410,7 @@ Põhjus: %1$s." "Lõpeta summutamine" "See kõne pole toetatud" "Toetamata sündmus" + "%1$s helistas" "Kasutajanimi" "Verifitseerimine on katkestatud" "Verifitseerimine on tehtud" @@ -479,6 +493,7 @@ Kas sa oled kindel, et soovid jätkata?" "Valikud" "Kustuta: %1$s" "Seadistused" + "Hääletuskordi kasutaja kohta" "Mitte keegi ei jaga oma asukohta" "Asukoht on jagamisel reaalajas" @@ -531,6 +546,10 @@ Kas sa oled kindel, et soovid jätkata?" "Kogukonnad" "Jagatud %1$s" "Kaardil" + + "%1$d liitus" + "%1$d liitusid" + "Sõnum on saatmata, kuna kasutaja %1$s digitaalse identiteet on lähtestatud." "Sõnum on saatmata, kuna %1$s pole verifitseerinud kõiki oma seadmeid." "Kuna sa pole üks või enamgi oma seadet verifitseerinud, siis sinu sõnum on saatmata." @@ -542,4 +561,6 @@ Kas sa oled kindel, et soovid jätkata?" "Sul pole ligipääsu antud sõnumile" "Sõnumi dekrüptimine ei õnnestu" "Kuna seade on verifitseerimata või saatja pole sinu digitaalset identiteeti verifitseerinud, siis sõnumi näitamine on blokeeritud." + "Sinu nutiseadme tarkvara on liiga vana, vajalik on Android 8 või uuem." + "Kaartide joonistamine pole toetatud" diff --git a/libraries/ui-strings/src/main/res/values-fi/translations.xml b/libraries/ui-strings/src/main/res/values-fi/translations.xml index 88d8d712b0..096652fbd4 100644 --- a/libraries/ui-strings/src/main/res/values-fi/translations.xml +++ b/libraries/ui-strings/src/main/res/values-fi/translations.xml @@ -99,6 +99,7 @@ "Hylkää ja estä" "Poista" "Poista tili" + "Poista tiedosto" "Poista kysely" "Poista kaikki valinnat" "Poista käytöstä" @@ -304,6 +305,7 @@ Syy: %1$s." "Odota hetki…" "Haluatko varmasti lopettaa tämän kyselyn?" "Kysely: %1$s" + "Kysely" "Ääniä yhteensä: %1$s" "Tulokset näkyvät kyselyn päätyttyä" @@ -543,4 +545,6 @@ Haluatko varmasti jatkaa?" "Sinulla ei ole oikeutta lukea tätä viestiä" "Viestin salauksen purkaminen ei onnistu" "Tämä viesti estettiin, koska et ole vahvistanut laitettasi tai koska lähettäjän on vahvistettava diigitaalinen identiteettisi." + "Laitteesi on liian vanha, tarvitset laitteen, jossa on Android 8 tai uudempi." + "Karttojen renderöintiä ei tueta" diff --git a/libraries/ui-strings/src/main/res/values-fr/translations.xml b/libraries/ui-strings/src/main/res/values-fr/translations.xml index 7d178cc105..cbddbf5f08 100644 --- a/libraries/ui-strings/src/main/res/values-fr/translations.xml +++ b/libraries/ui-strings/src/main/res/values-fr/translations.xml @@ -1,5 +1,6 @@ + "Ajouter un avatar" "Ajouter une réaction: %1$s" "Adresse" "Avatar" @@ -99,6 +100,7 @@ "Refuser et bloquer" "Supprimer" "Supprimer le compte" + "Supprimer le fichier" "Supprimer le sondage" "Tout désélectionner" "Désactiver" @@ -304,6 +306,7 @@ Raison : %1$s." "Veuillez patienter…" "Êtes-vous sûr de vouloir mettre fin à ce sondage ?" "Sondage : %1$s" + "Sondage" "Nombre total de votes : %1$s" "Les résultats s’afficheront une fois le sondage terminé" @@ -543,4 +546,6 @@ Raison : %1$s." "Vous ne pouvez pas voir ce message" "Impossible de déchiffrer le message" "Ce message a été bloqué soit parce que vous n’avez pas vérifié votre session, soit parce que l’expéditeur doit vérifier votre identité numérique." + "Votre appareil est trop ancien, un appareil fonctionnant sous Android 8 ou une version plus récente est requis." + "Affichage des cartes non supporté" diff --git a/libraries/ui-strings/src/main/res/values-hu/translations.xml b/libraries/ui-strings/src/main/res/values-hu/translations.xml index caca4b5014..131f6d5957 100644 --- a/libraries/ui-strings/src/main/res/values-hu/translations.xml +++ b/libraries/ui-strings/src/main/res/values-hu/translations.xml @@ -1,5 +1,6 @@ + "Profilkép hozzáadása" "Reakció hozzáadása: %1$s" "Cím" "Profilkép" @@ -18,6 +19,7 @@ "Információ" "Csatlakozás a híváshoz" "Ugrás az aljára" + "Ugrás az olvasatlanhoz" "Térkép áthelyezése a jelenlegi helyre" "Csak megemlítések" "Némítva" @@ -98,6 +100,7 @@ "Elutasítás és letiltás" "Törlés" "Fiók törlése" + "Fájl törlése" "Szavazás törlése" "Kijelölés megszüntetése" "Letiltás" @@ -303,6 +306,7 @@ Ok: %1$s." "Kis türelmet…" "Biztos, hogy befejezi ezt a szavazást?" "Szavazás: %1$s" + "Szavazás" "Összes szavazat: %1$s" "Az eredmények a szavazás befejezése után jelennek meg" @@ -541,4 +545,6 @@ Biztos, hogy folytatja?" "Nincs hozzáférése ehhez az üzenethez" "Nem sikerült visszafejteni az üzenetet" "Ez az üzenet azért lett blokkolva, mert vagy nem ellenőrizte az eszközt, vagy a feladónak ellenőriznie kell az Ön digitális személyazonosságát." + "Az Ön eszköze túl régi, Android 8 vagy újabb verziójú eszközre van szükség." + "A térképek megjelenítése nem támogatott" diff --git a/libraries/ui-strings/src/main/res/values-in/translations.xml b/libraries/ui-strings/src/main/res/values-in/translations.xml index 51d78530a8..95b5aa4112 100644 --- a/libraries/ui-strings/src/main/res/values-in/translations.xml +++ b/libraries/ui-strings/src/main/res/values-in/translations.xml @@ -145,7 +145,7 @@ "Tampilkan" "Masuk lagi" "Hapus device dari akun" - "Keluar saja" + "Hapus Perangkat ini" "Lewati" "Mulai" "Mulai obrolan" @@ -184,6 +184,7 @@ "Membuat ruangan…" "Permintaan dibatalkan" "Keluar dari ruangan" + "Ruang tersisa" "Undangan ditolak" "Kesalahan dekripsi" "Deskripsi" @@ -296,8 +297,9 @@ Alasan: %1$s." "Server tidak dapat dijangkau" "URL Server" "Pengaturan" + "Berbagi ruang" "Lokasi terbagi" - "Mengeluarkan dari akun" + "Melepaskan perangkat" "Ada yang salah" "Kami mengalami masalah. Silakan coba lagi." "Space" diff --git a/libraries/ui-strings/src/main/res/values-ja/translations.xml b/libraries/ui-strings/src/main/res/values-ja/translations.xml index ab5f64fc9e..a9bdedc1c1 100644 --- a/libraries/ui-strings/src/main/res/values-ja/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ja/translations.xml @@ -97,6 +97,7 @@ "拒否してブロック" "削除" "アカウントを削除" + "ファイルを削除" "投票を削除" "全ての選択を解除" "無効化" @@ -292,7 +293,7 @@ "または" "他のオプション" "パスワード" - "人々" + "ユーザー" "固定リンク" "権限" "ピン留め" @@ -300,6 +301,7 @@ "お待ちください…" "本当に投票を終了しますか?" "投票: %1$s" + "投票" "総投票数:%1$s" "結果は投票終了後に表示されます" diff --git a/libraries/ui-strings/src/main/res/values-ko/translations.xml b/libraries/ui-strings/src/main/res/values-ko/translations.xml index 303e8ba929..6336a8de92 100644 --- a/libraries/ui-strings/src/main/res/values-ko/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ko/translations.xml @@ -8,13 +8,16 @@ "%1$d자리 입력됨" + "소요 시간: %1$s" "아바타 편집" "전체 주소는 다음과 같습니다 %1$s" "암호화 세부 정보" "메시지 텍스트 필드 확장" "비밀번호 숨기기" + "정보" "통화 참가" "맨 아래로 이동" + "읽지 않은 항목으로 이동" "지도를 내 위치로 이동" "멘션만" "음소거함" @@ -31,6 +34,7 @@ "재생 속도" "투표" "종료된 투표" + "위치: %1$s" "QR 코드" "%1$s에 반응하세요" "다른 이모지로 반응하세요" @@ -45,10 +49,15 @@ "방 아바타" "파일 보내기" "발신자 위치" + "%1$s님이 %2$s에 보냈습니다." "제한 시간 내 인증이 필요합니다.1분 안에 확인해 주세요." + "설정,조치 필요" "비밀번호 표시" "통화 시작" + "영상 통화 시작" "음성 통화 시작" + "%1$s 내 스레드" + "%1$s 내 스레드 목록" "묘비 방" "사용자 아바타" "사용자 메뉴" @@ -66,6 +75,7 @@ "통화" "취소" "현재 취소" + "파일 선택" "사진 선택" "지우기" "닫기" @@ -85,12 +95,16 @@ "계정 비활성화" "거절" "거부 및 차단" + "삭제" + "계정 삭제" + "파일 삭제" "투표 삭제" "전체 선택 해제" "비활성화" "취소" "닫기" "완료" + "다운로드" "편집" "캡션 편집" "투표 수정" @@ -197,7 +211,9 @@ "베타" "차단한 사용자" "버블" + "통화 거절" "통화 시작" + "통화를 거절하셨습니다" "채팅 백업" "클립보드에 복사됨" "저작권" @@ -285,6 +301,7 @@ "기다려 주세요…" "정말로 이 투표를 종료하시겠어요?" "투표: %1$s" + "투표" "총 투표수: %1$s" "결과는 투표가 끝난 이후에 공개됨" @@ -448,6 +465,9 @@ "이런, 오류가 발생했어요" "🔐️ %1$s에 참여하기" "%1$s에서 대화해요: %2$s" + "실시간 위치 공유" + "위치 공유 중" + "%1$s님의 실시간 위치" "%1$s Android" "강하게 흔들어서 오류 보고하기" "스크린샷" @@ -455,6 +475,12 @@ "옵션" "%1$s 제거" "설정" + "위치를 공유 중인 사용자가 없습니다." + "실시간 위치 공유 중" + + "%1$d명" + + "지도 보기" "미디어 선택에 실패했습니다. 다시 시도해 주세요." "메시지를 누르고 \"%1$s\" 를 선택하여 여기에 포함합니다." "중요한 메시지를 고정하여 쉽게 찾을 수 있도록 합니다" @@ -478,6 +504,7 @@ "메시지 %1$s" "펼치기" "줄이다" + "실시간 위치 공유 중" "이 방을 이미 보고 있습니다!" "%2$s 의 %1$s" "%1$s 고정된 메시지" diff --git a/libraries/ui-strings/src/main/res/values-pl/translations.xml b/libraries/ui-strings/src/main/res/values-pl/translations.xml index 7e0b78641e..e07f564f3b 100644 --- a/libraries/ui-strings/src/main/res/values-pl/translations.xml +++ b/libraries/ui-strings/src/main/res/values-pl/translations.xml @@ -1,9 +1,12 @@ + "Dodaj awatar" "Dodaj reakcję: %1$s" "Adres" "Awatar" "Zmniejsz pole tekstowe wiadomości" + "Zmniejsz liczbę głosów dozwolonych na osobę" + "Zwiększ liczbę głosów dozwolonych na osobę" "Usuń" "Wprowadzono %1$d cyfrę" @@ -30,6 +33,7 @@ "Strona %1$d" "Wstrzymaj" "Wiadomość głosowa, czas trwania: %1$s, aktualna pozycja: %2$s" + "Podgląd zdjęcia" "Pole PIN" "Przypięta lokalizacja" "Odtwórz" @@ -65,6 +69,7 @@ "Pokój nagrobkowy" "Awatar użytkownika" "Menu użytkownika" + "Podgląd wideo" "Wyświetl awatar" "Wyświetl szczegóły" "Wiadomość głosowa, czas trwania: %1$s" @@ -101,6 +106,7 @@ "Odrzuć i zablokuj" "Usuń" "Usuń konto" + "Usuń plik" "Usuń ankietę" "Odznacz wszystko" "Wyłącz" @@ -192,9 +198,11 @@ "Przetłumacz" "Spróbuj ponownie" "Odepnij" + "Rozmowa wideo" "Wyświetl" "Wyświetl na osi czasu" "Wyświetl źródło" + "Rozmowa głosowa" "Tak" "Tak, spróbuj ponownie" "Twój serwer wspiera teraz nowy, szybszy protokół. Zaloguj się ponownie, aby zaktualizować. Dzięki temu unikniesz wymuszonego wylogowania, gdy stary protokół zostanie usunięty." @@ -215,6 +223,7 @@ "Zablokowani użytkownicy" "Bąbelki" "Połączenie odrzucone" + "Trwa połączenie" "Rozpoczęto rozmowę" "Odrzuciłeś połączenie" "Backup czatu" @@ -258,7 +267,9 @@ Powód: %1$s." "Plik zapisany do folderu Pobrane" "Przekaż wiadomość" "Często używane" + "Galeria" "GIF" + "Trwa połączenie grupowe" "Zdjęcie" "W odpowiedzi do %1$s" "Zainstaluj APK" @@ -306,8 +317,9 @@ Powód: %1$s." "Przypięte" "Sprawdź swoje połączenie internetowe" "Proszę czekać…" - "Jesteś pewien, że chcesz zakończyć tę ankietę?" + "Czy na pewno chcesz zakończyć tę ankietę?" "Ankieta: %1$s" + "Ankieta" "Łączna liczba głosów: %1$s" "Wyniki zostaną wyświetlone po zakończeniu ankiety" @@ -407,6 +419,7 @@ Powód: %1$s." "Wyłącz wyciszenie" "Nieobsługiwane połączenie" "Nieobsługiwane zdarzenie" + "%1$s rozpoczął połączenie" "Nazwa użytkownika" "Weryfikacja anulowana" "Weryfikacja zakończona" @@ -424,7 +437,7 @@ Powód: %1$s." "Balans między jakością a szybkością przesyłania" "Wiadomość głosowa" "Oczekiwanie…" - "Oczekiwanie na tę wiadomość" + "Oczekiwanie wiadomości" "Czekam na lokalizację na żywo…" "Każdy może zobaczyć historię" "Ty" @@ -489,6 +502,7 @@ Czy na pewno chcesz kontynuować?" "Opcje" "Usuń %1$s" "Ustawienia" + "Liczba głosów na osobę" "Nikt nie udostępnia swojej lokalizacji" "Udostępnianie lokalizacji na żywo" @@ -498,8 +512,8 @@ Czy na pewno chcesz kontynuować?" "Na mapie" "Nie udało się wybrać multimediów. Spróbuj ponownie." - "Naciśnij wiadomość i wybierz “%1$s”, aby dołączyć tutaj." - "Przypinaj ważne wiadomości, aby można było je łatwo znaleźć" + "Przytrzymaj wiadomość i wybierz “%1$s”, aby umieścić ją tutaj." + "Przypinaj ważne wiadomości, by łatwo je później odnaleźć" "%1$d przypięta wiadomość" "%1$d przypięte wiadomości" @@ -543,6 +557,11 @@ Czy na pewno chcesz kontynuować?" "Przestrzenie" "Udostępnianie %1$s" "Na mapie" + + "+ %1$d dołączył" + "+ %1$d dołączyło" + "+ %1$d dołączyło" + "Wiadomość nie została wysłana, ponieważ tożsamość %1$s została zresetowana." "Wiadomość nie została wysłana, ponieważ %1$s nie zweryfikował wszystkich urządzeń." "Wiadomość nie została wysłana, ponieważ nie zweryfikowałeś jednego lub więcej swoich urządzeń." @@ -554,4 +573,6 @@ Czy na pewno chcesz kontynuować?" "Nie masz uprawnień do tej wiadomości" "Nie można odszyfrować wiadomości" "Ta wiadomość została zablokowana, ponieważ urządzenie nie zostało zweryfikowane lub nadawca musi zweryfikować Twoją tożsamość." + "Twoje urządzenie jest przestarzałe, wymagany system Android 8 lub nowszy." + "Renderowanie map nie jest obsługiwane" diff --git a/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml b/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml index f35aca5a58..8ba2d1f107 100644 --- a/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml +++ b/libraries/ui-strings/src/main/res/values-pt-rBR/translations.xml @@ -155,8 +155,8 @@ "Compartilhar link" "Mostrar" "Entrar novamente" - "Sair" - "Sair mesmo assim" + "Remover este dispositivo" + "Remover este dispositivo mesmo assim" "Pular" "Iniciar" "Iniciar conversa" @@ -473,7 +473,7 @@ Você tem certeza de que deseja continuar?" "Abrir no Apple Maps" "Abrir no Google Maps" "Abrir no OpenStreetMap" - "Compartilhar esta localização" + "Compartilhar localização selecionada" "Os espaços que você criou ou entrou." "%1$s • %2$s" "Crie espaços para organizar salas" diff --git a/libraries/ui-strings/src/main/res/values-ru/translations.xml b/libraries/ui-strings/src/main/res/values-ru/translations.xml index 3596bc04fe..5c53c600d5 100644 --- a/libraries/ui-strings/src/main/res/values-ru/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml @@ -10,6 +10,7 @@ "Введено %1$d цифры" "Введено %1$d цифр" + "Продолжительность: %1$s" "Изменить аватар" "Полный адрес %1$s" "Сведения о шифровании" @@ -18,6 +19,7 @@ "Информация" "Присоединиться к звонку" "Перейти вниз" + "Перейти к непрочитанным" "Переместить карту к моему местоположению" "Только упоминания" "Без звука" @@ -34,6 +36,7 @@ "Скорость воспроизведения" "Опрос" "Завершённый опрос" + "Позиция: %1$s" "QR-код" "Реагировать вместе с %1$s" "Реакция с помощью эмодзи" @@ -50,12 +53,15 @@ "Аватар комнаты" "Отправить файлы" "Местоположение отправителя" - "Требуется действие, на которое есть ограничение по времени, у вас есть одна минута для проверки" + "Отправлено пользователем %1$s в %2$s" + "Требуется действие, на которое есть ограничение по времени, у Вас есть одна минута для проверки" "Настройки, требуется действие" "Показать пароль" "Начать звонок" "Начать видеозвонок" "Начать голосовой вызов" + "Обсуждение в %1$s" + "Обсуждения в %1$s" "Брошенная комната" "Аватар пользователя" "Меню пользователя" @@ -95,6 +101,7 @@ "Отклонить и заблокировать" "Удалить" "Удалить аккаунт" + "Удалить файл" "Удалить опрос" "Отменить выбор" "Отключить" @@ -127,7 +134,7 @@ "Покинуть беседу" "Покинуть комнату" "Покинуть пространство" - "Загрузить еще" + "Загрузить ещё" "Настройки аккаунта" "Управление учетной записью и устройствами" "Управление устройствами" @@ -173,7 +180,7 @@ "Показать" "Повторить вход" "Удалить это устройство" - "Все равно удалить это устройство" + "Всё равно удалить это устройство" "Пропустить" "Начать" "Начать чат" @@ -190,8 +197,8 @@ "Просмотреть в хронологии" "Показать источник" "Да" - "Да, попробовать еще раз" - "Теперь ваш сервер поддерживает новый, более быстрый протокол. Чтобы обновить его прямо сейчас, выйдите и войдите в свою учётную запись снова. Сделав это сейчас, вы сможете избежать принудительного выхода из системы при последующем удалении старого протокола." + "Да, попробовать ещё раз" + "Теперь Ваш сервер поддерживает новый, более быстрый протокол. Чтобы обновить его прямо сейчас, выйдите и войдите в свою учётную запись снова. Сделав это сейчас, Вы сможете избежать принудительного выхода из системы при последующем удалении старого протокола." "Доступно обновление" "О приложении" "Политика допустимого использования" @@ -302,6 +309,7 @@ "Подождите…" "Вы действительно хотите завершить данный опрос?" "Опрос: %1$s" + "Опрос" "Всего голосов: %1$s" "Результаты будут показаны после завершения опроса" @@ -370,7 +378,7 @@ "Общее пространство" "Удаление устройства" "Что-то пошло не так" - "Мы столкнулись с проблемой. Пожалуйста, попробуйте еще раз." + "Мы столкнулись с проблемой. Пожалуйста, попробуйте ещё раз." "Пространство" "Участники пространства" "О чём это пространство?" @@ -422,8 +430,8 @@ "Ожидание трансляции местоположения…" "Любой может видеть историю" "Вы" - "%1$s (%2$s) поделился этим сообщением, поскольку вас не было в комнате, когда оно было отправлено." - "%1$s поделился этим сообщением, поскольку вас не было в комнате, когда оно было отправлено." + "%1$s (%2$s) поделился(ась) этим сообщением, поскольку Вас не было в комнате, когда оно было отправлено." + "%1$s поделился(ась) этим сообщением, поскольку Вас не было в комнате, когда оно было отправлено." "Эта комната настроена так, что новые участники могут видеть историю. %1$s" "Личность %1$s была сброшена. %2$s" "Личность %1$s %2$s была сброшена. %3$s" @@ -446,11 +454,11 @@ "Ошибка" "Успешно" "Предупреждение" - "У вас есть несохраненные изменения." + "У Вас есть несохраненные изменения." "Изменения не сохранены. Вы действительно хотите вернуться?" "Сохранить изменения?" "Максимально допустимый размер файла: %1$s" - "Выберите качество для видео, которое вы хотите загрузить." + "Выберите качество видео, которое Вы хотите загрузить." "Выберите качество загружаемого видео" "Поиск эмодзи" "Вы уже вошли на данном устройстве как %1$s." @@ -491,7 +499,7 @@ "%1$d людей" "На карте" - "Не удалось выбрать медиа, попробуйте еще раз." + "Не удалось выбрать медиа, попробуйте ещё раз." "Нажмите на сообщение и выберите «%1$s», чтобы добавить его сюда." "Закрепите важные сообщения, чтобы их можно было легко найти" @@ -499,19 +507,19 @@ "%1$d закреплённых сообщения" "%1$d закреплённых сообщений" - "Закрепленные сообщения" + "Закреплённые сообщения" "Вы собираетесь перейти в свой аккаунт %1$s, чтобы сбросить личность. После этого Вы вернётесь в приложение." "Не можете подтвердить? Перейдите в свой аккаунт, чтобы сбросить свою личность." "Сбросить верификацию и отправить" "Вы можете либо сбросить подтверждение и всё равно отправить это сообщение, либо отменить его сейчас и повторить попытку после повторного подтверждения %1$s." "Ваше сообщение не было отправлено, потому что подтвержденная идентификации %1$s была сброшена" - "Все равно отправить сообщение" - "У %1$s есть одно или несколько неподтвержденных устройств. Вы все равно можете отправить сообщение или отменить его пока и повторить попытку позже, когда %2$s подтвердить все свои устройства." + "Всё равно отправить сообщение" + "У %1$s есть одно или несколько неподтвержденных устройств. Вы всё равно можете отправить сообщение или отменить его и повторить попытку позже, когда %2$s подтвердит все свои устройства." "Ваше сообщение не было отправлено, потому что %1$s имеет неподтвержденные устройства" "Одно или несколько ваших устройств не подтверждены. Вы можете отправить сообщение в любом случае или отменить его пока и повторить попытку позже, подтвердив все свои устройства." "Ваше сообщение не было отправлено, поскольку вы не подтвердили одно или несколько своих устройств." "Редактировать владельцев и администраторов" - "Не удалось обработать медиафайл для загрузки, попробуйте еще раз." + "Не удалось обработать медиафайл для загрузки, попробуйте ещё раз." "Не удалось получить данные о пользователе" "Сообщение в %1$s" "Развернуть" @@ -519,9 +527,9 @@ "Поделиться текущим местоположением…" "Эта комната уже просматривается!" "%1$s из %2$s" - "%1$s закрепленные сообщения" + "%1$s Закреплённые сообщения" "Загрузка сообщения…" - "Посмотреть все" + "Посмотреть Все" "Чат" "Поделиться местоположением" "Поделиться моим местоположением" @@ -548,4 +556,6 @@ "Вы не имеете доступа к этому сообщению" "Не удалось расшифровать сообщение" "Это сообщение было заблокировано либо потому, что вы не подтвердили свое устройство, либо потому, что отправителю необходимо подтвердить вашу цифровую личность." + "Ваше устройство слишком старое, требуется устройство с Android 8 или более новой версией." + "Отображение карт не поддерживается" diff --git a/libraries/ui-strings/src/main/res/values-uk/translations.xml b/libraries/ui-strings/src/main/res/values-uk/translations.xml index d7b18bf1ae..b84b3b92cd 100644 --- a/libraries/ui-strings/src/main/res/values-uk/translations.xml +++ b/libraries/ui-strings/src/main/res/values-uk/translations.xml @@ -1,15 +1,19 @@ + "Додати аватар" "Додати реакцію: %1$s" "Адреса" "Аватар" "Згорнути поле тексту повідомлення" + "Зменшити кількість голосів, дозволених на одну особу" + "Збільшити кількість голосів, дозволених на одну особу" "Видалити" "Введена %1$d цифра" "Введено %1$d цифри" "Введено %1$d цифр" + "Тривалість: %1$s" "Редагувати аватар" "Повна адреса буде %1$s" "Подробиці шифрування" @@ -18,6 +22,7 @@ "Інформація" "Приєднатися до виклику" "Перейти вниз" + "Перейти до непрочитаних" "Перемістити карту до мого місця перебування" "Тільки згадки" "Звук вимкнено" @@ -28,12 +33,14 @@ "Сторінка %1$d" "Пауза" "Голосове повідомлення, тривалість: %1$s, поточна позиція: %2$s" + "Попередній перегляд світлин" "Поле PIN-коду" "Закріплена локація" "Відтворити" "Швидкість програвання" "Опитування" "Опитування завершено" + "Позиція: %1$s" "QR-код" "Реагувати з%1$s" "Відреагувати іншими смайликами" @@ -50,15 +57,19 @@ "Аватар кімнати" "Надіслати файли" "Локація відправника" - "Необхідно виконати дію, обмежену в часі, у вас є одна хвилина для верифікації" + "Надіслано %1$s о %2$s" + "Необхідно виконати дію, обмежену в часі, ви маєте одну хвилину, щоб звіритись" "Налаштування, потрібні дії" "Показати пароль" "Розпочати виклик" - "Розпочати відеодзвінок" - "Розпочати голосовий дзвінок" + "Розпочати відеовиклик" + "Розпочати голосовий виклик" + "Гілка в %1$s" + "Гілки в %1$s" "Кімната більше не використовується" "Аватар користувача" "Меню користувача" + "Попередній перегляд відео" "Переглянути аватар" "Переглянути подробиці" "Голосове повідомлення, тривалість: %1$s" @@ -77,7 +88,7 @@ "Вибрати фото" "Очистити" "Закрити" - "Верифікація завершена" + "Завершити звіряння" "Підтвердити" "Підтвердіть пароль" "Продовжити" @@ -95,6 +106,7 @@ "Відхилити та заблокувати" "Видалити" "Видалити обліковий запис" + "Видалити файл" "Видалити опитування" "Скасувати вибір усіх" "Вимкнути" @@ -172,13 +184,13 @@ "Ділитися місцезнаходженням у реальному часі" "Показати" "Увійдіть знову" - "Вийти" - "Все одно вийти" + "Вилучити цей пристрій" + "Усе одно вилучити цей пристрій" "Пропустити" "Розпочати" "Розпочати бесіду" "Почати спочатку" - "Почати верифікацію" + "Розпочати звіряння" "Натисніть, щоб завантажити мапу" "Зупинити" "Зробити фото" @@ -186,9 +198,11 @@ "Перекласти" "Спробуйте ще раз" "Відкріпити" + "Відеовиклик" "Переглянути" "Переглянути на шкалі часу" "Переглянути джерело" + "Голосовий виклик" "Так" "Так, повторити спробу" "Ваш сервер тепер підтримує новий, швидший протокол. Вийдіть із системи та увійдіть знову, щоб оновити систему зараз. Якщо ви зробите це зараз, це допоможе вам уникнути примусового виходу з системи, коли старий протокол буде видалено пізніше." @@ -203,14 +217,15 @@ "Аналітика" "Ви вийшли з кімнати" "Ви вийшли з сеансу" - "Тема" + "Вигляд" "Аудіо" "Бета-версія" "Заблоковані користувачі" "Бульбашки" - "Дзвінок відхилено" + "Виклик відхилено" + "Виклик триває" "Виклик розпочато" - "Ви відхилили дзвінок" + "Ви відхилили виклик" "Резервне копіювання бесіди" "Скопійовано до буферу обміну" "Авторське право" @@ -252,7 +267,9 @@ "Файл збережений у Завантаження" "Переслати повідомлення" "Частовживані" + "Галерея" "GIF" + "Триває груповий виклик" "Зображення" "У відповідь на %1$s" "Встановити APK" @@ -302,6 +319,7 @@ "Будь ласка, зачекайте…" "Ви впевнені, що хочете закінчити це опитування?" "Опитування: %1$s" + "Опитування" "Всього голосів: %1$s" "Результати будуть показані після завершення опитування" @@ -343,7 +361,7 @@ "Збережені зміни" "Збереження" - "Блокування екрану" + "Блокування екрана" "Шукати когось" "Результати пошуку" "Безпека" @@ -368,7 +386,7 @@ "Поділитися місцезнаходженням в реальному часі" "Поширене розташування" "Простір спільного користування" - "Вихід" + "Вилучення пристрою" "Щось пішло не так" "Ми зіткнулися з проблемою. Будь ласка, повторіть спробу." "Простір" @@ -394,21 +412,22 @@ "Неможливо розшифрувати" "Надіслано з незахищеного пристрою" "Ви не маєте доступу до цього повідомлення" - "Ідентичність відправника скинуто" + "Звірена цифрова ідентичність відправника була скинута" "Не вдалося надіслати запрошення одному чи кільком користувачам." "Не вдалося надіслати запрошення" "Розблокувати" "Увімкнути звук" "Непідтриманий виклик" "Непідтримувана подія" + "%1$s розпочинає виклик" "Ім\'я користувача" - "Верифікацію скасовано" - "Верифікацію завершено" - "Перевірка не вдалася" - "Перевірено" - "Верифікувати пристрій" - "Підтвердити особу" - "Верифікувати користувача" + "Звіряння скасовано" + "Звіряння завершено" + "Не вдалося звірити" + "Звірено" + "Звірити пристрій" + "Підтвердити ідентичність" + "Звірити користувача" "Відео" "Висока якість" "Найкраща якість, але більший розмір файлу" @@ -425,11 +444,11 @@ "%1$s (%2$s) поділився цим повідомленням, оскільки вас не було в кімнаті, коли його надіслали." "%1$s поділився цим повідомленням, оскільки вас не було в кімнаті, коли його надіслали." "Згідно із налаштувань цієї кімнати, нові учасники можуть переглядати історію. %1$s" - "Ідентичність %1$s скинуто. %2$s" - "Ідентичність %1$s %2$s скинуто. %3$s" + "Цифрову ідентичність %1$s скинуто. %2$s" + "Цифрову ідентичність %1$s %2$s скинуто. %3$s" "(%1$s)" - "Ідентичність %1$s скинуто." - "Ідентичність %1$s %2$s скинуто. %3$s" + "Цифрову ідентичність %1$s скинуто." + "Цифрову ідентичність %1$s %2$s скинуто. %3$s" "Відкликати верифікацію" "Надати доступ" "Посилання %1$s спрямовує вас на інший сайт %2$s @@ -473,13 +492,17 @@ "Вибачте, сталася помилка" "🔐️ Приєднуйтеся до мене в %1$s" "Вітаю, поспілкуйтеся зі мною в %1$s: %2$s" + "Обмін місцезнаходженням у реальному часі" + "Триває обмін місцезнаходженням" + "%1$s Місцезнаходження в реальному часі" "%1$s Android" - "Повідомити про ваду за допомогою Rageshake" + "Повідомляти про помилку потрусивши телефон" "Знімок екрана" "%1$s: %2$s" "Варіанти" "Вилучити %1$s" "Налаштування" + "Кількість голосів, дозволених на одну особу" "Ніхто не ділиться своєю геопозицією" "Обмін геопозицією" @@ -497,11 +520,11 @@ "%1$d Закріплених повідомлення" "Закріплені повідомлення" - "Ви збираєтеся перейти до свого облікового запису %1$s, щоб скинути свій обліковий запис. Після цього ви повернетесь до програми." - "Не можете підтвердити? Перейдіть до свого облікового запису, щоб скинути облікові дані." + "Ви збираєтеся перейти до свого облікового запису %1$s, щоб скинути свою цифрову ідентичність. Після цього ви повернетеся до застосунку." + "Не можете підтвердити? Перейдіть до свого облікового запису, щоб скинути цифрову ідентичність." "Відкликати верифікацію та відправити" "Ви все одно можете відкликати підтвердження та надіслати це повідомлення, або ви можете скасувати підписку на даний момент і спробувати пізніше після повторної перевірки %1$s." - "Ваше повідомлення не надіслано, оскільки підтверджену особистість %1$s скинуто" + "Ваше повідомлення не надіслано, оскільки звірена цифрова ідентичність %1$s була скинута" "Надіслати повідомлення в будь-якому випадку" "%1$s використовує один або кілька неперевірених пристроїв. Ви можете відправити повідомлення в будь-якому випадку, або ж скасувати відправку і спробувати пізніше, коли %2$s перевірить всі пристрої." "Ваше повідомлення не було надіслано, тому що %1$s не перевірив усі пристрої" @@ -534,15 +557,22 @@ "Простори" "Надано доступ %1$s" "На карті" - "Повідомлення не надіслано, оскільки підтверджену особистість %1$s скинуто." + + "+ %1$d приєднується" + "+ %1$d приєднуються" + "+ %1$d приєднуються" + + "Повідомлення не надіслано, оскільки звірена цифрова ідентичність %1$s була скинута." "Повідомлення не надіслано, оскільки %1$s перевірив не всі пристрої." - "Повідомлення не надіслано, оскільки ви не підтвердили один або кілька своїх пристроїв." + "Повідомлення не надіслано, оскільки ви не звірили один або кілька своїх пристроїв." "Розташування" "Версія: %1$s (%2$s)" "uk" "Історичні повідомлення недоступні на цьому пристрої" - "Щоб отримати доступ до історичних повідомлень, потрібно верифікувати цей пристрій" + "Щоб отримати доступ до історії повідомлень, потрібно звірити цей пристрій" "Ви не маєте доступу до цього повідомлення" "Неможливо розшифрувати повідомлення" - "Це повідомлення заблоковано оскільки ви не верифікували свій пристрій, або тому, що відправнику потрібно верифікувати вашу особистість." + "Це повідомлення заблоковано, оскільки ви не звірили свій пристрій або відправник повинен звірити вашу цифрову ідентичність." + "Ваш пристрій занадто старий, потрібен пристрій з Android 8 або новіший." + "Відтворення карт не підтримується" diff --git a/libraries/ui-strings/src/main/res/values-zh/translations.xml b/libraries/ui-strings/src/main/res/values-zh/translations.xml index e40d369f76..bd0844f822 100644 --- a/libraries/ui-strings/src/main/res/values-zh/translations.xml +++ b/libraries/ui-strings/src/main/res/values-zh/translations.xml @@ -1,9 +1,12 @@ + "添加头像" "添加反应:%1$s" "地址" "头像" "最小化消息文本框" + "减少每人允许的投票数" + "增加每人允许的投票数" "删除" "已输入 %1$d 个数字" @@ -28,6 +31,7 @@ "第 %1$d 页" "暂停" "语音消息,时长:%1$s,当前位置:%2$s" + "照片预览" "PIN 字段" "已钉住的位置" "播放" @@ -60,6 +64,7 @@ "已封存的房间" "用户头像" "用户菜单" + "视频预览" "查看头像" "查看详情" "语音消息,时长:%1$s" @@ -96,6 +101,7 @@ "拒绝并屏蔽" "删除" "删除账户" + "删除文件" "删除投票" "取消全选" "禁用" @@ -187,9 +193,11 @@ "翻译" "重试" "取消置顶" + "视频通话" "查看" "在时间线上查看" "查看源码" + "语音通话" "是" "是,重试" "你的服务器现在支持更快的新协议。现在注销并重新登录以升级。立即这样做可以避免你在以后删除旧协议时被强制注销。" @@ -210,6 +218,7 @@ "已屏蔽用户" "气泡" "来电被拒接" + "通话进行中" "通话已开始" "你已拒接来电" "聊天记录备份" @@ -218,7 +227,7 @@ "正在创建房间…" "正在创建空间…" "申请已取消" - "离开房间" + "已离开房间" "离开空间" "邀请已拒绝" "解密错误" @@ -253,7 +262,9 @@ "文件已保存到“下载”" "转发消息" "常用" + "图库" "GIF" + "群组通话进行中" "图片" "回复 %1$s" "安装 APK" @@ -299,6 +310,7 @@ "请稍候…" "确定要结束这个投票吗?" "投票:%1$s" + "投票" "总票数:%1$s" "结果将在投票结束后显示" @@ -388,6 +400,7 @@ "解除静音" "不受支持的通话" "不支持的事件" + "%1$s 已开始通话" "用户名" "验证已取消" "验证完成" @@ -462,6 +475,7 @@ "嗨!请通过 %1$s 与我联系:%2$s" "正在共享实时位置" "位置共享正在进行" + "%1$s 实时位置" "%1$s Android" "摇一摇以报告 bug" "屏幕截图" @@ -469,6 +483,7 @@ "选项" "移除 %1$s" "设置" + "每人允许的投票数" "目前无人分享其位置" "共享实时位置" @@ -519,6 +534,9 @@ "空间" "已共享 %1$s" "在地图上" + + "+ %1$d 人已加入" + "消息未能发送,因为 %1$s 的已验证数字身份已被重置。" "消息未能发送,因为 %1$s 尚未验证所有设备。" "消息未能发送,因为你有尚未验证的设备。" @@ -530,4 +548,6 @@ "无权访问此消息" "无法解密消息" "此消息已被阻止,因为你未验证你的设备,或发送者需要验证你的数字身份。" + "你的设备过旧,需要 Android 8 或更高版本的设备。" + "地图渲染不受支持。" diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index d74f532484..82acfd14b3 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -1,9 +1,13 @@ + "Add avatar" "Add reaction: %1$s" "Address" "Avatar" + "Clear search field" "Minimise message text field" + "Decrease votes allowed per person" + "Increase votes allowed per person" "Delete" "%1$d digit entered" @@ -29,6 +33,7 @@ "Page %1$d" "Pause" "Voice message, duration: %1$s, current position: %2$s" + "Photo preview" "PIN field" "Pinned location" "Play" @@ -39,13 +44,14 @@ "QR Code" "React with %1$s" "React with other emojis" - "Read by %1$s and %2$s" + "Previous message read by %1$s and %2$s" - "Read by %1$s and %2$d other" - "Read by %1$s and %2$d others" + "Previous message read by %1$s and %2$d other" + "Previous message read by %1$s and %2$d others" - "Read by %1$s" + "Previous message read by %1$s" "Tap to show all" + "show all read receipts" "Remove reaction: %1$s" "Remove reaction with %1$s" "Room avatar" @@ -63,6 +69,7 @@ "Tombstoned room" "User avatar" "User menu" + "Video preview" "View avatar" "View details" "Voice message, duration: %1$s" @@ -99,6 +106,7 @@ "Decline and block" "Delete" "Delete account" + "Delete file" "Delete Poll" "Deselect all" "Disable" @@ -190,9 +198,11 @@ "Translate" "Try again" "Unpin" + "Video call" "View" "View in timeline" "View source" + "Voice call" "Yes" "Yes, try again" "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later." @@ -213,6 +223,7 @@ "Blocked users" "Bubbles" "Call declined" + "Call in progress" "Call started" "You declined a call" "Chat backup" @@ -256,7 +267,9 @@ Reason: %1$s." "File saved to Downloads" "Forward message" "Frequently used" + "Gallery" "GIF" + "Group call in progress" "Image" "In reply to %1$s" "Install APK" @@ -399,6 +412,7 @@ Reason: %1$s." "Unmute" "Unsupported call" "Unsupported event" + "%1$s started a call" "Username" "Verification cancelled" "Verification complete" @@ -481,6 +495,7 @@ Are you sure you want to continue?" "Options" "Remove %1$s" "Settings" + "Votes allowed per person" "Nobody is sharing their location" "Sharing live location" @@ -533,6 +548,10 @@ Are you sure you want to continue?" "Spaces" "Shared %1$s" "On the map" + + "+ %1$d joined" + "+ %1$d joined" + "Message not sent because %1$s’s verified digital identity was reset." "Message not sent because %1$s has not verified all devices." "Message not sent because you have not verified one or more of your devices." @@ -545,4 +564,6 @@ Are you sure you want to continue?" "You don\'t have access to this message" "Unable to decrypt message" "This message was blocked either because you did not verify your device or because the sender needs to verify your digital identity." + "Your device is too old, a device with Android 8 or newer is required." + "Rendering maps is not supported" diff --git a/libraries/ui-strings/src/main/res/values/temporary.xml b/libraries/ui-strings/src/main/res/values/temporary.xml new file mode 100644 index 0000000000..fd1edb0759 --- /dev/null +++ b/libraries/ui-strings/src/main/res/values/temporary.xml @@ -0,0 +1,11 @@ + + + + "Mark as read" + "Jump to first unread message" + diff --git a/libraries/ui-utils/build.gradle.kts b/libraries/ui-utils/build.gradle.kts index a0144fbc27..f1423107db 100644 --- a/libraries/ui-utils/build.gradle.kts +++ b/libraries/ui-utils/build.gradle.kts @@ -19,6 +19,7 @@ android { dependencies { implementation(projects.libraries.androidutils) implementation(projects.services.toolbox.impl) + implementation(libs.androidx.compose.ui.text) testCommonDependencies(libs) } diff --git a/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/text/TextDirection.kt b/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/text/TextDirection.kt new file mode 100644 index 0000000000..33c01cb8ff --- /dev/null +++ b/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/text/TextDirection.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.ui.utils.text + +import androidx.compose.ui.text.style.TextDirection + +/** + * Detect if a text is RTL or not, based on its content. + */ +fun TextDirection.Companion.detect(text: String): TextDirection { + return if (text.any(::isRtlChar)) TextDirection.Rtl else TextDirection.Ltr +} + +/** + * Detect if a character is an RTL character or not, based on its Unicode directionality. + */ +fun isRtlChar(char: Char): Boolean = when (Character.getDirectionality(char)) { + Character.DIRECTIONALITY_RIGHT_TO_LEFT, + Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC, + Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING, + Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE -> true + else -> false +} diff --git a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/CustomRecoveryPassphrase.kt b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/CustomRecoveryPassphrase.kt new file mode 100644 index 0000000000..c7bc602dde --- /dev/null +++ b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/CustomRecoveryPassphrase.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.wellknown.api + +/** + * Server-driven settings for a user-chosen recovery passphrase, advertised under the well-known + * `custom_recovery_passphrase` key. Today the only rule is a minimum character count; additional + * settings can be added here as the schema grows. + */ +data class CustomRecoveryPassphrase( + val minCharacterCount: Int, +) { + /** True when [input] meets every active rule. */ + fun isSatisfiedBy(input: String): Boolean = isSatisfiedBy(input.length) + + /** True when an input of [length] characters meets every active rule. */ + fun isSatisfiedBy(length: Int): Boolean = length >= minCharacterCount +} diff --git a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt index 4c1c476c7a..8f2c07ab68 100644 --- a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt +++ b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt @@ -15,4 +15,5 @@ data class ElementWellKnown( val brandColor: String?, val notificationSound: String?, val identityProviderAppScheme: String?, + val customRecoveryPassphrase: CustomRecoveryPassphrase?, ) diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt index 2e2b5de16f..cd0f39c77f 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt @@ -15,7 +15,15 @@ import kotlinx.serialization.Serializable * Example: *
  * {
- *     "registration_helper_url": "https://element.io"
+ *     "registration_helper_url": "https://element.io",
+ *     "enforce_element_pro": true,
+ *     "rageshake_url": "https://example.org/rageshake",
+ *     "brand_color": "#FF0000",
+ *     "notification_sound": "ring.flac",
+ *     "idp_app_scheme": "io.element.app",
+ *     "custom_recovery_passphrase": {
+ *         "min_character_count": 8
+ *     }
  * }
  * 
* . @@ -34,4 +42,12 @@ data class InternalElementWellKnown( val notificationSound: String? = null, @SerialName("idp_app_scheme") val identityProviderAppScheme: String? = null, + @SerialName("custom_recovery_passphrase") + val customRecoveryPassphrase: InternalCustomRecoveryPassphrase? = null, +) + +@Serializable +data class InternalCustomRecoveryPassphrase( + @SerialName("min_character_count") + val minCharacterCount: Int? = null, ) diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt index 41ed54d7db..c8760881d4 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt @@ -8,7 +8,19 @@ package io.element.android.libraries.wellknown.impl +import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase import io.element.android.libraries.wellknown.api.ElementWellKnown +import timber.log.Timber + +private val loggerTag = LoggerTag("Wellknown") + +/** + * Floor for the recovery passphrase minimum length. A value of 1 guarantees the derived passphrase is + * never empty (an empty passphrase derives a recoverable but effectively unprotected secret-storage + * key). Anything stronger than non-empty is left to the homeserver operator's configuration. + */ +private const val MINIMUM_PASSPHRASE_CHARACTER_COUNT = 1 internal fun InternalElementWellKnown.map() = ElementWellKnown( registrationHelperUrl = registrationHelperUrl, @@ -17,4 +29,20 @@ internal fun InternalElementWellKnown.map() = ElementWellKnown( brandColor = brandColor, notificationSound = notificationSound, identityProviderAppScheme = identityProviderAppScheme, + customRecoveryPassphrase = customRecoveryPassphrase?.toPublic(), ) + +private fun InternalCustomRecoveryPassphrase.toPublic(): CustomRecoveryPassphrase { + // Whenever the homeserver advertises the settings block we run the custom passphrase flow, flooring + // the minimum at 1 so the passphrase can never be empty even if the server omits min_character_count + // or advertises a non-positive value. The operator owns any stronger minimum. + val min = (minCharacterCount ?: MINIMUM_PASSPHRASE_CHARACTER_COUNT).coerceAtLeast(MINIMUM_PASSPHRASE_CHARACTER_COUNT) + if (min != minCharacterCount) { + Timber.tag(loggerTag.value).w( + "custom_recovery_passphrase.min_character_count was %s; flooring to %d", + minCharacterCount, + min, + ) + } + return CustomRecoveryPassphrase(minCharacterCount = min) +} diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/api/CustomRecoveryPassphraseTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/api/CustomRecoveryPassphraseTest.kt new file mode 100644 index 0000000000..d4e7ac112e --- /dev/null +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/api/CustomRecoveryPassphraseTest.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.wellknown.api + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class CustomRecoveryPassphraseTest { + @Test + fun `empty input never satisfies a positive minimum`() { + assertThat(CustomRecoveryPassphrase(minCharacterCount = 1).isSatisfiedBy("")).isFalse() + } + + @Test + fun `input shorter than minimum is not satisfied`() { + assertThat(CustomRecoveryPassphrase(minCharacterCount = 8).isSatisfiedBy("abc")).isFalse() + } + + @Test + fun `input exactly at minimum is satisfied`() { + assertThat(CustomRecoveryPassphrase(minCharacterCount = 8).isSatisfiedBy("abcdefgh")).isTrue() + } + + @Test + fun `input longer than minimum is satisfied`() { + assertThat(CustomRecoveryPassphrase(minCharacterCount = 4).isSatisfiedBy("abcdefgh")).isTrue() + } +} diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt index cca40e283f..a64d156f6e 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt @@ -19,6 +19,7 @@ import io.element.android.libraries.cachestore.api.CacheStore import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.sessionstorage.test.InMemoryCacheStore +import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.services.toolbox.api.systemclock.SystemClock @@ -51,6 +52,7 @@ class DefaultSessionWellknownRetrieverTest { brandColor = null, notificationSound = null, identityProviderAppScheme = null, + customRecoveryPassphrase = null, ) ) ) @@ -76,6 +78,7 @@ class DefaultSessionWellknownRetrieverTest { brandColor = "#FF0000", notificationSound = "a_notification_sound.flac", identityProviderAppScheme = "an_app_scheme", + customRecoveryPassphrase = null, ) ) ) @@ -105,6 +108,93 @@ class DefaultSessionWellknownRetrieverTest { brandColor = null, notificationSound = null, identityProviderAppScheme = null, + customRecoveryPassphrase = null, + ) + ) + ) + } + + @Test + fun `get element wellknown with custom recovery passphrase settings`() = runTest { + val sut = createDefaultSessionWellknownRetriever( + getUrlLambda = { + Result.success( + """{ + "custom_recovery_passphrase": { + "min_character_count": 8 + } + }""".trimIndent().toByteArray() + ) + }, + ) + assertThat(sut.getElementWellKnown()).isEqualTo( + WellknownRetrieverResult.Success( + anElementWellKnown( + customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 8) + ) + ) + ) + } + + @Test + fun `get element wellknown with custom recovery passphrase settings missing min character count floors to 1`() = runTest { + val sut = createDefaultSessionWellknownRetriever( + getUrlLambda = { + Result.success( + """{ + "custom_recovery_passphrase": {} + }""".trimIndent().toByteArray() + ) + }, + ) + assertThat(sut.getElementWellKnown()).isEqualTo( + WellknownRetrieverResult.Success( + anElementWellKnown( + customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 1) + ) + ) + ) + } + + @Test + fun `get element wellknown with zero min character count floors to 1`() = runTest { + val sut = createDefaultSessionWellknownRetriever( + getUrlLambda = { + Result.success( + """{ + "custom_recovery_passphrase": { + "min_character_count": 0 + } + }""".trimIndent().toByteArray() + ) + }, + ) + assertThat(sut.getElementWellKnown()).isEqualTo( + WellknownRetrieverResult.Success( + anElementWellKnown( + customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 1) + ) + ) + ) + } + + @Test + fun `get element wellknown with negative min character count floors to 1`() = runTest { + val sut = createDefaultSessionWellknownRetriever( + getUrlLambda = { + Result.success( + """{ + "custom_recovery_passphrase": { + "min_character_count": -5 + } + }""".trimIndent().toByteArray() + ) + }, + ) + assertThat(sut.getElementWellKnown()).isEqualTo( + WellknownRetrieverResult.Success( + anElementWellKnown( + customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 1) ) ) ) @@ -157,6 +247,7 @@ class DefaultSessionWellknownRetrieverTest { brandColor = "#FF0000", notificationSound = "a_notification_sound.flac", identityProviderAppScheme = "an_app_scheme", + customRecoveryPassphrase = null, ) ) ) @@ -210,6 +301,7 @@ class DefaultSessionWellknownRetrieverTest { brandColor = "#FF0000", notificationSound = "a_notification_sound.flac", identityProviderAppScheme = "an_app_scheme", + customRecoveryPassphrase = null, ) ) ) diff --git a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt index ae7d1c629c..51b06f7226 100644 --- a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt +++ b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt @@ -8,6 +8,7 @@ package io.element.android.features.wellknown.test +import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase import io.element.android.libraries.wellknown.api.ElementWellKnown fun anElementWellKnown( @@ -17,6 +18,7 @@ fun anElementWellKnown( brandColor: String? = null, notificationSound: String? = null, identityProviderAppScheme: String? = null, + customRecoveryPassphrase: CustomRecoveryPassphrase? = null, ) = ElementWellKnown( registrationHelperUrl = registrationHelperUrl, enforceElementPro = enforceElementPro, @@ -24,4 +26,11 @@ fun anElementWellKnown( brandColor = brandColor, notificationSound = notificationSound, identityProviderAppScheme = identityProviderAppScheme, + customRecoveryPassphrase = customRecoveryPassphrase, +) + +fun aCustomRecoveryPassphrase( + minCharacterCount: Int = 8, +) = CustomRecoveryPassphrase( + minCharacterCount = minCharacterCount, ) diff --git a/plugins/src/main/kotlin/Versions.kt b/plugins/src/main/kotlin/Versions.kt index 5e9a8694be..237aa9ad67 100644 --- a/plugins/src/main/kotlin/Versions.kt +++ b/plugins/src/main/kotlin/Versions.kt @@ -39,13 +39,13 @@ private const val versionYear = 26 * Month of the version on 2 digits. Value must be in [1,12]. * Do not update this value. it is updated by the release script. */ -private const val versionMonth = 5 +private const val versionMonth = 7 /** * Release number in the month. Value must be in [0,99]. * Do not update this value. it is updated by the release script. */ -private const val versionReleaseNumber = 2 +private const val versionReleaseNumber = 0 object Versions { /** @@ -61,19 +61,19 @@ object Versions { * Compile SDK version. Must be updated when a new Android version is released. * When updating COMPILE_SDK, please also update BUILD_TOOLS_VERSION. */ - const val COMPILE_SDK = 36 + const val COMPILE_SDK = 37 /** * Build tools version. Must be kept in sync with COMPILE_SDK. * The value is used by the release script. */ @Suppress("unused") - private const val BUILD_TOOLS_VERSION = "36.0.0" + private const val BUILD_TOOLS_VERSION = "37.0.0" /** * Target SDK version. Should be kept up to date with COMPILE_SDK. */ - const val TARGET_SDK = 36 + const val TARGET_SDK = 37 /** * Minimum SDK version for FOSS builds. diff --git a/plugins/src/main/kotlin/extension/CommonExtension.kt b/plugins/src/main/kotlin/extension/CommonExtension.kt index 5f243f4319..1f24473f8e 100644 --- a/plugins/src/main/kotlin/extension/CommonExtension.kt +++ b/plugins/src/main/kotlin/extension/CommonExtension.kt @@ -9,67 +9,111 @@ package extension import Versions -import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.ApplicationDefaultConfig +import com.android.build.api.dsl.ApplicationExtension +import com.android.build.api.dsl.CompileOptions +import com.android.build.api.dsl.LibraryDefaultConfig +import com.android.build.api.dsl.LibraryExtension +import com.android.build.api.dsl.Lint import isEnterpriseBuild import org.gradle.api.Project import java.io.File -fun CommonExtension<*, *, *, *, *, *>.androidConfig(project: Project) { - defaultConfig { - compileSdk = Versions.COMPILE_SDK - minSdk = Versions.minSdk - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" +fun ApplicationExtension.androidAppConfig(project: Project) { + compileSdk = Versions.COMPILE_SDK - vectorDrawables { - useSupportLibrary = true - generatedDensities() - } - } - - compileOptions { - sourceCompatibility = Versions.javaVersion - targetCompatibility = Versions.javaVersion - } - - testOptions { - unitTests.isReturnDefaultValues = true - } + defaultConfig(::defaultApplicationConfig) + compileOptions(::defaultCompileOptions) + testOptions(::defaultTestOptions) lint { - lintConfig = File("${project.rootDir}/tools/lint/lint.xml") - if (isEnterpriseBuild) { - // Disable check on ObsoleteSdkInt for Enterprise builds - // since the min sdk is higher for Enterprise builds - disable.add("ObsoleteSdkInt") - } - checkDependencies = false - abortOnError = true - ignoreTestSources = true - ignoreTestFixturesSources = true - checkGeneratedSources = false + project.defaultLintOptions(this) } } -fun CommonExtension<*, *, *, *, *, *>.composeConfig() { +fun LibraryExtension.androidLibraryConfig(project: Project) { + compileSdk = Versions.COMPILE_SDK - buildFeatures { - compose = true - } - - packaging { - resources.excludes.apply { - add("META-INF/AL2.0") - add("META-INF/LGPL2.1") - } - } + defaultConfig(::defaultLibraryConfig) + compileOptions(::defaultCompileOptions) + testOptions(::defaultTestOptions) lint { - // Extra rules for compose - // Disabled until lint stops inspecting generated ksp files... - // error.add("ComposableLambdaParameterNaming") - error.add("ComposableLambdaParameterPosition") - ignoreTestFixturesSources = true - checkGeneratedSources = false + project.defaultLintOptions(this) } } +fun ApplicationExtension.composeAppConfig() { + buildFeatures(::defaultComposeBuildFeatures) + packaging(::defaultPackagingOptions) + lint(::defaultComposeLintOptions) +} + +fun LibraryExtension.composeLibraryConfig() { + buildFeatures(::defaultComposeBuildFeatures) + packaging(::defaultPackagingOptions) + lint(::defaultComposeLintOptions) +} + +fun defaultApplicationConfig(applicationDefaultConfig: ApplicationDefaultConfig) = applicationDefaultConfig.apply { + minSdk = Versions.minSdk + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + vectorDrawables { + useSupportLibrary = true + generatedDensities() + } +} + +fun defaultLibraryConfig(libraryDefaultConfig: LibraryDefaultConfig) = libraryDefaultConfig.apply { + minSdk = Versions.minSdk + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + vectorDrawables { + useSupportLibrary = true + generatedDensities() + } +} + +fun defaultCompileOptions(compileOptions: CompileOptions) = compileOptions.apply { + sourceCompatibility = Versions.javaVersion + targetCompatibility = Versions.javaVersion +} + +fun defaultTestOptions(testOptions: com.android.build.api.dsl.TestOptions) = testOptions.apply { + unitTests.isReturnDefaultValues = true +} + +fun defaultComposeBuildFeatures(buildFeatures: com.android.build.api.dsl.BuildFeatures) = buildFeatures.apply { + compose = true +} + +fun defaultPackagingOptions(packagingOptions: com.android.build.api.dsl.Packaging) = packagingOptions.apply { + resources.excludes.apply { + add("META-INF/AL2.0") + add("META-INF/LGPL2.1") + } +} + +fun defaultComposeLintOptions(lint: Lint) = lint.apply { + // Extra rules for compose + // Disabled until lint stops inspecting generated ksp files... + // error.add("ComposableLambdaParameterNaming") + error.add("ComposableLambdaParameterPosition") + ignoreTestFixturesSources = true + checkGeneratedSources = false +} + +fun Project.defaultLintOptions(lint: Lint) = lint.apply { + lintConfig = File("${project.rootDir}/tools/lint/lint.xml") + if (isEnterpriseBuild) { + // Disable check on ObsoleteSdkInt for Enterprise builds + // since the min sdk is higher for Enterprise builds + disable.add("ObsoleteSdkInt") + } + checkDependencies = false + abortOnError = true + ignoreTestSources = true + ignoreTestFixturesSources = true + checkGeneratedSources = false +} diff --git a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts index a489884df5..4683ee1b5f 100644 --- a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts @@ -9,9 +9,9 @@ /** * This will generate the plugin "io.element.android-compose-application" to use by app */ -import extension.androidConfig +import extension.androidAppConfig import extension.commonDependencies -import extension.composeConfig +import extension.composeAppConfig import extension.composeDependencies import extension.setupKover import org.gradle.accessors.dm.LibrariesForLibs @@ -19,14 +19,13 @@ import org.gradle.accessors.dm.LibrariesForLibs val libs = the() plugins { id("com.android.application") - id("kotlin-android") id("com.autonomousapps.dependency-analysis") id("org.jetbrains.kotlin.plugin.compose") } android { - androidConfig(project) - composeConfig() + androidAppConfig(project) + composeAppConfig() compileOptions { isCoreLibraryDesugaringEnabled = true } diff --git a/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts b/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts index 26b1a1f122..1fd697806d 100644 --- a/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts @@ -9,9 +9,9 @@ /** * This will generate the plugin "io.element.android-compose-library", used in android library with compose modules. */ -import extension.androidConfig +import extension.androidLibraryConfig import extension.commonDependencies -import extension.composeConfig +import extension.composeLibraryConfig import extension.composeDependencies import extension.setupKover import org.gradle.accessors.dm.LibrariesForLibs @@ -19,14 +19,13 @@ import org.gradle.accessors.dm.LibrariesForLibs val libs = the() plugins { id("com.android.library") - id("kotlin-android") id("com.autonomousapps.dependency-analysis") id("org.jetbrains.kotlin.plugin.compose") } android { - androidConfig(project) - composeConfig() + androidLibraryConfig(project) + composeLibraryConfig() compileOptions { isCoreLibraryDesugaringEnabled = true } diff --git a/plugins/src/main/kotlin/io.element.android-library.gradle.kts b/plugins/src/main/kotlin/io.element.android-library.gradle.kts index c10c1bb3d7..18b1e1d3f8 100644 --- a/plugins/src/main/kotlin/io.element.android-library.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-library.gradle.kts @@ -9,7 +9,7 @@ /** * This will generate the plugin "io.element.android-library", used in android library without compose modules. */ -import extension.androidConfig +import extension.androidLibraryConfig import extension.commonDependencies import extension.setupKover import org.gradle.accessors.dm.LibrariesForLibs @@ -17,12 +17,11 @@ import org.gradle.accessors.dm.LibrariesForLibs val libs = the() plugins { id("com.android.library") - id("kotlin-android") id("com.autonomousapps.dependency-analysis") } android { - androidConfig(project) + androidLibraryConfig(project) compileOptions { isCoreLibraryDesugaringEnabled = true } diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png index c975946b3d..f41f849449 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad7189cbb855280fd2e12a5dc43d0062918f76ddcc4b5cc7677748cf08a4afa9 -size 34478 +oid sha256:25753de5e78f127478e94ca29354a0ef057a20b795b302a911748b724b206c17 +size 33753 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png index adfa2c9666..94b18f3f19 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17acafce434f31f50b3232c2bebcd3bb828c70031cb892d7f5a78704f5d58661 -size 36455 +oid sha256:4cac82fe268df0631f766e69030e1dc1bdb09d869db18e62d15c563e9ff81260 +size 36237 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png index ae6d2b8bd1..a8937dbed9 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f063ef08eaf607de6d7d7361046ac96f8932d232b1f5cc48125cc2ac04d30531 -size 45836 +oid sha256:88eab769270bf7492cfbafbd537392348b76780bc93c2b4b858f1fecbc8e8af2 +size 45264 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png index 777af38fbf..f7d745f184 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f30f5d0f8e410f3addc64cd5fa7fbed8505bcd562a75de06cbf3a1e7a40ceb0 -size 46745 +oid sha256:d94c8697c49e36f4275860e6a1825815738f1c8263ae7e129cd4139b2544b3e7 +size 46286 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png index 16cf139fa9..41b1a4e9cf 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ce82d48e8b0b0c78a978277886a9916775cc12fc28edeb2807f63afb879c6a5 -size 48236 +oid sha256:919e66822097fe71920c70c4923bcb61b332fb0766dd0bfd4e662081854151c3 +size 47732 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png index ae6d2b8bd1..a8937dbed9 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f063ef08eaf607de6d7d7361046ac96f8932d232b1f5cc48125cc2ac04d30531 -size 45836 +oid sha256:88eab769270bf7492cfbafbd537392348b76780bc93c2b4b858f1fecbc8e8af2 +size 45264 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_de.png index 0fb00157c3..d8196828b8 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c844dd51824db5a123a2b7e564a001b3609245259ec25c601a181eb69362098 -size 46863 +oid sha256:ce9fbcbf082cf07edbb271870818e74782cbc5ed6c71624e1297b9af10a3c130 +size 46273 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_de.png index 08a4e04bba..f98071e4d3 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9b6138083429a82d1de576009df367a52361b39e5ac094d0c4abc0bb47e89550 -size 41888 +oid sha256:42d004e1086f2224bb9ab8b41568d4e7f60a9f4c5b7a3e75394ef0f623f8bebf +size 41247 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_de.png index 371a8aca55..866b224b68 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e3b6ee300dc038fbea819d19286d10bdf023872abda1bbe6d81b4fef97a2d934 -size 41341 +oid sha256:df105a3030abbf1760d5c1ee580664349f745d08023ad0f5da784ff7a6a3a1db +size 40619 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png index 62ffd0f03e..b8bf1e9d18 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d550d37eb3a14779dd33171843339729cf3457f9a2a6e9d41d89b6c9f52f2f0f -size 35489 +oid sha256:cc1d720d39e352d815fe20759dae937f87a50e89cf9de4aa998d20e2408417dc +size 34846 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png index 9a45949a2f..99923dc3af 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68ab96769960de6cc00a06b2ca59cbf4ad20e9788c9fcf09b4ddb126104359f7 -size 37773 +oid sha256:ff909aab1190f8d9eff5b3c100df6d2a5cad0513955a1ab09351b2ac6fd9a021 +size 37618 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png index fe057074c4..d5ea39c88e 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8583c1a707b3784dc2daf279628d86d813046743f77568aa1acb0361ce7cb4e -size 47505 +oid sha256:7d10e5c062dee14e0775ac72884ebbed0fe41aae4d1bb9a0892d8fa456d8c296 +size 47067 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png index fc4b29fedf..5c2eb9e1e6 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9016458c07e6c5e8fd962fe1ef08d0da82572c867304fb3ff4f694f83c40f36c -size 48497 +oid sha256:44fd0dd695a9e059ab54b2e6c628a6ac24625ec7c9c92c651c6626a228bd541c +size 48101 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png index 62222688ca..0863a13d18 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ba0af2f22cd932c626df190f2139f11906934b4d5de16cc1fde9d35488552ab -size 50028 +oid sha256:fe8b585c1bca2036160cac128233b0899c091bbc30fd087a72e4b1191ee5eef9 +size 49666 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png index fe057074c4..d5ea39c88e 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8583c1a707b3784dc2daf279628d86d813046743f77568aa1acb0361ce7cb4e -size 47505 +oid sha256:7d10e5c062dee14e0775ac72884ebbed0fe41aae4d1bb9a0892d8fa456d8c296 +size 47067 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_de.png index 5a68c04ad0..5b794372ed 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab9a5bc72358625c7623b3156365c299eaec576e96d11ecc3946e92511815509 -size 48578 +oid sha256:0d56402d64dc752d4cccc3a1e0642a69ca244225cce346aa842fdf3cc492f8d1 +size 48121 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_de.png index 5771464dd2..9495d79405 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:981e3075d5285a630932c02427cca3d46efad74a640f12d35da8e0f29fb4b779 -size 43474 +oid sha256:55e147811154db2ce5de206693057fedf11b38ce6fcf23ef7ef4ac9ee00d4f7d +size 42888 diff --git a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_de.png b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_de.png index 11f94e5f15..c393b6bc0e 100644 --- a/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_de.png +++ b/screenshots/de/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d35a6a56027b453b845400ec2b5b5912eb5eff551b2c370a26110b584ed3d3a3 -size 42939 +oid sha256:807efc10c7d97dcfcbbaa2c696996c9ffe3c69f3f21d992fee0635f5c1dd623b +size 42289 diff --git a/screenshots/de/features.home.impl.components_RoomListContentView_Day_0_de.png b/screenshots/de/features.home.impl.components_RoomListContentView_Day_0_de.png index 05106c3ac1..dd7ef2cf63 100644 --- a/screenshots/de/features.home.impl.components_RoomListContentView_Day_0_de.png +++ b/screenshots/de/features.home.impl.components_RoomListContentView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2f2b452d5f951c917841eacea002106c353f1236a63450498a7cb3cab948ab1 -size 43627 +oid sha256:ab2ea24bf2c91529674d2d3d582137ec195c6d28f10d65d46c1851716c1d1408 +size 43842 diff --git a/screenshots/de/features.home.impl.components_RoomListContentView_Day_5_de.png b/screenshots/de/features.home.impl.components_RoomListContentView_Day_5_de.png index 944aa69386..1a9997ccbd 100644 --- a/screenshots/de/features.home.impl.components_RoomListContentView_Day_5_de.png +++ b/screenshots/de/features.home.impl.components_RoomListContentView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6708f52e140fb8a5e2697a221182d36048671063ae3fdca96a49c131a129cc0 -size 63960 +oid sha256:5eee6d3b3040f3144e4785aa1b14fdf2057ef9a43a758317f4d59a47c8fbc2fb +size 63817 diff --git a/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_0_de.png b/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_0_de.png index efd83f7af8..3419248cbe 100644 --- a/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_0_de.png +++ b/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f2e4ee3ec519388e7acdedac96636aa3f0e0d9dc4f4a061a0b3e4c345b824a3d -size 24961 +oid sha256:9af82b0e785a85acb47d0b02b682c659bc13dbff01eb969f367d2ee413b6cbb1 +size 25165 diff --git a/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_1_de.png b/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_1_de.png index b7a581021f..706b96c796 100644 --- a/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_1_de.png +++ b/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d367fc2d1c620eb370e28db890e4f01acd85b0273b241d0b0b701f23939fabc8 -size 25377 +oid sha256:37dc07b7be3f81a8b3925e1325baecff04dc2f3cd92316140f969610b6362169 +size 25691 diff --git a/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_2_de.png b/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_2_de.png index 0c1e7996ff..b8c5829e1e 100644 --- a/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_2_de.png +++ b/screenshots/de/features.home.impl.roomlist_RoomListContextMenu_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6175b377fcdb3f70739c36ceb1d59a7e108d8f1d08b4c10ec6d28744ff0f0545 -size 27442 +oid sha256:ace88630fc2d12ce8f9f610683626ff9d8ad8d3a18564791d3abdcff5743ed46 +size 27731 diff --git a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png index e37cdbea74..9114db106e 100644 --- a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png +++ b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d2644ac4e57a29d145c34f7752496e5985430760ef2f519f78588afcc2fbc70 -size 85745 +oid sha256:ed39d041acd3bb008f20f567b93fa01217dbbe075d198a213b9058351d198118 +size 85682 diff --git a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png index 5bfa67b2fd..1a7a7bfa89 100644 --- a/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png +++ b/screenshots/de/features.home.impl.spaces_HomeSpacesView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27e1b519904b26e0164f1bebd1dc1c28abe2f4352d107f07d66db7ed9dd59e52 -size 38165 +oid sha256:1fe768ccb0272e435f42ba94c6b15ed3b6703f32385a307def2040f703b3ba0a +size 38119 diff --git a/screenshots/de/features.home.impl_HomeView_Day_0_de.png b/screenshots/de/features.home.impl_HomeView_Day_0_de.png index 3f4ea30f5c..7a78ab01dc 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_0_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 -size 69561 +oid sha256:b9c0e16d5506092e20da1413016148110a5509b4f1a906d22967a59171770443 +size 69777 diff --git a/screenshots/de/features.home.impl_HomeView_Day_13_de.png b/screenshots/de/features.home.impl_HomeView_Day_13_de.png index ae22fbde6b..53e115bc5a 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_13_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba73b9e725eed082239a57c1233bb05e69a0a44dddaa64a4cc2b4a8e83130dfc -size 99560 +oid sha256:53d6acbc84bc668a38789626e17f9ffa288b3ef9b4911a18dfd93d24d5ec5b35 +size 99809 diff --git a/screenshots/de/features.home.impl_HomeView_Day_14_de.png b/screenshots/de/features.home.impl_HomeView_Day_14_de.png index 7476615fc3..f845f2e13f 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_14_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_14_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36a222231a7399ffa88190117f82db0f96b3a3aef4c939988e8f862c75d1fa52 -size 91989 +oid sha256:64771726d8c2436f1478c503991176d2f675b21fa36c9228bf18976f73034b7c +size 91946 diff --git a/screenshots/de/features.home.impl_HomeView_Day_1_de.png b/screenshots/de/features.home.impl_HomeView_Day_1_de.png index 3f4ea30f5c..7a78ab01dc 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_1_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 -size 69561 +oid sha256:b9c0e16d5506092e20da1413016148110a5509b4f1a906d22967a59171770443 +size 69777 diff --git a/screenshots/de/features.home.impl_HomeView_Day_2_de.png b/screenshots/de/features.home.impl_HomeView_Day_2_de.png index 3f4ea30f5c..7a78ab01dc 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_2_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 -size 69561 +oid sha256:b9c0e16d5506092e20da1413016148110a5509b4f1a906d22967a59171770443 +size 69777 diff --git a/screenshots/de/features.home.impl_HomeView_Day_3_de.png b/screenshots/de/features.home.impl_HomeView_Day_3_de.png index f4adeb4894..9520da70ed 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_3_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7a3316558a8b352adc4bfc18030e8cf30e06fd5f3e78524c46e3cdbdd2c5907 -size 65168 +oid sha256:1a025368b62aa4bd6fb915a7f52b42acee43e73a0291126eb52440c29e9d8162 +size 64511 diff --git a/screenshots/de/features.home.impl_HomeView_Day_4_de.png b/screenshots/de/features.home.impl_HomeView_Day_4_de.png index f5b92f61d9..22c21d8384 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_4_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c54f63ff4b9621dc8e34179f15033a4ff6d61dd7cb22b47e56b5e2b9fda113d4 -size 57802 +oid sha256:eaa2cf678000a055ecb900430c4c7986af97e365df42ac17682b6525febbbe25 +size 57680 diff --git a/screenshots/de/features.home.impl_HomeView_Day_5_de.png b/screenshots/de/features.home.impl_HomeView_Day_5_de.png index 3f4ea30f5c..7a78ab01dc 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_5_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ffc6ec59463b5047e28186f2e0628dcd10391ce51515f2ffbbca150fe590cf4 -size 69561 +oid sha256:b9c0e16d5506092e20da1413016148110a5509b4f1a906d22967a59171770443 +size 69777 diff --git a/screenshots/de/features.home.impl_HomeView_Day_6_de.png b/screenshots/de/features.home.impl_HomeView_Day_6_de.png index 467350fe56..1aa91d8732 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_6_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5cc8182e0e5413cc51f0df6d2724efae8af4101f9ac6cf21ca9260c2a2aa245a -size 57989 +oid sha256:da970271201eb9d665400d1ef5791d5e3ae5f770c8bec9c07bd25275ac5fe942 +size 58273 diff --git a/screenshots/de/features.home.impl_HomeView_Day_7_de.png b/screenshots/de/features.home.impl_HomeView_Day_7_de.png index 774818bd57..cae7125417 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_7_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f235995960c6237f4e03e7b0736cb280e1627590b0761a334c7a969491a12da8 -size 57321 +oid sha256:d11e27bd7446de6523449ce5f718df71f89a7d68ddb17f84ae7cc055273db655 +size 57593 diff --git a/screenshots/de/features.home.impl_HomeView_Day_8_de.png b/screenshots/de/features.home.impl_HomeView_Day_8_de.png index e644082cae..ee515055c9 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_8_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba1fbfc866d6de2cafae55b6da0721f12a1acb25163ad31ae2995f6ff9016856 -size 56039 +oid sha256:2adf95b28da91bdc7bee8a34d035dea6fd7980970e16143727677b72cd238ec4 +size 56339 diff --git a/screenshots/de/features.home.impl_HomeView_Day_9_de.png b/screenshots/de/features.home.impl_HomeView_Day_9_de.png index 3a5002ae42..6465fe66b3 100644 --- a/screenshots/de/features.home.impl_HomeView_Day_9_de.png +++ b/screenshots/de/features.home.impl_HomeView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fef5908ddd4fba551a21710e5558089d8b22af459b8024ec0e49489e44a9409c -size 93092 +oid sha256:35b33bec36e7731a2aea269b1a3c1b3e1506855f4f75fcf0ef0745a9165d140a +size 93077 diff --git a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_0_de.png b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_0_de.png index 94bf3f406b..f032ae2d3c 100644 --- a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_0_de.png +++ b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbd1cef03d962c679705a6a7f54fb78c504360df94c1734eef8435e5122b834a -size 37265 +oid sha256:7007f01f29c880ae8019beab2d2314b93fae26a90c6359f287098314632cab99 +size 37291 diff --git a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_10_de.png b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_10_de.png index 821bf59326..4bf78594db 100644 --- a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_10_de.png +++ b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:569ac37ef5a1a15b294d70e0aba93dd2c4a8f8e2c23cc043e82759ab06ce14a6 -size 54965 +oid sha256:27a5bb5482628162bc6da9caf59fd0bf62f8bec661f30896f11c3442ced3e471 +size 54950 diff --git a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_1_de.png b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_1_de.png index ff371dc689..553eccad81 100644 --- a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_1_de.png +++ b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1269f6fa16bb38ea55ed98b502c3fb350fde867e31b18cb6a61b2306f75ca6cb -size 50323 +oid sha256:445fab1f219d05b107836780070ac6b91c02b4cc0f289e0b30145f1cefea757d +size 50657 diff --git a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_9_de.png b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_9_de.png index ff371dc689..553eccad81 100644 --- a/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_9_de.png +++ b/screenshots/de/features.invitepeople.impl_InvitePeopleView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1269f6fa16bb38ea55ed98b502c3fb350fde867e31b18cb6a61b2306f75ca6cb -size 50323 +oid sha256:445fab1f219d05b107836780070ac6b91c02b4cc0f289e0b30145f1cefea757d +size 50657 diff --git a/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_4_de.png b/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_4_de.png index 107aa2698a..823bf7c844 100644 --- a/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_4_de.png +++ b/screenshots/de/features.knockrequests.impl.list_KnockRequestsListView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e75d1447ac2e3a46a57488300f582d050e7494ec280fb52eee2b15bbe2a3774 -size 57121 +oid sha256:0e7e18df03c83c7a0d5d1074677a121fdf7177de86b74811533aff21d34234d0 +size 57197 diff --git a/screenshots/de/features.linknewdevice.impl.screens.error_ErrorView_Day_3_de.png b/screenshots/de/features.linknewdevice.impl.screens.error_ErrorView_Day_3_de.png index 7ea7736a31..fbcb03812f 100644 --- a/screenshots/de/features.linknewdevice.impl.screens.error_ErrorView_Day_3_de.png +++ b/screenshots/de/features.linknewdevice.impl.screens.error_ErrorView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06fa1d9cfcdd7e81dd5d08f584651d982136e7491041b4db6c0feb9875c2db49 -size 43509 +oid sha256:026cde07bd625e7457af44ef19c4865f6bad8fc7c8ddfcc43c7a6dbdd4acf467 +size 33651 diff --git a/screenshots/de/features.location.api_RenderingMapsNotSupportedDialog_Day_0_de.png b/screenshots/de/features.location.api_RenderingMapsNotSupportedDialog_Day_0_de.png new file mode 100644 index 0000000000..06c4be2c81 --- /dev/null +++ b/screenshots/de/features.location.api_RenderingMapsNotSupportedDialog_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3065603f9b067f0ddc89a7b8dc24921afd031f4658f6ac11de8feb0c4bf26b62 +size 23910 diff --git a/screenshots/de/features.location.impl.share_ShareLocationView_Day_9_de.png b/screenshots/de/features.location.impl.share_ShareLocationView_Day_9_de.png new file mode 100644 index 0000000000..d8b464213f --- /dev/null +++ b/screenshots/de/features.location.impl.share_ShareLocationView_Day_9_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1ab182dfc2b45c80972722b1963a75c29175c1d09369fafb96c7b0ea04bf08a +size 21171 diff --git a/screenshots/de/features.location.impl.show_ShowLocationView_Day_6_de.png b/screenshots/de/features.location.impl.show_ShowLocationView_Day_6_de.png index d52980f113..0c68797fef 100644 --- a/screenshots/de/features.location.impl.show_ShowLocationView_Day_6_de.png +++ b/screenshots/de/features.location.impl.show_ShowLocationView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e8cb1edecba35913251d57d6eaa9d48149f7b2a26c180978c0ae34d3d354d97 -size 19693 +oid sha256:6fe56f20ce5792f9dd60bf0ae08fa5c5c78fbb7a5f1a80eb2fe973716be69c00 +size 19831 diff --git a/screenshots/de/features.location.impl.show_ShowLocationView_Day_7_de.png b/screenshots/de/features.location.impl.show_ShowLocationView_Day_7_de.png index 0c68797fef..a49023fb61 100644 --- a/screenshots/de/features.location.impl.show_ShowLocationView_Day_7_de.png +++ b/screenshots/de/features.location.impl.show_ShowLocationView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6fe56f20ce5792f9dd60bf0ae08fa5c5c78fbb7a5f1a80eb2fe973716be69c00 -size 19831 +oid sha256:fa435ee5d684b82c66c7207e0bcdc2d608a634e02d534530cccf8abd0f40f784 +size 21292 diff --git a/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_de.png b/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_de.png index 901899b6aa..9ea51fc8de 100644 --- a/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_de.png +++ b/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f79feaab47702a7875ffd06557bd90bb36792195fa1643f8614162ae49e57316 -size 19094 +oid sha256:73eff278a1d56a54cc068a145b73d792e0e40c7bc6db926df2db1c23229ef5a7 +size 19145 diff --git a/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_de.png b/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_de.png index 3df5f3c6a9..25429f5f83 100644 --- a/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_de.png +++ b/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51a45136541e3bc31adb410303f8244c8ac75cea055d673e94eded52bc867445 -size 21317 +oid sha256:0e9079d17f328a1b1bc24c3d85f9c0db5d76a1a8a5937bcbadaa092cb0b71f6e +size 21325 diff --git a/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_de.png b/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_de.png index abf9afbd2f..69eb1f4aeb 100644 --- a/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_de.png +++ b/screenshots/de/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52921866cbcc80363f8bf8d3fb57a94fcdac7910d0dd56d83c9d6feb9912aaab -size 32648 +oid sha256:8ff4b516f4282d6a78164c011332a4dd9dc1d0fe5f21ef7b5d574503d271eb90 +size 32624 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_de.png new file mode 100644 index 0000000000..4bc3702d4b --- /dev/null +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bce43aafc388033e057078e19b68f609f8f40a9c81b6a236a6e9735df6cb24f4 +size 34798 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_de.png new file mode 100644 index 0000000000..92b3009a33 --- /dev/null +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8304689ab13c57ecbef0d34863d2f5d0178d04656ba8371ac41c8c8adf1771f9 +size 35106 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_de.png new file mode 100644 index 0000000000..2a985393c6 --- /dev/null +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fef8dac7418c2ee8655e7ee488b4c1dc2765fdfc3fcee86685c9059c48254770 +size 22796 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_0_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_0_de.png index 44b295fbb3..bde4a6cba7 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_0_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c0f9f0948da8553e64cbd3dd8643420dbbe0b2ee0655ef09b4d4869495f8f67 -size 38036 +oid sha256:4c764d8bd6dbf39c937b45eaa6a24b048ab9db1528494503494c02b6fcdf1523 +size 38035 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_10_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_10_de.png new file mode 100644 index 0000000000..1d4a0bcf29 --- /dev/null +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_10_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:29c3399d104ced9fdbfc5be3dd9792fa5b3a42174a3cb81fcee11ac099a80055 +size 38394 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_1_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_1_de.png index 3b324af20f..2ec1d65aaf 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_1_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53f201aeace81ee0564d41542bfc8ea904d71527746ead6cbd6e9faddf29e699 -size 38421 +oid sha256:b047b01f0573eff0ae7798afbbed1df7e52c754df8d5a7744958eed939179443 +size 38422 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_2_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_2_de.png index 0343205abb..b6dd30b9a3 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_2_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:15200b3f62fbd9b0ecab51560faa4696f384daf7463a407445b2191f94c13645 -size 38695 +oid sha256:962d90cd71c5ed7ea19ad08bb641f197466defb85840ff7ed30d49656eee1b06 +size 38679 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_3_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_3_de.png index d78926b966..06011700ab 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_3_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb3267c007e01c5e691841911e4aa7bcfe319077a6b4f49d945e9bacc5474087 -size 45041 +oid sha256:ca9d69de30e7fa7008263c78f5586814d109ab8c043a19ed687f9327b955e03e +size 45033 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_4_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_4_de.png index 2b7542cc53..ba059493a7 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_4_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30358430cd572face46c5d6e060fe0b93947670aa4c4caa091f8a50521ae36a7 -size 35467 +oid sha256:902411746e402c8c5e82393ba854d40a17f60b0ff5ab13ce3b8928449bf92fa4 +size 35471 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_5_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_5_de.png index 4502875e08..e9d66d7ee5 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_5_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71f8a9d484a4056507b129f7fb390b2c67c99ec46a928da15caac4f95ffbd6fd -size 42006 +oid sha256:41a80abb68a227320c18a797f73efe0fe9dc0ebed50fe8f6523c433fc566e6df +size 41989 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_6_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_6_de.png index 014fdcd4b7..759b17db50 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_6_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c2e7d3a0b31388c8f373920e71ca23228fd5961a1705b3032b1407f35dc2e28 -size 31051 +oid sha256:93caba67729429e85bfe4a26846a1ea1c122f1b1aa7e0622dc11bdecb2741cd8 +size 31032 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png index 2840a40c3b..1fed050403 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91a83c3de10fea2e5edf3d96bc9ecc1fd81000ec957970696bca6c13d4d9dca3 -size 31820 +oid sha256:fc5e9086a7896b21d7a46fbad3ee5962be125fdd5f9609603dfe6f1779395c7a +size 31798 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_8_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_8_de.png index 28afdb624e..2e062dad91 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_8_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6f6d2946d194ba97c64e6749b1f9d8bf4ce52e685d06631cf22b47e156791d1 -size 41526 +oid sha256:b3cbbc047bbdfa813c4bb984a469370b33d8ceb44b1e57e2a40cf84c7b20f7a1 +size 41492 diff --git a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_9_de.png b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_9_de.png index 9c540f1299..9968deee8e 100644 --- a/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_9_de.png +++ b/screenshots/de/features.lockscreen.impl.unlock_PinUnlockView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b74c5fd9cb084ca2c391ea65dea23ecc027d1206510841ada0d28d5f6674995 -size 32940 +oid sha256:fcfcf26c1c2cb4e33e6709232f535331ce00fdde22455940e7b02b4dc727ecb2 +size 32938 diff --git a/screenshots/de/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_de.png b/screenshots/de/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_de.png index 4d4ea2f91b..dddd616aee 100644 --- a/screenshots/de/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_de.png +++ b/screenshots/de/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d1ce3c32dbdbaf44d7e2dc92687c66212538b89bfebfb0eb5e7b7dd768dd0ebc -size 6983 +oid sha256:0abc6cf5caded1e0feed221cab79a46b7e718ddb584c3483bc23ce8ddccae909 +size 7035 diff --git a/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_de.png b/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_de.png index 6d5ff2fb19..6f7d6a890e 100644 --- a/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_de.png +++ b/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30d254a28c96235d956b694cae9e698a73c86b2c750e458efc88e08fc4d18a58 -size 55417 +oid sha256:af547cb5fc2383ebd6171d2833b481c0969e273f144e24bd121e07678fbd54ab +size 55044 diff --git a/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_de.png b/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_de.png index d7180b80b0..5fe846ac85 100644 --- a/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_de.png +++ b/screenshots/de/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6cca634095d7d739fde70368cc0115c6041734cd8346006acbd5f377b9b91a5d -size 52531 +oid sha256:90815365dfcf8173bc6793920eaeb200b8fc0d07a395bd13d8f3606578de5c85 +size 52318 diff --git a/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_de.png b/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_de.png index 795eb7f26a..860b8ce02d 100644 --- a/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_de.png +++ b/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d187b6625c1faa80e8586ee0eafdf204f8409a2ac7c2e04fb56397482d928cf -size 22145 +oid sha256:da20d1d3458a85ae1fb27923cbb5bf338bfc3386d1725dc8222836bb3984b49d +size 22169 diff --git a/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_de.png b/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_de.png index 7de0dea136..cc70955112 100644 --- a/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_de.png +++ b/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7ba030dbe6187462882c8f850bce242f7fe0e3fda7e84dc4d89f72509f03a26 -size 23032 +oid sha256:d722df4ed5bcb4eb50d360c0170f9ad786c7652ea5f4316d15800d8e2ecb2af7 +size 23058 diff --git a/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_de.png b/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_de.png index ecb67acfc5..b9d19b2899 100644 --- a/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_de.png +++ b/screenshots/de/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a89d26ff170ac81964f27ab8c43772afb295446c2c1d7281f8ac4fe6bfddbf35 -size 23650 +oid sha256:a0bc78928bf5d2f228f0f81ad96b5d87a317aa69c19ad6690bc1decf4f51539d +size 23680 diff --git a/screenshots/de/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_de.png b/screenshots/de/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_de.png index c3966f7b8f..a5492d7f3b 100644 --- a/screenshots/de/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_de.png +++ b/screenshots/de/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92c6387df06a280ad6467b8a819c3e7435fafc0a3ea440b090e240e952b552cb -size 59255 +oid sha256:1482aa508f02e9e4db7a91e5cf69f3d6f9cf5b2f30ec76ca8c5b76a9428e76cd +size 59401 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png index 8df559390e..b45f9735e9 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5758b86295a5cd92cd103992ee601c762b876fec28a4380c793a6c054993513b -size 35016 +oid sha256:ec2f3efaf97bcc35ec40f04a2196ff6c194a9481847e10354aab7a84ffe44cb6 +size 35651 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png index 044901ea5b..9c4b79d103 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ce01cf6c3d326ad4208fa9832cab3e56164f791f59833b1f73d6f29e531dab8 -size 54709 +oid sha256:2958036448d7d58899dbfbda756a9d426bce315ef5b435d79396a9a80784940a +size 55178 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png index a7ba678616..7844abdf8c 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c52f77e77180d8e15b67abefac41b54107397fd489440d5aafdc4079d0100b8 -size 55075 +oid sha256:2d217bc76203d0dbbda69a567502a0ef2966408422ddea258b1171a72d32c382 +size 55460 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png index 220ebf1ac9..4c23a8e276 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29ac70d223cc1f1c3a63c21431864f60bd6e199de574e1a2cded10bcaac11a8d -size 46842 +oid sha256:ca13fadfa2beebca49b47539556a7b65f9ad1e79b73af5d1682c743899c7563b +size 47402 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png index 5150bb2206..995e5ead80 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f04c852c210a027d1792d7512aa9ecc3a6913d3ba9d18d8680df991f8050f57d -size 51086 +oid sha256:40fa4dc8d26755ff63458009a315eebd3709b600e0a1a702d4943ce799235632 +size 51647 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png index 3c5ff4c7c5..db7d125d2e 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c0d6742849583dc21500d5dba09bf535f71a5bcd070cd129305c1dffd817d8b5 -size 49443 +oid sha256:553c3b8caf077981aeabe99175f5626737347f5ddf8eb983f6453f18d52f28f2 +size 50050 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png index ef8273806a..8f8b6a4d85 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbf746337b88e848b7e99e526efe2ba468d28fd1536970ddc4e02e0d946e026d -size 45151 +oid sha256:efb40271c1a53965bc57d1a43517d1043df44bb3df97042b0255f66e96a01a28 +size 45325 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png index b75f0d76b6..7ca56941ca 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:63b5fdd8b50485c835ce04e61b3c21d2f6d306d73c98675d1368772f4ca74c1d -size 49708 +oid sha256:918feb5ac03bee1e4b7fd833d1d6c5614aea5356cccd6655fb43152a5d9629fe +size 50302 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png index 0d842f530c..3f72616816 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d7e27bf9c1e2fa0bd86fbf986ced9f21ceabddae14c00086b691f182aa7ec5b -size 45918 +oid sha256:323c2ce83c77f3a68c6543f6c9882639ee33004fb9fd5717f2e1e2b7db68dc81 +size 46073 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png index b6587618ec..e69c8dc756 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f61af5729e24ee0b15af8df2bd641411ac8f17a5b7f9a76899c6d05f328dbd05 -size 48879 +oid sha256:438227f1c69e12a7f4e661820e1bd8ae49b2849ff6fc4fcab3850f3c17b67239 +size 49412 diff --git a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png index e41b40ead2..439f7d1e9e 100644 --- a/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png +++ b/screenshots/de/features.messages.impl.actionlist_ActionListViewContent_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f83a10070d130542d0783c8a39f588b869ec265b9c0026afaeccc0b7b50602e4 -size 38159 +oid sha256:bce484eb6c854e78da2d354728de6b4f4f74d5f75ea452174ac9f5343be448bf +size 38679 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_de.png new file mode 100644 index 0000000000..210020e06e --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99d5cf65c968619f2a99f382e2de07d08022f0325349f86571c5766d17fff9e0 +size 327894 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_de.png new file mode 100644 index 0000000000..3ee21f4b12 --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:82b816075c7ca6898da2c295740f6828a15a16062e944f01a4401ac0b84f6008 +size 282325 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_de.png new file mode 100644 index 0000000000..7aeafb4481 --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11222c39d8ef830649fdd0b35c95b31b4d934c0c2667674ef7d659d9a3320b52 +size 255483 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_de.png new file mode 100644 index 0000000000..2c62689a45 --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc3d7320da4451c862f1083981d628a4df4115e95f9e88db7e0d1910f9890eba +size 276670 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_de.png new file mode 100644 index 0000000000..1ba1a3158a --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b23a3fd19bb6057dc13f61525a4589a3d1dd66a97818c4229d4db35cb6f56faa +size 250779 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_de.png new file mode 100644 index 0000000000..3f3fa22933 --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:028b3249d8d63cdf799ac1e0ab530e4a46140c53adf8b83a05153d03d030d4e6 +size 310168 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_6_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_6_de.png new file mode 100644 index 0000000000..aaedf662af --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_6_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:24b6a36a3efa0127a099081ef711fa804879ddca347849580e80c2a147c7f4c9 +size 282515 diff --git a/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_7_de.png b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_7_de.png new file mode 100644 index 0000000000..5b2ff9626b --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_7_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7138b55da8a0a0a3ed2c049ec84d01fa298223a3b6ffe391fad7a7e3a3a3beb2 +size 282778 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_de.png index 3d408f0ee2..486830b06a 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c110f007c954fd01fad8d4e9810abae47bb89c330141c7c1d6412d3995943f4b -size 400985 +oid sha256:ec642dfd92ffcd3ba4a9ed06518481935c4e38342622c4c5c74efdd68a4e7190 +size 403979 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_de.png index 4ce254bb81..77e3ac9d5b 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af9841032d9faebbee6f759259ef14b0d4cca3424ac110e1dfd1d3357768e436 -size 399354 +oid sha256:45e5a33dc04d65050fd9098727f262dca526d5f55f2c64ecd235e9ae97aa8767 +size 402313 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_2_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_2_de.png index d466ee2bc4..7700d70b06 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_2_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8fae17aad6ac7dfb2fd2fac83c2c1b6d9e0743fa9d3d1a874fe269284149ce29 -size 62760 +oid sha256:608236a6a1864f0036fb0d2bcd85d7269557dc3453876495585573471d08d2de +size 65085 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_de.png index 3d408f0ee2..486830b06a 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c110f007c954fd01fad8d4e9810abae47bb89c330141c7c1d6412d3995943f4b -size 400985 +oid sha256:ec642dfd92ffcd3ba4a9ed06518481935c4e38342622c4c5c74efdd68a4e7190 +size 403979 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_4_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_4_de.png index c45996cc7b..c9b90482e3 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_4_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dbcda50596ea08167fda422fae89758bc46c719cd320103def3c90cea0a152ff -size 62616 +oid sha256:116502f69435e6d7a5fe9fe9a2a604fcca36d1c6e1e09836595769cf8e8022d9 +size 64937 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_de.png index a1ae4a1c9b..a1609b8144 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b1172f37d89f97ec0360402c013328ad65bfb62422d5b81a8d06e9d8dc3cbba -size 67739 +oid sha256:4d3ecea8217faca0d45acfa0a04023efff0124ad0563857ec4ce81e826033f74 +size 70311 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_de.png index 3baea3a223..a10d3f58f7 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29d6a3980b5928907e5d5203ba4a5010feed5ca67107ef464933717664d72fb1 -size 71937 +oid sha256:f350e78ea3bba4a80d22af4df58b8a6e415a68fe56770027c9da95da0cab0973 +size 327790 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_de.png index be72870cdf..f609ffd014 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df744636336e3b7dcf4b8c20a3a9dcf70247ea0a5602c11665bb020925c94dd1 -size 407934 +oid sha256:fd092ba5b859abc14b18702a613aa4b7bbfad43c2e91e294ad876edbcc5f9960 +size 74489 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_de.png index 48b54318d5..ed5e8cf442 100644 --- a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_de.png +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea59b97a710eab6b10192373c7058b301e0d2b4bfe07d16f952d69593b8b78d7 -size 88581 +oid sha256:5ae9aeabad16587e233b815e60c76856f30f7296562a2b4abb1149a8490435ee +size 410888 diff --git a/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_9_de.png b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_9_de.png new file mode 100644 index 0000000000..50674e05be --- /dev/null +++ b/screenshots/de/features.messages.impl.attachments.preview_AttachmentsPreviewView_9_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a927ba77b12465d718d8b09ed12c4c04b18c2d9474d242a2c1a8bbea5cf3b226 +size 90934 diff --git a/screenshots/de/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_de.png b/screenshots/de/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_de.png index ee068ebc52..ce82506ac2 100644 --- a/screenshots/de/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_de.png +++ b/screenshots/de/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a237e342ba5bce3980d0f0164afe658993741ff8238e7cbdf9c73f7eb83f2f4c -size 36792 +oid sha256:c5194a762cd92151c0f5de9c29d2393bb7c93137f03bcb7750f788bf449f0508 +size 36902 diff --git a/screenshots/de/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_de.png b/screenshots/de/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_de.png index 14abdc0caf..198bd4553b 100644 --- a/screenshots/de/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_de.png +++ b/screenshots/de/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e4f823bf8a422775693ba64ca10e087286967d11c8ed94a3198f108abd3a9367 -size 27026 +oid sha256:1ff21ba8a011e0aedbbcad919f46db1a26895ae6e286335055532f43dbf505de +size 27661 diff --git a/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_de.png b/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_de.png index 807e16c40a..6d9b506ac7 100644 --- a/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_de.png +++ b/screenshots/de/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bbdd0d31786b29709c02e9f35191af1334b6f6a32cc0614a833f79d47551fc70 -size 42687 +oid sha256:cc44a5bef33ae51161dee412b729baf328b188976156d7eeb7677039ad60b7cd +size 42147 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_de.png new file mode 100644 index 0000000000..fc985de87d --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f358da2b9b0521c14e525bcb2bd41c29c96aacaf5f007546e6d362bde2ee3fb +size 612526 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_de.png index a854d161d7..2a6974b789 100644 --- a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_de.png +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad01125850f8dc08f39832fe3ffcaae1950edd736a80f39811b4c1d9a6eafd93 -size 122264 +oid sha256:42743cf803a9acb5dac130af3de4fa08f78847567ce6aee1ec5596a96ed09e6c +size 197869 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_de.png index 2ed9893cb4..abdfda2abe 100644 --- a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_de.png +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dbe9d2831b54807db3c329ac4ca9e853198195df21f8db348050b40fe98cab5f -size 121228 +oid sha256:1be36834af38c01a6c6153d1f6a65bb89713edb4c2641e2f2944d33b119e4bbc +size 197468 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_de.png index 236409c967..04dde37923 100644 --- a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_de.png +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d83ed47c66eb0437193de92c356668ad479dd7cd3f97e864f121fdd01b3abac -size 48319 +oid sha256:b2fa0d69002c82ea536b1d7c6d46a93bf53bb484b1f995929661af4b1b5d77d8 +size 48271 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_de.png index 3c80b38276..afe7a74f31 100644 --- a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_de.png +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a7d35ee4b53fa88a65380c38a39b8b512fa155d380458dda00fe48ead065fe1 -size 50606 +oid sha256:baf37ce8445ef13163eea35baad0c0e08a70d0cc03e9b8021407ae1b376ca95b +size 50574 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_de.png index 25a5c7d18e..e38faafccd 100644 --- a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_de.png +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:31bfafa9a3c71609932ae9de739529b6dfeb1038392cee97638311fc490c0015 -size 52029 +oid sha256:29af094f63268254fd2c67417ab4e4c129961edf2ba7076f4a8ab9a28bf19ad9 +size 51952 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_de.png index 34073d7f96..2c874ba817 100644 --- a/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_de.png +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1dce19e15e65b860ae2b8a1799ddfe49d4643582659530f7e6e900eb23a80ed -size 52380 +oid sha256:1241bde9ac9922970e2b8d1ff473e2bcc7a676057e5e62d26cdb1994b0100322 +size 52304 diff --git a/screenshots/de/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_de.png new file mode 100644 index 0000000000..80857358e7 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:54e71f45db31e8664c42f8c05feb91ae839589e00cb89d12088c15c85fb9f25f +size 607824 diff --git a/screenshots/de/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_de.png index f7ae17e756..0701db921c 100644 --- a/screenshots/de/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_de.png +++ b/screenshots/de/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38261034a3b8d7bbb53b34a50b92de88ff790bc2547065d44786a2e650789139 -size 4347 +oid sha256:19dc73c912a6f3375c0f2b7bc9e3c75481fa7107515a1655e314db070b775425 +size 4344 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_de.png index d005896ab7..b6f95124eb 100644 --- a/screenshots/de/features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_de.png +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08984e24e297742f065201c4cea3d07eda34e4c80fbcb4689e539ac64f32f1db -size 53795 +oid sha256:a2d68bc8db6190fbd5205fdaa386c250ae3a2014804a5372052d851a313a6ef1 +size 47808 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_de.png new file mode 100644 index 0000000000..0435f55de6 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff839731834d7d0c94fa9a2c412014ddbaeaa053c5af1c8cbd00a3f3a583f364 +size 379511 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_de.png new file mode 100644 index 0000000000..94428abb56 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36d7cf2510d546d2b330b1d1b1674ce58df0558c547e443794a1e7b2222add87 +size 347897 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_de.png new file mode 100644 index 0000000000..7ddac02717 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4ac79f3b8fb4e231244bd96b244a4f2526d6ed28d558f9d50734d83bbb74992 +size 363909 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_de.png new file mode 100644 index 0000000000..67490ba700 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4431e2d9f30123949ea5676ce60f642234adcf9b5a33f2acc3f80ebf6609a66 +size 369730 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_de.png new file mode 100644 index 0000000000..f0dfbc3321 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7a6302320bd1e4258e03487539bf46b0b12781dfc8a22b3f9f267017a6146fa +size 354751 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_de.png new file mode 100644 index 0000000000..68f8148879 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ca8cf82aa8ab1bdad56a27584b27789402aeb7ad8fadd038280a376fb75a72c +size 345094 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_de.png new file mode 100644 index 0000000000..8aa2cca147 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02ecb903124273e24151ea2088f6b99144f7dcadba00a582b6210dd23835b5c9 +size 357743 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_de.png new file mode 100644 index 0000000000..133fd3903f --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:426d1c844a8c88281c5fa4c61916d93278fdfd38f8cdf2dc54bf1a821f2de3eb +size 397167 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_de.png new file mode 100644 index 0000000000..0041a870b9 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2bd77c08be705c66225f16c29fd6826decd92b41922d0f8ffc0d1a63d8c59d2 +size 356193 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_de.png new file mode 100644 index 0000000000..b10f9741b9 --- /dev/null +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ec1b0244dab22414c6719b3309426e13128d0c70fb67dc66cd8a60d42521fd0 +size 355411 diff --git a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_de.png b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_de.png index c4357e38dc..cefd1decbc 100644 --- a/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_de.png +++ b/screenshots/de/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d9c7c8dcd575bf6376edd385e32b489ff322944a323df989a30e8779fc59f25 -size 56604 +oid sha256:aa9709734259b3aeae5cda5fd0cc9553ef741fa3712b5ff39fc27d1690219d3d +size 56460 diff --git a/screenshots/de/features.messages.impl.timeline_TimelineView_Day_10_de.png b/screenshots/de/features.messages.impl.timeline_TimelineView_Day_10_de.png index ff53dce724..7ba4cfc7cb 100644 --- a/screenshots/de/features.messages.impl.timeline_TimelineView_Day_10_de.png +++ b/screenshots/de/features.messages.impl.timeline_TimelineView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ebbbddf29df78c6a6b37f931052cac67ea7ae1c875e2d75fa6ae8aa1683971b -size 87348 +oid sha256:20d88acd1cec244527f3f1ae3ac49cdea7ba2e0f4710ef30eec90f8eb5d6093e +size 87253 diff --git a/screenshots/de/features.messages.impl.timeline_TimelineView_Day_4_de.png b/screenshots/de/features.messages.impl.timeline_TimelineView_Day_4_de.png index ba7d60941b..2cc385f926 100644 --- a/screenshots/de/features.messages.impl.timeline_TimelineView_Day_4_de.png +++ b/screenshots/de/features.messages.impl.timeline_TimelineView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e916a49d3cd4d81d8ec5f3d66f0b930bfba6e9c20f1b9c5f7d4c0bfe51895036 -size 67398 +oid sha256:a6325d21da32e6def01f35803b4823d037076f0c96c24d864fad33b0a7d9a7b7 +size 65731 diff --git a/screenshots/de/features.messages.impl.timeline_TimelineView_Day_6_de.png b/screenshots/de/features.messages.impl.timeline_TimelineView_Day_6_de.png index 0d70a656c2..1d36e3c163 100644 --- a/screenshots/de/features.messages.impl.timeline_TimelineView_Day_6_de.png +++ b/screenshots/de/features.messages.impl.timeline_TimelineView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:86fa2e5742ba38c173add0921615a18c1271caa783fd1a505c80a06096a3c248 -size 71646 +oid sha256:853058d4d90fc9d39115263ab74e7813ab6a52844cc56cc4a30c3dcb42e291b9 +size 70016 diff --git a/screenshots/de/features.messages.impl.topbars_MessagesViewTopBar_Day_0_de.png b/screenshots/de/features.messages.impl.topbars_MessagesViewTopBar_Day_0_de.png index 2190897314..5239fec1c7 100644 --- a/screenshots/de/features.messages.impl.topbars_MessagesViewTopBar_Day_0_de.png +++ b/screenshots/de/features.messages.impl.topbars_MessagesViewTopBar_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f952ad332aea788e87445b304894f0acf77a6ca5498d67584ab4e727cbb16eb4 -size 58055 +oid sha256:5ce1d8a9e700209185e94ec2f7fb7696188d8e264a09223f7120dd9f1215a9ef +size 57721 diff --git a/screenshots/de/features.messages.impl.topbars_ThreadTopBar_Day_0_de.png b/screenshots/de/features.messages.impl.topbars_ThreadTopBar_Day_0_de.png index 800b5dac71..ddf65dd3f6 100644 --- a/screenshots/de/features.messages.impl.topbars_ThreadTopBar_Day_0_de.png +++ b/screenshots/de/features.messages.impl.topbars_ThreadTopBar_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d33bc741fdb4b81e5b15e46c5248d0b8627f552314d02a0795c3eee24cc2b8c -size 32788 +oid sha256:cca92a56b93e76b181f8eaa54bad7d9102b452de9df115e239160f50da45e843 +size 33118 diff --git a/screenshots/de/features.messages.impl_MessagesView_Day_1_de.png b/screenshots/de/features.messages.impl_MessagesView_Day_1_de.png index 8e73293bb2..5f24ba6d45 100644 --- a/screenshots/de/features.messages.impl_MessagesView_Day_1_de.png +++ b/screenshots/de/features.messages.impl_MessagesView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1afe6a244e864befb72decf8d2518b9588b3f59b5382c8e5c6130a2ea33e23b -size 41952 +oid sha256:c100900785c0c11cd69b60da9ed3909f135b876d0546722f707febd24e796256 +size 42510 diff --git a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_de.png index e0b6b5510c..8c4b6af1e0 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:acffa3d209c390caa581e5afdf4d31ef5556e96eeac1d136cb7f24a9bc9996d3 -size 22234 +oid sha256:bb05198bc007e836b105f9139f7deeba673cd2a7664c53a85e25e5fbec2d2052 +size 22188 diff --git a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_de.png index 4780df6550..11b6cab54f 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8387c3a65fcf21312934adcb97c85f18e2764deb774c38821d360eed2f97101e -size 21960 +oid sha256:b73aa1594f1e0f6ef0903ba7bf69e48f50b6904511828213fd2462a75b670894 +size 21912 diff --git a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_de.png index dd7fd4540b..132504aee7 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bbc74888e9ddb1123ebb9e6d1f0851b55cd68b69b3bf284ff41d5e8f394e6999 -size 22042 +oid sha256:fa73db75c4d6bbc88359aeb8348eceb2a7775290218a1a761dd0e993427b6435 +size 21992 diff --git a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_de.png index 702cedc003..46f744276e 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed21a6bc055bfc7964bd0268cf4597350786e5c58c869d0fe47d3938f41e5af4 -size 21995 +oid sha256:7ef4b1d40c17d7e949d051c275cac81db5f231214499ca6f8f40d36b7cbc3e32 +size 21952 diff --git a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_de.png index 2ae2780a01..9d8e17945f 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ebef4dd474d40bd93a5448a851ea8d1400bd14e9bc625d091ef2265764a6f01f -size 21880 +oid sha256:ce03160f5c2c13b3516f75d64ec311331d1a99d7c72c2112843b25332d2de042 +size 21841 diff --git a/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_de.png index 9b8bd6aba7..b4f5edc8ab 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80411a8f91e1cbfce66887dce4cca84155199e2f2aba492526665952a09ce9a7 -size 52353 +oid sha256:525984fd154320f88445fde7298b1509a86eb8691e5a9a8cf4c58d8fda9b01ec +size 52272 diff --git a/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_de.png index 7e89601827..014cb01e47 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf3fcef9ae6c81f5f063c230a57f3b4dcbb5c6f1e4d08df176df9712dbe209e8 -size 48711 +oid sha256:b00f990de2e706b44b81ce25cbe63eca682a8336931079f5b3d06c8fee57a14d +size 48644 diff --git a/screenshots/de/features.poll.api.pollcontent_PollContentViewCreator_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollContentViewCreator_Day_0_de.png index 25a5c7d18e..e38faafccd 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollContentViewCreator_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollContentViewCreator_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:31bfafa9a3c71609932ae9de739529b6dfeb1038392cee97638311fc490c0015 -size 52029 +oid sha256:29af094f63268254fd2c67417ab4e4c129961edf2ba7076f4a8ab9a28bf19ad9 +size 51952 diff --git a/screenshots/de/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_de.png index 236409c967..04dde37923 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d83ed47c66eb0437193de92c356668ad479dd7cd3f97e864f121fdd01b3abac -size 48319 +oid sha256:b2fa0d69002c82ea536b1d7c6d46a93bf53bb484b1f995929661af4b1b5d77d8 +size 48271 diff --git a/screenshots/de/features.poll.api.pollcontent_PollContentViewEnded_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollContentViewEnded_Day_0_de.png index 7e89601827..014cb01e47 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollContentViewEnded_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollContentViewEnded_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf3fcef9ae6c81f5f063c230a57f3b4dcbb5c6f1e4d08df176df9712dbe209e8 -size 48711 +oid sha256:b00f990de2e706b44b81ce25cbe63eca682a8336931079f5b3d06c8fee57a14d +size 48644 diff --git a/screenshots/de/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_de.png b/screenshots/de/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_de.png index 9dc06851c0..69fd570f47 100644 --- a/screenshots/de/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_de.png +++ b/screenshots/de/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:543af353f726b5e68f22303bd580ad2a827affad3618140dc7ee87c12ee0d9a3 -size 46153 +oid sha256:fa2bd8a0567d05208a570830dfeea3a3f123bfe7d310c777c9f4a36d942d4583 +size 46081 diff --git a/screenshots/de/features.poll.impl.create_CreatePollView_Day_0_de.png b/screenshots/de/features.poll.impl.create_CreatePollView_Day_0_de.png index e2a4e320c3..aa6f300abb 100644 --- a/screenshots/de/features.poll.impl.create_CreatePollView_Day_0_de.png +++ b/screenshots/de/features.poll.impl.create_CreatePollView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97fc60499c5f669bfbc200fc859e8a39ac0815ad281f7fbfcec656259ef1d30f -size 39066 +oid sha256:ed6d994b119d688999501ebd52c97003b4501f0b4013ab51a75b0f20b24075c6 +size 38914 diff --git a/screenshots/de/features.poll.impl.create_CreatePollView_Day_1_de.png b/screenshots/de/features.poll.impl.create_CreatePollView_Day_1_de.png index 31603b0b30..4e493c9379 100644 --- a/screenshots/de/features.poll.impl.create_CreatePollView_Day_1_de.png +++ b/screenshots/de/features.poll.impl.create_CreatePollView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b443e0ceed54e76337bc86cd278efe22e46516659f611abb5ba166a83eccc1a -size 41925 +oid sha256:c874ff8f546368fd02b97675058578c0915739a8d0419df4d9f7c57fde325acf +size 41638 diff --git a/screenshots/de/features.poll.impl.create_CreatePollView_Day_2_de.png b/screenshots/de/features.poll.impl.create_CreatePollView_Day_2_de.png index bded534a61..9bc140b2bc 100644 --- a/screenshots/de/features.poll.impl.create_CreatePollView_Day_2_de.png +++ b/screenshots/de/features.poll.impl.create_CreatePollView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78b18d7bf93b1efa40e0746b32e3a8228e49a063d49628c7e18f1ae7288e2dbc -size 42104 +oid sha256:317e4ac99bafec3256906621758d7f2122e3fa9f751f60aa825d4a14641f3b5f +size 42146 diff --git a/screenshots/de/features.poll.impl.create_CreatePollView_Day_3_de.png b/screenshots/de/features.poll.impl.create_CreatePollView_Day_3_de.png index 2e504e332f..d015e20463 100644 --- a/screenshots/de/features.poll.impl.create_CreatePollView_Day_3_de.png +++ b/screenshots/de/features.poll.impl.create_CreatePollView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cdb9a9e2a5af6b2cd8a43e07b79d0925b317210f85c714a1b26b529870752b5 -size 49372 +oid sha256:26e47150797605d5233f2d9043b325a3e674b62f68f0aac172588c3f24385f52 +size 49345 diff --git a/screenshots/de/features.poll.impl.create_CreatePollView_Day_6_de.png b/screenshots/de/features.poll.impl.create_CreatePollView_Day_6_de.png index 1d952fc98b..cfa660cfca 100644 --- a/screenshots/de/features.poll.impl.create_CreatePollView_Day_6_de.png +++ b/screenshots/de/features.poll.impl.create_CreatePollView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30d0bef4cb216aef676fd88b4e12c76c6d1198c24a5f47c46b5398363fd1dc62 -size 42706 +oid sha256:a3f339d9122bc91e2838c7cbf8bee8f7cc50ff75540d5337834969531e6f8584 +size 42507 diff --git a/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png b/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png index f24a053b60..45eccdfdcb 100644 --- a/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png +++ b/screenshots/de/features.poll.impl.create_CreatePollView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f66184e6357282ff5b9688dfdcfaa3da2a26971a99b3258448647559e1a0d495 -size 40408 +oid sha256:d6075dc5472b55e47a0156ff75649f8360b791006dc3313d4a067749037c39db +size 40318 diff --git a/screenshots/de/features.poll.impl.history_PollHistoryView_Day_0_de.png b/screenshots/de/features.poll.impl.history_PollHistoryView_Day_0_de.png index 7731d6380c..a51cb6cf8c 100644 --- a/screenshots/de/features.poll.impl.history_PollHistoryView_Day_0_de.png +++ b/screenshots/de/features.poll.impl.history_PollHistoryView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d3cc301b373d6261bc57f91ff1f83485268f23add4864b75471b8879fd2b7cf -size 59648 +oid sha256:d33aaff7f6b61e202d114f91b3c4bbdc9e7554910b1d7bfa8aa463f508927b65 +size 59530 diff --git a/screenshots/de/features.poll.impl.history_PollHistoryView_Day_1_de.png b/screenshots/de/features.poll.impl.history_PollHistoryView_Day_1_de.png index eea3b79e31..9cdf321360 100644 --- a/screenshots/de/features.poll.impl.history_PollHistoryView_Day_1_de.png +++ b/screenshots/de/features.poll.impl.history_PollHistoryView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26284504e5cafc2c5bcdbc804a0712d4644fa2184751b76b6762c75c8b6d1cc9 -size 63811 +oid sha256:c2f1237015fe09c45636a00b3bb5991e6b1c544ab129cdf0f720db881e0f2f50 +size 63697 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_de.png index 0793b01c92..9f2744b09a 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cea139c9bc1d71d342a99ce43b6bff414e1f9cb53ac69b8994b1b7ea2c750f41 -size 60894 +oid sha256:024657931956e21eb6decfa8a39a213fc621d0f4c694bcbbd56d013d49bda838 +size 61364 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_de.png index c50a3e35cf..c3522b0cb7 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e19998bcd7bb878ee3fa1429ce7edd03293e8f9dfc2dc9cd439ad3a71ccd6276 -size 60764 +oid sha256:3ec9e46a3360cd996a219151fda05f38248af4bfe3f2a39d0becf74d840f5478 +size 61231 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_de.png index eb4c703d89..269c6bff1e 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:139462dbd69c23df0aff5b8a2b310c2a9a40a9f691ebff57a03d0bf7cf638269 -size 60757 +oid sha256:038b8dfdb5996d6da4b460a5ebe3b2f4aad5549a894babc583bcf15ffc549264 +size 61225 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_de.png index 4e5adc17e1..ab55a3a8c3 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3013b0a0e261f87364a5e72cce9d25cf59c2d1360dc778fec533268e1340a0ca -size 60755 +oid sha256:49b2f7bc8675304be3d71d144584b7e7ace735c187093749cc2b94a7af091bef +size 61229 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_de.png index 33a8e007e4..b874052a4c 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a8f056723e3999c53a1e582237290b74e178e652fd49d5b636d1256bcb846de3 -size 60597 +oid sha256:23d2a782811171fa55a0861450a667edcd2d22784ee3711bd00674f178144a4c +size 61120 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_de.png index 61e1649e93..ceed65f824 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db5aa655ec48b8b8c3019e886a742a2e7922f329c7d7e7c88ca5d70cbf2f6f3e -size 60901 +oid sha256:16644a82af1efbf83460df01b14d85d1c2d16fa2e1a9bc4d1a591082adfb6167 +size 61366 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_de.png index f48a864d6d..a7498d2de5 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0fdcef2b4374ba9a1dded6c7fe3315ccc3c585e489d59572879a1e5efe2dff1c -size 60422 +oid sha256:6b6c34ba3d6d833137c1faccbaab4ab32b844af05a6ffbd136b6582c16aebec4 +size 60891 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_de.png index 3c66dd1128..6d227268fa 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee1b3b15e7f08f2f63c556a584db2fa3ebcf004b980f7fe837c32ea2d166159c -size 60000 +oid sha256:114543bb1fb1985f0dbc2d78044e4f606eab3e30a6d99d83c5c0985fdc6bcaba +size 60458 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_de.png index 1eca9c9326..32702f443b 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1dca13f4ac7e2d0f80d302d2d819a32f536d5765b2d7533be4f019b6bc28dd92 -size 63485 +oid sha256:74261b09ccbe64e4a3902e907e22391bab3264f43f1f449d43955cb4326d5912 +size 63797 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_de.png index 246e46b33d..740cd2486b 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a060a4ef3ae0e7117863606fac9196536fce38d5483e3d882e86931d5f6098e1 -size 57951 +oid sha256:81240edb02f00691d55f343e53d3af922bbfedb32e60f757a62ae8b2f43230c9 +size 58356 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_de.png index 248175a402..e67d492f0e 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e4faac64c7b38a8b9613eddc62805a5816ed340984e62dc5d6625a79782d3e6 -size 57811 +oid sha256:822b20a349d75de5c1f7000d394f3e32b62dc419bf157dec025ef56ecf3d7f80 +size 58218 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_de.png index c8bc853a8e..f4f9d96dd6 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e4713a87444130061d605edcf65d67d5aa1d6730e8afee1ba41c751c2dac77f -size 57804 +oid sha256:03d5a02197f9ad9157752533aa9ed1c2659a0b2967c3007b6f2b2f2d2b7a98d8 +size 58210 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_de.png index 19d124ead1..87337d55fe 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8907dbe4553c7aac67cd5007dffc12a06e3c3f218fa95a75c390ee8982cf117 -size 57815 +oid sha256:49569410e3b6e1d009e87d7d652f9bcc2c7d4c77e1e5ca86be7fe9dfed9c3c1b +size 58222 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_de.png index 26bdb4b258..0cec2ab3a9 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:961a4dd2ef4c74770f9c140f4b337146225d7a626ca2082f35cc107c91263e12 -size 57670 +oid sha256:8ab6c693d3cd149dea1f9e8ba95c09710aa52c8869a866412651862680c9bd4b +size 58083 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_de.png index dca7c97656..3252e63243 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ea1eb184dcfcf13c8673f3df717a540c74eb500b759cd752e8fd270da9b8f4e -size 57951 +oid sha256:f30a0a38f20c9ead24ec669fbf7d25713d1e41b1de99d4358bfbc36f34146d5b +size 58356 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_de.png index 53eb657d5f..37272bf3ef 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad17f959304774a8956cc38cb008024e79ae70dd1d2f147b2de20a95ca29ca96 -size 57638 +oid sha256:c4f03d366950465820c07b24eb401614d122d244c1c782993f679d61d234418f +size 57924 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_de.png index 1d51b69a1a..70b5f0ccc9 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85693d212e3726d4e7bc5cd3c4c2e9d73276cac7a6cba7b9549d5b45bf55b686 -size 57160 +oid sha256:b787733f83c3c7d7f3ee8d144f4aa3f0c5a9f7985854d5b427e8ac4fe26781ab +size 57654 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_de.png index 5736128377..856754abf5 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aca6e0c7f9d7c48ca80c5a8e56a86e8d0a1cced6020d5b4ef0aae443575071ae -size 60239 +oid sha256:43dae2fb98ed0f6fc1f4d67d1c5bf2a8d0e45e5c3ba217af0dd31c7d2ea48528 +size 60496 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_de.png index 36df3fb547..cfb15dff1a 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7713d5bb6252597bfc465fc85b3283e08d95684f9d0a17fc89e08f5cf8e870e4 -size 60327 +oid sha256:0335d534e1ee34920b9f5adf79ba614d03ac62fe352a1c9da57c79f2f74b87d8 +size 60698 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_de.png index 833794c51e..f14eb96ef4 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59b93100a819cc8a0b8b8156da39f47034745bfc6d06957907009ff3eef3c2b0 -size 60210 +oid sha256:d3d773c0c42aa2070fb201fc25f4b456692543ff85085693f9003b839b31df26 +size 60584 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_de.png index 25914b7cbe..6da04e5146 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eaaf5ae88296f64e80ebbe60a126a1fd40944e31311329cade209631f36424cd -size 60223 +oid sha256:0cccc5f8efaf4ec7dcd2c0f5f21cf3141ee0a5d6884aee64b4396ac0da883d0e +size 60596 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_de.png index 2af3d0fc1b..119cdecbbb 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77c71a0c84d3fa9e39ba3c9b9b81e8a3b6e406af87e4158bfb8bb4736a8b27c7 -size 60217 +oid sha256:bb801d3af2f9343662380f6df93c9dedfe513c6c842edc91608b6b7c0f9b6b27 +size 60594 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_de.png index 9f0b5c037c..8c3bd9e91e 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9228e4ace7d30444a45deb04f211782ca53c5a366e0e812145b5b772fa51d3b -size 60085 +oid sha256:a428f83ae44b904269e7f1a8dd38854c3d99142bca7b14309c8de2484ba5269b +size 60524 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_de.png index a880ff90f4..6588f7c6fe 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c00205667f22842c1c5d63c20c0990b6e0fb7f7cd134f625957df733627378df -size 60330 +oid sha256:11abff30b2a9035a3c619ed46ef056133e90af2e67e2febe82969f5d8f4d21e5 +size 60699 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_de.png index 4265684997..1e610fb222 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cbed351c3ce6dfcb334d28316501baa5f97ade4614bd9b7dbbd91b0ce7689994 -size 59987 +oid sha256:beac41fbdfcdcb78f0693e0a4f247ae43fd29ee11f6fd8e1854c93beb2152d5b +size 60295 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_de.png index dd801a4745..68442d924a 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:09bcae54d99e6b9279794ebebf32a67f67a8347c94f3286243fe8d2c0a92f352 -size 59623 +oid sha256:05215baa5484072411d171d01d34def469a96740764782b2625f36b22c77daef +size 59999 diff --git a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_de.png b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_de.png index 2e74f12057..763d414677 100644 --- a/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_de.png +++ b/screenshots/de/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d0ccc252fedce22f568f8d26f25a8600c21236e1d489a4dd59ccd63c1085227 -size 62771 +oid sha256:851e30212320b7398100b5bdf712467538f9d58bd50724239d3ff013c596e6b8 +size 62968 diff --git a/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_de.png b/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_de.png index 7fe20b1ba2..daea1e22ae 100644 --- a/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_de.png +++ b/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:acd9db5acab1221cd8e78ba1fa3679da5e84c6c3e648e87c7143753bb636e498 -size 59053 +oid sha256:efd05a781d752f681f06ec085b7a352eda4d6a4db9107fc633f5aa187262c304 +size 59147 diff --git a/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_de.png b/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_de.png index 74819b40b1..da2ad18fe4 100644 --- a/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_de.png +++ b/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c3a9be1c0c98f2735fd882bf6ccee1efb4b2ba3f14ef161b8b4401cb01ad19d -size 56242 +oid sha256:e7ccab9e3dfa3913fa9fb0ba2b2d234c136f9a06fa9daf212919e2bf417f1465 +size 56274 diff --git a/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_de.png b/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_de.png index 61c5d7bad5..fec5646925 100644 --- a/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_de.png +++ b/screenshots/de/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cfd699dea1779a7a04f8c27b7e1034ed366f21b4248791786ebd521cf942f38f -size 53865 +oid sha256:a6f9541fcb93dabd9e48738da4a4ce12d5fb64c58cfb40c800567f8c59c8a1c9 +size 53689 diff --git a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png index c90222ce97..3a0ebcaa2f 100644 --- a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png +++ b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99f92671020a73a3350a84e30fbe8915e0d8704f846a15bc01a56ac17b223e87 -size 56493 +oid sha256:4a85070e2115cf92ea89f969ca6aa726a2e209bf9c0e8c131f54e261442313ee +size 56390 diff --git a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png index 20639717fc..0c9bcdc2d6 100644 --- a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png +++ b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ab82b153feaaa1b8f43f9a3586387e87fd598b9055ebb6d3a6ecb81c7f071f2 -size 47418 +oid sha256:04b4c9f15f880e5b82741ddadb2cded1f9d51c5acb96157042b711c152087713 +size 47422 diff --git a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png index c90222ce97..3a0ebcaa2f 100644 --- a/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png +++ b/screenshots/de/features.preferences.impl.developer_DeveloperSettingsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99f92671020a73a3350a84e30fbe8915e0d8704f846a15bc01a56ac17b223e87 -size 56493 +oid sha256:4a85070e2115cf92ea89f969ca6aa726a2e209bf9c0e8c131f54e261442313ee +size 56390 diff --git a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_de.png b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_de.png index 01b5e92f74..64c764a8aa 100644 --- a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_de.png +++ b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:035755520b2ac1f0745b100e4bf7ee51b9823e05e7baedf42667997822540ddf -size 50092 +oid sha256:469e3ce9d6ad2997c4611ee981f104207a2f492d727877383923a8d80c2824f8 +size 50096 diff --git a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_de.png b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_de.png index 7009bfc863..b1207d5499 100644 --- a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_de.png +++ b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b75989caba4bf09c4646ae6edaa66c74b3c294d09ba27a01bec69281fb1a7529 -size 50826 +oid sha256:5fc7f93f7c419f911b3d5b6b306b4eaf0cd64b84f21696dfa30373b0393d69b3 +size 50859 diff --git a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_de.png b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_de.png index 2b36d7deda..77d5dad1cb 100644 --- a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_de.png +++ b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d93e743327459fd9a32cab57bd726539c39f08dee888be875336c9df07b7319 -size 41726 +oid sha256:abcc97de678f492673a85941f66e1ad1fd98cc5faa2457105c6cecdf41ae6341 +size 41942 diff --git a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png index b9207f45b9..8f6beaa251 100644 --- a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png +++ b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bdb85156d682764c02fdb14c06e22236620f411f34ff042a7df358d6a2ef7030 -size 41012 +oid sha256:9f7127ce6ea3bc311e5385cdc6aecfd5cd48d60bb1d1562e7167326f87dcf38f +size 41153 diff --git a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_de.png b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_de.png index 1d1a4d4079..f6955a4d3c 100644 --- a/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_de.png +++ b/screenshots/de/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:48efeb0a54eecc4cdcd17a9f13f94e884272a79c7cc46df6dc791e143ca10959 -size 69223 +oid sha256:2500b1577de3fec5fe17f441a92aaa8a52137d08a85548f03bde41e273d5aaed +size 69248 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_0_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_0_de.png index 446b8185f5..078e7d0f20 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_0_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26f2620aa348febb2db9ebe379a964b76220819f7165fa7a5be5e2a38c2534a2 -size 67183 +oid sha256:6f1404b8d9cf2a4074117a0dd5f7c600bde096f1b3061e9ba86f76d316b56a07 +size 64370 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_12_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_12_de.png index dd3a3472ec..e6af8d3a74 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_12_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2290982a0712c88d4128e3a81b1c327f817c124f03f083db9562512855a4f5d -size 71473 +oid sha256:7fbbeedd76ea3453a747c860561d9c5951026ad49f44e67d56d6ad8ddf5ec208 +size 71632 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_14_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_14_de.png new file mode 100644 index 0000000000..ed49db01f0 --- /dev/null +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_14_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:989614879ae7f0104235f3547394e4491581b081f1bf091645376487a09d00ee +size 53148 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_15_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_15_de.png new file mode 100644 index 0000000000..55c801e0d2 --- /dev/null +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_15_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc6663f6bb621600ffdfe327317f80e859216fa3071914ea2210af3803c747bf +size 51729 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_16_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_16_de.png new file mode 100644 index 0000000000..3cc9288d94 --- /dev/null +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_16_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd73a2f4882661074626c99dc53bc3fc7cf52550ad2817a60dc366a078dede4a +size 52964 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_17_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_17_de.png new file mode 100644 index 0000000000..81ca5e31d8 --- /dev/null +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_17_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1de536f73fde823cf3ba37a12ae778f5ddfd2c0ba408823c92c6b197a51a5969 +size 52880 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_18_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_18_de.png new file mode 100644 index 0000000000..b2643af43a --- /dev/null +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_18_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b43ae79cdc8523d93a55a53098d7cea5d60003d954ae1f87bb30c5a2af66308 +size 48869 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_19_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_19_de.png new file mode 100644 index 0000000000..fbccf3bdba --- /dev/null +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_19_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4123b4b31046f99612585b7132f1ccea6c69a34c3bdce671b56dc8d23585493f +size 44900 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_1_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_1_de.png index e0fac995a2..81ca5e31d8 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_1_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9ebab37f3d289cd684d616961b2f4b993a851a34bb8d41ce889443ce51c4c5f -size 53981 +oid sha256:1de536f73fde823cf3ba37a12ae778f5ddfd2c0ba408823c92c6b197a51a5969 +size 52880 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_20_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_20_de.png new file mode 100644 index 0000000000..3a78ffad51 --- /dev/null +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_20_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8dfc412406efc35555095baf1b3bc408b211789e3d4ddc3e0e2f7ceb0e9176a0 +size 46489 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_2_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_2_de.png index 286ee2d3e3..884d3d5322 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_2_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d578725c9ef0c37be7115017fe1b7f7da41c02a54f932ee389d4683f2ec3f524 -size 48465 +oid sha256:297dfd25bb5b2cc0a1164febbb71623dd534f8ddb8614c50d50743c9ef417de1 +size 47530 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png index 8428aafe61..a434f64c54 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e949b9fc728afe5da33073a5273aebe797a7c45a68fc6049e9292d0a256adad7 -size 49632 +oid sha256:bc7d4a5537f9c3f87be21f2a2b48dab2568285cdc15c6ac6443b8d0696fb29e3 +size 48558 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png index 8428aafe61..a434f64c54 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e949b9fc728afe5da33073a5273aebe797a7c45a68fc6049e9292d0a256adad7 -size 49632 +oid sha256:bc7d4a5537f9c3f87be21f2a2b48dab2568285cdc15c6ac6443b8d0696fb29e3 +size 48558 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_5_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_5_de.png index e0fac995a2..81ca5e31d8 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_5_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9ebab37f3d289cd684d616961b2f4b993a851a34bb8d41ce889443ce51c4c5f -size 53981 +oid sha256:1de536f73fde823cf3ba37a12ae778f5ddfd2c0ba408823c92c6b197a51a5969 +size 52880 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png index b107216acc..0a43e1b84f 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:23548dc4c9b3ede93580ce56989ff05d4317605aaa584744f73a5897d0cd6c51 -size 46743 +oid sha256:936871dfc521b9b18b12cd52c97d1b67fae39226fb0b065b13f20a061c9a842d +size 45847 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png index 058db215b6..a20e7a834f 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a284cc8503c3cd6227afbd593d36e6f9a9eeadbd323b5cf66d77e3b5eeb6681 -size 51713 +oid sha256:2a7701285cddc1f66a569d60dd4799cf35ca070e920f95a2463d4f48d81430ff +size 50861 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_8_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_8_de.png index e0fac995a2..81ca5e31d8 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_8_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9ebab37f3d289cd684d616961b2f4b993a851a34bb8d41ce889443ce51c4c5f -size 53981 +oid sha256:1de536f73fde823cf3ba37a12ae778f5ddfd2c0ba408823c92c6b197a51a5969 +size 52880 diff --git a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_9_de.png b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_9_de.png index e0fac995a2..81ca5e31d8 100644 --- a/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_9_de.png +++ b/screenshots/de/features.preferences.impl.notifications_NotificationSettingsView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9ebab37f3d289cd684d616961b2f4b993a851a34bb8d41ce889443ce51c4c5f -size 53981 +oid sha256:1de536f73fde823cf3ba37a12ae778f5ddfd2c0ba408823c92c6b197a51a5969 +size 52880 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png index 9827329bbd..28a5fae9af 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ece0f3e49ca489a67aa7a489bc2d7e4f35a99cff4e4f2df3f7ab480965b3f972 -size 44150 +oid sha256:52c61b6e8b5322667cab679c5d9bbf5b6a0dbec6bfd8c8df2e1367df849593a0 +size 43932 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png index 28e4e403fe..0105d69f9d 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b8741879622a799c9cae5ba7ecb0f83700cdfca52dd9e6b281bfa0cc31267b3 -size 26817 +oid sha256:b987a54cc2967aab79fbbff1e2b133071483559b3eec87f0e87468652ca0fa96 +size 26764 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_2_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_2_de.png index 2f7d54a7ac..d8c7cd2d67 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_2_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61958e2bf98bcc380bca8622d53ea8d46ec466de6e8da134a9b01ea1605eca6c -size 38040 +oid sha256:bb537b9cd5288885487fa2c23f7d93d80d64b125ec824530c9dbc3c3be0ce91b +size 37934 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_3_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_3_de.png index 61aba383d1..0c8e2fe1a5 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_3_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e8275f65773690627383ef7f030f270c7f93639af5dff40ca46ee0c2d5e0316 -size 27628 +oid sha256:09ea4ed4f9abe47b57ec34d46bbc52e1740a55c299012a8ce565cfe807a63947 +size 27766 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_4_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_4_de.png index 672f329d0d..b84fd55ce2 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_4_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3efe6d5c4b5f02679eddf9be90af0ee0648a576a4488c021d9d7601aac3c71ab -size 29060 +oid sha256:8daa203d69b6e75a33fffdaacb58368fb23cf80ceb9b9f1c09173aabc3106bcd +size 29089 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_5_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_5_de.png index 5d238d5c65..a96aa07639 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_5_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewDark_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17f591ce8aa0dc3c79dd450dc58b84194625f1eee1b8fb3d5dbd67b3b1e07966 -size 21035 +oid sha256:ca5475ad46a4e9041b965454d13140fb66f4a79fd43a1c411a619a9be2188812 +size 20947 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png index ba560e522f..becff12dda 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7fff1e6cc2fe7ae2fe3dc81ee1f13f096245c238f3ca946ba4a353e693d0ecb8 -size 45468 +oid sha256:a91738f516c04ee2ce383535e14084977dad3ad75adc2099614b53b107309e41 +size 45423 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png index 893d7a086f..2b3134576a 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e335a7132330e2c5dfb3f4cc015e25fdf67af2030474b347df2e0cca343b1c74 -size 27763 +oid sha256:3084be95d6aef18c27e62c21b2d2bbf3eddf305ebcb07bd42b9d26e0d019b527 +size 27683 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_2_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_2_de.png index 7a2abd7f42..4d8a4b92a2 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_2_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:645d02f8d4503edfc2e5fb756050ed1ddb8a692d715d06b84b232e744379d613 -size 38820 +oid sha256:8ac9746cb6f4154eb1d9ca97d5d4ee6cc301ef1a0754614872af4be1c5d69deb +size 38865 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_3_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_3_de.png index 3b526c2fc1..597f641b83 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_3_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4df58e4d7f0baeb0bfd0225302ed8e69eba1edc0ef37ae6cb8b86ffdd057b924 -size 28414 +oid sha256:ac67f10c25ad4f4873dab015f494cd9d34b880bcc5e846f90b963a052c6e31f3 +size 28677 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_4_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_4_de.png index 57bed01c00..44db3098af 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_4_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a24be625e8a7d6eeb46f0066247bc22bd367b0e035802b54a663478392f4289 -size 29980 +oid sha256:9453ad930d644293a3437cdb5a169e901ced8f9b86e8c41154f9871484ac5085 +size 30028 diff --git a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_5_de.png b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_5_de.png index 4537f0ff7f..928a53ba64 100644 --- a/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_5_de.png +++ b/screenshots/de/features.preferences.impl.root_PreferencesRootViewLight_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7a69722f7e5f6373a266116e7d97bef5e620b136deb2cea30409c41ec8d4180 -size 21310 +oid sha256:8cbbde65a12a8618dc211b8a33e876d757ea0571ce69de6156e5f2f32a59e0e7 +size 21337 diff --git a/screenshots/de/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_de.png b/screenshots/de/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_de.png index 4e69e6226c..92e0cba9ae 100644 --- a/screenshots/de/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_de.png +++ b/screenshots/de/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b601bd80631b10503580d5dded81cc29647bc02da02576cb420921aea3177dd2 -size 20136 +oid sha256:84dbbb41148ae5962843a1ef337ecaa0b8d5fed1f1b0c40fe9e7b1b12af80afa +size 20076 diff --git a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_0_de.png b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_0_de.png index 42885de40c..416a90558c 100644 --- a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_0_de.png +++ b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f935cbeb516a345549877793ed1e0e5d82b0b1b81b65d54f028d8ee30a3eeb7c -size 50075 +oid sha256:4d747bd7c8ff2fe4ddbfbaf7dc58adbda51b6eeb790cf9b9886a695bacc598e5 +size 55304 diff --git a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_1_de.png b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_1_de.png index afb28a7513..402f60a833 100644 --- a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_1_de.png +++ b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54c0d5db8026616d766d1ceb94fbac1c3588be1ac3baa38e05ef4f665aa9419f -size 115721 +oid sha256:9aa99577ce3172b8c8067efa3494c541a409c6e3d021b84209ae77f192cac31f +size 115625 diff --git a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_2_de.png b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_2_de.png index 4b03d29ff9..3e53f7bbba 100644 --- a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_2_de.png +++ b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8efca7b9be49bd84f809fac58de983e6126714914250ce4b0dcb96a56125bb7 -size 46915 +oid sha256:7e89127359e73a5ae2002906732958f071c989a587a091cead3859378d02aa87 +size 52421 diff --git a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_3_de.png b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_3_de.png index 42885de40c..416a90558c 100644 --- a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_3_de.png +++ b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f935cbeb516a345549877793ed1e0e5d82b0b1b81b65d54f028d8ee30a3eeb7c -size 50075 +oid sha256:4d747bd7c8ff2fe4ddbfbaf7dc58adbda51b6eeb790cf9b9886a695bacc598e5 +size 55304 diff --git a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_4_de.png b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_4_de.png index 473b887d73..70642b4911 100644 --- a/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_4_de.png +++ b/screenshots/de/features.rageshake.impl.bugreport_BugReportViewDay_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a3d7c97667774e00e618be65e63423d9d62c8b30dfe95cddad1d5dc62255e38c -size 39638 +oid sha256:ac3cf799c382dac09ec91c857cfbbf15148863cc66921bee326d76f3700ba168 +size 44154 diff --git a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_de.png b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_de.png index a0f75cd738..cdaffc1a49 100644 --- a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e8caaa7abe0756779ff2fc479a8642a135a697b7081d0765d0ea8b23091bd95 -size 56826 +oid sha256:d03e7f9d66b93e98bd4c76669d42ae28a5b70fc7a675c252b77eca422b8afa4f +size 56809 diff --git a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_de.png b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_de.png index 3497888ca6..900983a6d9 100644 --- a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57cde12fdeba9556f2060e220703f7505d2e23d02215cf1fc5a92eaba24b0628 -size 55135 +oid sha256:d24e1c49ba19e2d095b2bd4dfd4999a36620bf881520249a5db5c76c4753fb94 +size 55180 diff --git a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_de.png b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_de.png index a66b84a19d..0a1c88d294 100644 --- a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:beff4f5e0fb5d44354cc8e3804d86213d3a21bf4d689f2363960cd7e22fee44f -size 56667 +oid sha256:ce1b25f6e6dab11a22e038c2e1561d88c09f75a4d961a279bf485163015adaaa +size 56651 diff --git a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_de.png b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_de.png index a575cd3638..d7687aa81f 100644 --- a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45934c98831269dd7eb1b798647cb145faf5590b3740936146c1cd513cf6e907 -size 50243 +oid sha256:68f712db6d7db3c628acfec73233f2bd9704b86aa0993787e941ef5d5b1e2cae +size 50354 diff --git a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_de.png b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_de.png index d3003c3e88..784bb3cbcc 100644 --- a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c9859b4d53d54adb5dd12213bef1b6a50d4e0862ce5c0deda752a5779b18b6c -size 47676 +oid sha256:d56ec5babe852f439f172f8548d4cb03b3fa60b0e5ea21e9afd5fb6abb38b0e8 +size 47972 diff --git a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_de.png b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_de.png index 892907a12a..2e8b0be837 100644 --- a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ceb9e1948ff34962548c21adf3892715cedaf50d3bbafc2dc9015a9e96331d7 -size 56658 +oid sha256:a24f3c88154b22392a93e7ee473e5f3e55dd501e328179477bf4e3e4026f6b47 +size 56934 diff --git a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_de.png b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_de.png index 256d632422..05574dec84 100644 --- a/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8312152f57b9d6a37ab33f426d1881a5c1e36c4457a89e4b4f06c5b1105d8cc3 -size 58109 +oid sha256:8248854c81134542e7ba7d34882fb0bc9728b10d8872e86cc0ac6599a04fba97 +size 57987 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_de.png index 0c347055ba..328b85823d 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96cecbe1b351347b6eff86293a80ffbf143600fcbe3ed238c61b2347b8879411 -size 52376 +oid sha256:817b59bc4317f89f141e341b1c866ab195f34b1120f69c85804cef1b18b178ea +size 52296 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_de.png index 18794908b1..044814a52c 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:745935d5abff334391b1e588178e1c1b14a3ee0572c0ac1124958834929363ae -size 54870 +oid sha256:ec2116368a69a68c118470138f97f9be4995b5d7b2b58dc85bc70ff48c879b82 +size 54846 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_de.png index 93afdaa467..75f5513426 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ba2a125fe3a0d178de0b10794fa36183aeba355281919b453d7d66626abc6d8 -size 54882 +oid sha256:1745e6ef8dcf256f34c0ad441c5fc6a1732bd792a3341293a1124985c8ca358a +size 54858 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_de.png index 2092f34632..a3b8460ded 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97be53a837124736da9064a51783a8a39f793460b520b6fac35fb05cf7571b4d -size 65428 +oid sha256:ecfec111e21ba2c98edc3746bf844490fc7c64fd3b39a3ec176c42095aee4bdc +size 65643 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_de.png index 7a05054cd0..30fdcb59a6 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b021c5c11bd6bfe0527db0ec4d1c387245af705775317f423026f59afb7104fc -size 71218 +oid sha256:61e5c4c759fe08c919a2de146b39ca5762281197c06d1d1ba8b2e0db45fb2a64 +size 70562 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_de.png index d745128db1..25117e4af3 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cdcb5fb7c63dfed91d7b1319ab7ae9ded40d3f7a4aae9b9e49e22c7fc2b6b127 -size 64824 +oid sha256:8472cbf44919672c8406bca52f9a2256e2414a2e827b3b167b03222558631fe7 +size 64700 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_de.png index 6c38c5cce3..e41cf2a965 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f0ef695696bbe691990ded32cd6009c42b189afe437218155c09a2135e25dacd -size 64652 +oid sha256:4237263a8d328c51203cabcc3714f88799ba219979294d01b2bfd45b5fc127f6 +size 64527 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_de.png index 426f20e7c1..17e65d6333 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:068211f1259ed0d3ae2dee3db6c399baa2d94bb7a5a53fddacfc8efd87988d05 -size 58601 +oid sha256:9ef732aee7d4a81cd4e50d8eb006f98a56e7cb1e11f6eb8a35ead4f6a5cc01cb +size 58443 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_de.png index 1d339102fb..b0df582d6f 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cbf48859a2a9443f5ff5cf061a0c68f8b9e9d9e27626faf439f0b7005537345a -size 61178 +oid sha256:6b5badeee7216296f286422014e6b84c5acb6473d21390312f029ff8b666e0a8 +size 61192 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_de.png index a54355414a..0422f0c5e8 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:761687db6cf908b4dd8d4fda6db683a864d61abbe91f64c2ab87369ce5f2ec97 -size 65487 +oid sha256:772e74f99812853139c120b28ce56cfffa5d22f25b3e9f6fea7e229766574b06 +size 65428 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_de.png index 89e5409ee4..fedf2b87e4 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db7912e6566d4eabfc8673f0d2f7c5340259b26ed4ea3cfacc76f21dfa7552a1 -size 55075 +oid sha256:a8201fa17fa46021b640a2792ffab61189036288112076d58fa17a596bbfbf66 +size 55001 diff --git a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_de.png b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_de.png index 6c38c5cce3..e41cf2a965 100644 --- a/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f0ef695696bbe691990ded32cd6009c42b189afe437218155c09a2135e25dacd -size 64652 +oid sha256:4237263a8d328c51203cabcc3714f88799ba219979294d01b2bfd45b5fc127f6 +size 64527 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_de.png index 9359c3833b..be4e082882 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1942a4d7fd419e1703f7050bea511b57fb11799f83dc023b0ba31151c4ebb7c -size 31670 +oid sha256:699a1cf4c54ab25a11dd198316403879870759c1972a98919da02cd2a982b2bb +size 31597 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_de.png index 07ad48c32d..185799c671 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:552ee8af61138f3bea47fd478be899418d55b3477a179e17f278393e244cccd4 -size 33767 +oid sha256:865f1e58cfcbf1de8efde943e16a4a3f7b8f800d013432c61fc63f17f4fb2da8 +size 33682 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_de.png index 4a3fc2a3ad..e2e4faccd3 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd8aea477b02dec08fcbc09e10849a3786b0cd6d16f725e562b94dfbce04245c -size 30137 +oid sha256:b196ba5482799666ee1bd9000de4c40895f7405cea38f9018eb45da3afc4c455 +size 30363 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_de.png index b271b405f7..a15d3951ed 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c740bbb8e53f1df984a46c86f468f42632ae55659fdd0fcbb19dbc6caf1de5b -size 28490 +oid sha256:fb7aa2178a4aaac88562276bb85879ac05bf57321460102c7b4598d69ed6388c +size 28540 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_de.png index 29aaf37520..4d2146e323 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:18c6aa596af711ce96e196f63cd2b9d10a7e5edfeb37a74c6e70202a5692a162 -size 43002 +oid sha256:39d9e350f2fff99f89123c5899230d29fdfee85208bd611c5fc313a5d1c69098 +size 43051 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_de.png index 4a3fc2a3ad..e2e4faccd3 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd8aea477b02dec08fcbc09e10849a3786b0cd6d16f725e562b94dfbce04245c -size 30137 +oid sha256:b196ba5482799666ee1bd9000de4c40895f7405cea38f9018eb45da3afc4c455 +size 30363 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_de.png index aef5118d3d..9a8abbfd94 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d008b8e9bf69f7b98b03189bdc3557cef24b2a0f5c8a4ef3ee964d08537ba974 -size 27959 +oid sha256:7d3c850336f4ffd9bd3e9f7da36e1b6ce85d5a308687a66623a3be79569ce45c +size 28009 diff --git a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_de.png b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_de.png index 17fc76ae48..cc535a7d40 100644 --- a/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_de.png +++ b/screenshots/de/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e4e9e8fa10f638c2b68b67d3598522bb1689873cf93fbc388fedef3d05ad4b3d -size 29801 +oid sha256:c28d3688d90167323b819b20ccdf27a1049f51750b66cfad162baa974e0c591e +size 29710 diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_de.png index db3bddd540..36dbf6b80a 100644 --- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_de.png +++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dbfbce290df1e1d1dedf38e7e642fceb44e00837413de97bf454df71c9459e9 -size 47635 +oid sha256:e46f6eeaabf4f20e9baac0c7c9468548c3368ffdac418eab9ba63710fcf29ab0 +size 47203 diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_de.png index d0e56a6e30..96fb67684d 100644 --- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_de.png +++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2711e8dccd0a317264b86c9801dab196381be9c88b12796aa4af43bff93355f2 -size 49346 +oid sha256:a97165e24d2d7e8aa3f66e63a21a510c87b6b530484779b58de684b62fc3417d +size 49588 diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_de.png index ec9d76a63c..1345662657 100644 --- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_de.png +++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9481de4eeacf6b7a067450ba5e6dbb6b3e05e1f1b561ce71e7873fb0efe6ca04 -size 40534 +oid sha256:b013298feee179a8533e62c9c8f526dee39cee0f523310fc69d134ee83ed2be0 +size 40249 diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png index 49af1493fa..d7b3e00503 100644 --- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png +++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf1854518f5e3e3fb4c8e439d927a3f7d2f0617d22f2e684c09240920ef5e64f -size 42350 +oid sha256:8bbf2ca23feca4f9fd0d4ab60a58ff53bea0bc6328bdf520d7e637f6fa411ebd +size 42411 diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_de.png index ec9d76a63c..1345662657 100644 --- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_de.png +++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9481de4eeacf6b7a067450ba5e6dbb6b3e05e1f1b561ce71e7873fb0efe6ca04 -size 40534 +oid sha256:b013298feee179a8533e62c9c8f526dee39cee0f523310fc69d134ee83ed2be0 +size 40249 diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png index 49af1493fa..d7b3e00503 100644 --- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png +++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf1854518f5e3e3fb4c8e439d927a3f7d2f0617d22f2e684c09240920ef5e64f -size 42350 +oid sha256:8bbf2ca23feca4f9fd0d4ab60a58ff53bea0bc6328bdf520d7e637f6fa411ebd +size 42411 diff --git a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_de.png b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_de.png index db3bddd540..36dbf6b80a 100644 --- a/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_de.png +++ b/screenshots/de/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dbfbce290df1e1d1dedf38e7e642fceb44e00837413de97bf454df71c9459e9 -size 47635 +oid sha256:e46f6eeaabf4f20e9baac0c7c9468548c3368ffdac418eab9ba63710fcf29ab0 +size 47203 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_0_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_0_de.png index 9dfcbcf1f6..de07bf97f9 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_0_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce3c8e771e43c186cadcf495a7d85d6ad36c089373782c209170282e0e5fb1fb -size 49709 +oid sha256:fbd93cc28496ba6ab5073b8d0a41181dec8fadaca522d2242d35f7795dbcb2dd +size 46008 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_10_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_10_de.png index 26411218a7..467997d3b6 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_10_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db7a53d858a08f1396a9c04b6a253623fa25160f90de62be9dc187f72fccedbd -size 48374 +oid sha256:962b465563feef46eb5200c2ac06183faf62003be30c571f9a38c7b393d9ed51 +size 44089 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_11_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_11_de.png index db935d5dc9..d326ab1ffd 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_11_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38e49c07c2f49bee8ba4d37f684be34ccb247bfecbfea5b1733e76246d160a45 -size 47086 +oid sha256:e80a4e54736d672b29f06e4d41d6c51ded45ebefde349f1ee27944fca0226586 +size 43439 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_12_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_12_de.png index d0343f2f12..916dacb45f 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_12_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f91bfd31c40b1cea5b4dd763dbc92eaaf7335d078ac496b51b05617c01f8b96 -size 48934 +oid sha256:3839b0a82b13e279c90f5a9f6657c37f42e830785a062056c2a2187dff96905f +size 44432 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_13_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_13_de.png index 12ccf2ffc3..caa09c00cb 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_13_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d85a9aa1456dccaef8a7cb2c8b8c756e54c4fe03402d39d1240624d279449c28 -size 48821 +oid sha256:32fbde62b59e63d0ac9ed5f18bd9d90e5cbc49ff15edd73550630e780eef3022 +size 44382 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_14_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_14_de.png index 625ef06b29..222bdbb69b 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_14_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_14_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b65c937240f2a5bee4e4170a511fff5437c5bce47fb987674548487fcf72fd1 -size 49350 +oid sha256:9425cc752cbeb63712a1a4b0ac2da47afb7137d0031e4e86654741c13a26a01f +size 45782 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_15_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_15_de.png index 0ab84d817e..0db1dcb516 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_15_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_15_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f965ec5c45372e04fdcdc1c3c65633551f83e8dede75df8e8c329f849f487bf -size 49885 +oid sha256:242141af976b1ff1e45dc36314b065a3e1e7669aff0a2715ea4f858556dfb706 +size 46146 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_16_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_16_de.png index 4798c4bc07..86317ef16a 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_16_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_16_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b68d23accbe81e6913d16ef6bb15712105422911905f274d66ef656f98d8a28f -size 49201 +oid sha256:81a2d147b0216dfa3f5890fe156b9d5b3286b9eca9a4eda6f411f3973aad5d49 +size 44669 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_17_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_17_de.png index 11a68a7982..de0b76baad 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_17_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_17_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3699ee438dbbd4aa0e5c5cd5a054304888421cb8c8a822dc52cb8369816f7feb -size 48429 +oid sha256:7e199eacdb84d5c47d7c2a60775167c55aa83c3961ff297d0bbcf3575ff09cfe +size 44069 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_18_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_18_de.png index de0323860c..f1252a74c9 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_18_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_18_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3eada7d271b1f649d931e5077fc04e232046fd4171881c673bab8eaf990f92b -size 44452 +oid sha256:4f7e9e7b633ac41323515f71587c046cf3fbc1c41a091f1d48e2ea6a2f09a0ff +size 42864 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_19_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_19_de.png index 65d67f1746..a6096d72ea 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_19_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_19_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:934be11ba08bc83461c1d859b3cf8b6f367feb89f6a779689ece209c30d8eaa8 -size 44441 +oid sha256:9d197a1c9731d9422f514558f97ceb150b7e1ef696910463999b5e8b3df944f8 +size 42856 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_1_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_1_de.png index 637fe31e2f..25729f3411 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_1_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:540a461ec0a84d22269abc644dd62444223818e337edbab2f79317f80cc24696 -size 44107 +oid sha256:09a2ea1dd8fcac508e33dc773cf5bcdb2761d907133f199dbd97a72c6ca7376e +size 40443 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_20_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_20_de.png index bfa129700d..fb904c2bd5 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_20_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_20_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30918ebc116ebf2058aa619debfa9165d5ef95feb916a83e94e49d09377435e8 -size 49193 +oid sha256:920cfd59a2a083ba13af990feb457b70f165ccecdcb0e11c4a9cfb3455d3963b +size 44594 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_21_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_21_de.png index 8a5276b209..b0c47dccd6 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_21_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_21_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5cf3437703035eec0dd9623032bb62f1472b1a5fe996b7b85b9050385eb118ba -size 49109 +oid sha256:afcc12b627f86a179dcbb61417190a1c3e86f990d50fa631be38472b82d38206 +size 44531 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_22_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_22_de.png index a9e5ff3132..7ff5e0c2f6 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_22_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_22_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:983d019c59d97d4bbe5b42562d6d028bb094a5b405fb2adc033232838952890d -size 48673 +oid sha256:6bfa7e56cac57ed69d6d430075fc35e41c2b80b7a7d5d933370a5368647437f6 +size 44201 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_2_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_2_de.png index 404ba5c5c1..d72ce031a3 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_2_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c79eb29314fbb2378034b03d368d5ca49ae49c6a53387784445a0b97e3cc56e -size 43324 +oid sha256:3cc7e47edd40cab9ed9941705590f0752b20449efc870f86abd43b54bd49dfcb +size 38465 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_3_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_3_de.png index b492032c83..d3a56873a6 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_3_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d605c8379ff6844f7581231574cdfb50e5bce0b2e33c886fd43b520576f9149a -size 45963 +oid sha256:3e11c3a17f4899077f64d7a7a90f993da912e871b4935b5e308dd9e31bac5e4c +size 34408 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_4_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_4_de.png index 09c0f584a7..7afe84322f 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_4_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:355905f6a0fc25abe31db1359f24af1acb60bb3a013e697663c3ee9f87a9be52 -size 47386 +oid sha256:7a4e837ebfec6f590aacfafd7589524e7d15c970efdbd29a2b7c0e82ce81867a +size 43229 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_5_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_5_de.png index 0fd7d3e667..0574322da7 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_5_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a378c9b3a9bde80050444029ec6eaaaf76a5182c45babc898dbea24207466a32 -size 44054 +oid sha256:76c41c7b34d99e430c4cf5b7e76bcce3c63a59d1e346bf43ef8ae51f94efcfcb +size 42571 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_6_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_6_de.png index 6392ad39ea..7e7f454647 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_6_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:737de18454bbb78bd9ca789ba1ab821f203c54d55301a5851ae01e336cc42260 -size 45324 +oid sha256:e33775515ae038a38c2c0777ab6a30b38b17cfbb9211008bf6d84f7f75da4549 +size 34952 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_7_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_7_de.png index 425e08b224..9c036da39d 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_7_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2ce5bb8422a493541b30fe3eb95f756367358e039b759967e1f4d96f7cf337a -size 49729 +oid sha256:1ade79185899845159fceff103119f0c811453645b63336a0315815079d116ed +size 45062 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_8_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_8_de.png index 6be8a7cc91..1f2b90d768 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_8_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4fd1c7495908336646a05655f1c4c2d2ea0ece1e690f69164cc2946273a077c -size 49038 +oid sha256:df94c2469a79844306bde7021d072eee808be975e7cf9ab95d66d5278130681f +size 44585 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_9_de.png b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_9_de.png index 8927152505..beeb0f0754 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetailsDark_9_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetailsDark_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12d25ae598f1a05aa86f0125b6acbaa4137becc2900a2ac649880c521ba2ef52 -size 48034 +oid sha256:f41518b33e2bac87a66d68b7a8ec1ef03d75282b191e81a89c6fb3a95534c5b6 +size 43435 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_0_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_0_de.png index 86a072cb2b..f6bd795833 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_0_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7382605cb34650919a0b9f1d1e9460e28ce963dc4ff899fc6906dfcdd73dda50 -size 50783 +oid sha256:27c4a30fedcbdd2f87adbde9cbae6811d44e1717263afef69d94f30c62220d43 +size 47690 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_10_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_10_de.png index b3d5dd204c..f925db69d4 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_10_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6f057a687620b49fde08e0c241aadca011d87154e73b7cbaf21a22896de07c9 -size 49348 +oid sha256:1a2660554dd6866800fcf5c4cb0db71c5352ebfc8bdf8f578fbed919f1a8ea35 +size 45591 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_11_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_11_de.png index abf7a28899..8ad1f37884 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_11_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a08b46085a213f7c6a93f24c2afc04cab4a0c30369d6eaf552cc6e58f50aea34 -size 48160 +oid sha256:07f570ce47d91018e4c5bac7b97f02808d6f04dd45c75ecaa598f5fa015b961f +size 45030 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_12_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_12_de.png index 257169012b..262fea0568 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_12_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e624adcc59354fc21c960547d0766929b95e1a2745b667eb57dd5e62d3ca8451 -size 49914 +oid sha256:8d83c1ad4304b03c83d355637d274ed5d7afed687d71b4584f996ba40cc8b36d +size 45999 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_13_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_13_de.png index 3804c84919..1d9b3083d3 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_13_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60cc99a113658fc4222b68b4801066c112d02dbd5c5b39e12471f77bb71ab348 -size 49807 +oid sha256:0afc00ea3c7c01ca8d569207c67fc1e638089e02f86a799d884203743383e7fc +size 45930 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_14_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_14_de.png index 080e2d2199..d40ba234d2 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_14_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_14_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd16c5e9846823589ad5b22568c25b0cf3335cba8b467ceb3c9186e5b84e7fc7 -size 50318 +oid sha256:5d3c930789935491a5941dd049bf534c13eda091a3334490a930c32b7746891c +size 47431 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_15_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_15_de.png index f80834a2e0..c54012fde6 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_15_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_15_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d3dbdcfe1dedaabb5d03dbdcc2a2f377fb6d1aafccd6b70cb147a97bf23b1c5 -size 50929 +oid sha256:d522792c4dccd88c57877fb1889f79e6bdee9dd46b0a69c630b4ee4c44d080fd +size 47870 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_16_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_16_de.png index b43767563e..e7b5b4dcda 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_16_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_16_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0761670005dd4463b662efb563a5270f89790470017d42001d00ce44e96f045c -size 50201 +oid sha256:7c07ddb2e3c67d14161cdb50c1aeb843ed2d809c2ede25781120212c9ea8db1b +size 46245 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_17_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_17_de.png index 3c0a33e5fc..236f7b9264 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_17_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_17_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6361321527d1bfa1ea84b361dec64c3746a85079a4048666e4016f52d3d34246 -size 49681 +oid sha256:6f5adab2c88707d8cfdf02afed207ed1c9dae6e079c56dafded849e69d7251ff +size 45775 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_18_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_18_de.png index c3b0b28c5d..e63f91816b 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_18_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_18_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5bbd36791567c89996dcd755b3ff4f956f69f1ff3f6f66595f16e1e733fe0a7 -size 45751 +oid sha256:13de8e3d3e4fe65ded75c0bf83d35ba3d6e3fb399f6e44cf5c0dfb22a0760c8d +size 44605 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_19_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_19_de.png index 7dc11fb06d..45f99a6437 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_19_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_19_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3bf0969b8a24c8d06fb3253646d6e2d0a94572cc346a8a9f9522ae48e5b4217a -size 45686 +oid sha256:d7c01f6c32eb80dd6bf9b155a4a502c4fc547b75da8b4fb35fb9fdf79a74660f +size 44557 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_1_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_1_de.png index 4fb1d5bebc..7ea3b25be1 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_1_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cfbd204c871feea36d0ac5ec740049488a9d3511156cf7a3e30d724d62fbdae -size 45187 +oid sha256:de5b2d0455df42d3c78ddb53af7026302bb5685cdedc95833792e056afd64a35 +size 41836 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_20_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_20_de.png index 96b2a06800..1cfd57e644 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_20_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_20_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84af752733042d4d487a934144525bbcf31cf9c1cb1454a5561ea9b3bf794afd -size 50205 +oid sha256:ff079ace53452fdee5aa1e6bc891a20155363f9ad222a88850a940c73d4128de +size 46222 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_21_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_21_de.png index 3576b6b30c..297290822b 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_21_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_21_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a5c142c8539e0a7d40f4455e96d3d5fe1003f2cef84095709f15fd63b945a06 -size 50130 +oid sha256:4aa47c73d51ec8e922cf57d70dff2ba980e2a7f7bc8a9ac879cf82c558464884 +size 46114 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_22_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_22_de.png index 6905512be4..82265039d2 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_22_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_22_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:375274f827cb0b1a56461a95ebbbc12ab8dead23a41059b0909d87892b5b7f74 -size 49645 +oid sha256:b5b6a74f88e2237029aefa7958f053e8a417ce151ae15be6c9b2a23bc7cbccf0 +size 45711 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_2_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_2_de.png index 23620c662b..fdd2a706e2 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_2_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9737debc2f342c5ce2b20f48151597e164526297d2789b04bfda74e4cc70153c -size 44357 +oid sha256:f1fba8dc7f4a0aefd8a31497e503c965e944563974020549f2410d4d417e0144 +size 39952 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_3_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_3_de.png index aca9ef2193..ccf2aaa37e 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_3_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d16e1a72ac9f47e0236b5ce3bf82c7e8d0d3ca0b245aba5fc751a0b9bed6cae -size 46946 +oid sha256:3afc35e14b7f3b1ff3af6661b38e6bee333f10dec623f34814e114a28a1fa61c +size 35556 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_4_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_4_de.png index ab1ea77140..6db4c29c9e 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_4_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e483482b88e7edc6724459da394f87a587ada9ddefea5d05d9bdcfe57e34ec47 -size 48423 +oid sha256:07a8fcf6977221be7d9bda3dcc23cb3d3d22f0e46a36b282473d08d0dbfed29b +size 44735 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_5_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_5_de.png index bd270b4ed0..0360351793 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_5_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c8130c023137a1c3872202df289f364a3cc85217c7b0d7d36609d1fe896e96c -size 45304 +oid sha256:be92b2bdb3d9e5778c3853391213d7f6656c06f158fd1835b8cb59fba7721bad +size 44263 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_6_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_6_de.png index 26e23487c0..60b772f6fb 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_6_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c67de39146bb8c0049de90223d4a7293e3f42ab8f3780cc0980e62c97d10760 -size 46651 +oid sha256:b2cc88fed3c7e90fd974d6d0bf047cf4cb6b16dd9697f2042d75973c5da53785 +size 36515 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_7_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_7_de.png index 2001c831b0..c8899b5e0a 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_7_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69695044a9afdc82d1a65e0911effcbb660dd550c31d5b8ae1f6a0f674dacd30 -size 50843 +oid sha256:6e1f82c49cb2852e455f081a1e3feeb4d89bc3066e60baffa404a0126da3db35 +size 46732 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_8_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_8_de.png index bbec3a797e..84c108ea47 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_8_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:acbbccc700060f3511bdc2a44661ecd1442bb8db107c52d8a3ea93085e3cc370 -size 50181 +oid sha256:267aa0d69468e5d413fa1484dd836c438d52841ec66ba47cc292c5fcbf119beb +size 46238 diff --git a/screenshots/de/features.roomdetails.impl_RoomDetails_9_de.png b/screenshots/de/features.roomdetails.impl_RoomDetails_9_de.png index f1098ffed9..7f0b76d09e 100644 --- a/screenshots/de/features.roomdetails.impl_RoomDetails_9_de.png +++ b/screenshots/de/features.roomdetails.impl_RoomDetails_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:891f50447359e8697ca26ac27179fb1687851c24156d36006764c874592c7584 -size 49072 +oid sha256:683a93dd5a05a3c51fc9644a0779996ff63c67b33c23df919fb142020b2f519d +size 44864 diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_de.png index 5781478873..7fbe8f888d 100644 --- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_de.png +++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a78ad12392ea4d4e9e54ffbc786a6e3eec73294e088f5403db88af5269a6b003 -size 18523 +oid sha256:0578d53cd64a18056d550c9b0b8bdfbf510392b1898718efc6e753d251c21a2b +size 18557 diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_de.png index 819491fece..f45704af84 100644 --- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_de.png +++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dc117e18612891f202c6bc093e4a2063632ee974939606af6eb09ee36deba9e -size 22172 +oid sha256:0f63174a49edc5ce7f1e7d13253c1fc8449dfd3d3029a240d6d47ded6b7b20fb +size 22233 diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_de.png index ad63075b13..4fbd71efb8 100644 --- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_de.png +++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc3534d406c3ef468e9af1b86d8d09998fd173aa1f63627412053f4e4d76bbcd -size 27625 +oid sha256:bc661e4e10991f3810a28a69381036a8445fd44aeb27614a6ae59668c8ddcddf +size 27638 diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_de.png index d5df6b6df0..8c6d78c1d4 100644 --- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_de.png +++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1d10f6ddd38cffdf7f8ba188790f6115b18b95de401ce08ba4530f249f99410 -size 28109 +oid sha256:7c34192c1c65387e5772a9763cab97c12fffdbbc148c0d08343c211a3b8eafcb +size 28105 diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png index 6d6878395b..5d00c96c9b 100644 --- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png +++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0666fc8348e5f33b265d2345973aa529ca12e464535331c71244cf3a17c94cf -size 33570 +oid sha256:b3face6ab5952fafe521e1df418eb1ea14746107b78c993c992f188f4f0b5ee6 +size 33690 diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png index 56c4a02de7..f23adb562c 100644 --- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png +++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24bc5b3a5be02a4dabe2a4c1a773206dc7f991ea99e6b5d2c1b8e99f69055611 -size 31547 +oid sha256:290e8fd9f8b7ee1532d050dbfb0c888870c12f88e9c8c60a3de54b1caad3e453 +size 31655 diff --git a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_de.png b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_de.png index 7cc591adbc..c9f77b1c8c 100644 --- a/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_de.png +++ b/screenshots/de/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5cedc1ead4632facdffa78ae83a0636d08e92013184587f346d13cbc4f98fd29 -size 35997 +oid sha256:19fe1682689050cce7831aa90f339175248ba578ac68fc7e1913b3eebece61f8 +size 36059 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png index 5db03f0da8..f437eb6ae7 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3644179c35846aec7a93ee45a6e0ee14ec1ca7795ca270a26cddc7c9813cedd3 -size 40448 +oid sha256:f9a36e73dae1d3829c3575f0490df31c502e9535faefba3c0f1f9d0ce71a3d22 +size 40449 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png index 5db03f0da8..f437eb6ae7 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3644179c35846aec7a93ee45a6e0ee14ec1ca7795ca270a26cddc7c9813cedd3 -size 40448 +oid sha256:f9a36e73dae1d3829c3575f0490df31c502e9535faefba3c0f1f9d0ce71a3d22 +size 40449 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png index 391331f263..8ac3eaa191 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b9d3c8cdbd10537eba77829cd3c91f18e6637ae1d02fcbc242cc26e860e226 -size 41319 +oid sha256:1851a2e559c42ec1508e3020d1b56c467b3098eeac4e47d22daae3591a711fff +size 41332 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png index 391331f263..8ac3eaa191 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_12_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b9d3c8cdbd10537eba77829cd3c91f18e6637ae1d02fcbc242cc26e860e226 -size 41319 +oid sha256:1851a2e559c42ec1508e3020d1b56c467b3098eeac4e47d22daae3591a711fff +size 41332 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png index 122e462156..71b79e0b69 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_13_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4978ac3b31f5f03fc81846e64c183a857d1f468bc1dc2816b123b92e5b2a1824 -size 67792 +oid sha256:af8b41d7e76c06bce4ad9420c6f2876ed61fc3e4d558e3b3e089f3ca5603b459 +size 67837 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png index 6d0b15b0f1..fb8b09020a 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_14_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:552461f34b6873315ec01cc013fbc3ef4a0796c9bfa0bfd445ef94e7db2d3317 -size 73308 +oid sha256:923386ffe1a9737066c590a1d666439942cdc4177831a22e615633334503811d +size 73363 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png index 6e24f8a5ad..804b76f295 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_15_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2f75acc56ee1d7e6d0381db66cc8771f787e37c51171d1d0e478045759a8997 -size 54450 +oid sha256:80c069fb357ca634c17251356dfed57884f7b50490a027d6f6254fb1c5b68330 +size 54504 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png index 822271d7a7..7b474bc71d 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_16_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1c9d7db00eb7b3eb03328c7e885e8ed608e8747851e3beab4c9f2d9613fb1b3 -size 65694 +oid sha256:dd3eee57a5934460aa6cb061a32bda34b96146b230e874122e17e473e6a49ebc +size 65886 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png index f0e0b4d14e..acc9ca2eae 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_17_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:23ded671d28f0bf1f6f857575603e4f4a63e666ce184aa1cb24d09e868f98bef -size 51149 +oid sha256:d00a9f39c51db7e3bcb3230b29d6b4b86cd2c538057f4a2d471e463eae7ecd8a +size 51204 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png index 391331f263..8ac3eaa191 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b9d3c8cdbd10537eba77829cd3c91f18e6637ae1d02fcbc242cc26e860e226 -size 41319 +oid sha256:1851a2e559c42ec1508e3020d1b56c467b3098eeac4e47d22daae3591a711fff +size 41332 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png index 75a0e8a25a..5b59fc55b3 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9acf83c1389f316025d5aa95fe3ba43dc871df0cf01cdf364a228090c2873ff0 -size 41709 +oid sha256:e4538e4994ff46b67cfc376469f152b2c8725131ba555328c8fd2b8233018fbc +size 41721 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png index 08ee8d01ed..6c964087de 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17cc8bd2c275abd9f02a6ec753c05e8af0426c3831ed51d1caa3e3b034ec48eb +oid sha256:4b9bab52cbb4226177052e55217ba518706af204f4550ae9d1986d05d0cc401b size 42318 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png index 5db03f0da8..f437eb6ae7 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3644179c35846aec7a93ee45a6e0ee14ec1ca7795ca270a26cddc7c9813cedd3 -size 40448 +oid sha256:f9a36e73dae1d3829c3575f0490df31c502e9535faefba3c0f1f9d0ce71a3d22 +size 40449 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png index 391331f263..8ac3eaa191 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b9d3c8cdbd10537eba77829cd3c91f18e6637ae1d02fcbc242cc26e860e226 -size 41319 +oid sha256:1851a2e559c42ec1508e3020d1b56c467b3098eeac4e47d22daae3591a711fff +size 41332 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png index efef76cdd6..ef70e07494 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e39e5084b58380e734fa88b624e4715489bf01411997a35f4eebcfffa11edb1 -size 39552 +oid sha256:f8a1e425850742521751919d5f0df63f27035c9a7d7bf7d442cda12dcfe451f7 +size 39619 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png index 391331f263..8ac3eaa191 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b9d3c8cdbd10537eba77829cd3c91f18e6637ae1d02fcbc242cc26e860e226 -size 41319 +oid sha256:1851a2e559c42ec1508e3020d1b56c467b3098eeac4e47d22daae3591a711fff +size 41332 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png index 391331f263..8ac3eaa191 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b9d3c8cdbd10537eba77829cd3c91f18e6637ae1d02fcbc242cc26e860e226 -size 41319 +oid sha256:1851a2e559c42ec1508e3020d1b56c467b3098eeac4e47d22daae3591a711fff +size 41332 diff --git a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png index 391331f263..8ac3eaa191 100644 --- a/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png +++ b/screenshots/de/features.securebackup.impl.root_SecureBackupRootView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b9d3c8cdbd10537eba77829cd3c91f18e6637ae1d02fcbc242cc26e860e226 -size 41319 +oid sha256:1851a2e559c42ec1508e3020d1b56c467b3098eeac4e47d22daae3591a711fff +size 41332 diff --git a/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_0_de.png b/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_0_de.png index 51aae98e87..1ffc68233a 100644 --- a/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_0_de.png +++ b/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f227026b935e504faee7bc02ec3c6d15fb6527fba2fb45f487f828bf70493d8 -size 43527 +oid sha256:a6b99e3e1da0674aa6aaac2133cd473ed3b8db9b6ba69bff1e64956d83d68515 +size 43418 diff --git a/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_4_de.png b/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_4_de.png index 9594f63be7..0b0daa881e 100644 --- a/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_4_de.png +++ b/screenshots/de/features.space.impl.addroom_AddRoomToSpaceView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:650f369a7dd427fbd039dfbb0c396514947fd393b81dc39e1f336a7d4c2a0579 -size 47729 +oid sha256:ea62f1044cc3b7ceaef32b5ffec837437f1275e65a3823147427286b3728cdeb +size 47776 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_0_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_0_de.png index df387ee482..6fdf9dde5b 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_0_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8ec051c3ff5258f937b80e879d5120cff573558418e022df0604c85ea0d20af -size 50027 +oid sha256:8321ad726880f5dc67bc29d68d24b5e8c868f868ef603d39718a0345571db485 +size 50014 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_1_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_1_de.png index c3ddaacb75..5750b88b53 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_1_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e253dbf67edbe2047726be540ca8dd96a92623fe786f4c642ce369779b2a20ea -size 51127 +oid sha256:75e6e31a59cef9f8629a6e04af3cbe605ae55390bf9c257f03ec22392c92425a +size 51075 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_2_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_2_de.png index 03e3a3e58e..e401943ba4 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_2_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a11958a3fb1af0e4ab037fc47aca888d9d14fc6fa692a8409766071629e55631 -size 52246 +oid sha256:f182c31190dbad4f38d2ceafcf57b55c5c588502962cd8a33ec3e24256fbfadb +size 52230 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_3_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_3_de.png index aa75305737..78c6aaa1e3 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_3_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70972a7bcb6546370e820cd8e6dd56f27d8ebc42974d041fa4d028520ee1407d -size 61119 +oid sha256:c8755ce084a21ffc75645ae66e3b2ad1f4bd2c162a5fa8998a7afb6da59a1c04 +size 60608 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_4_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_4_de.png index 1fe2580582..389fe3f63b 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_4_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e59fa963aa02f2b621c9dacb4dfab56dcca4fde294d1cfecb31c83496dc6448e -size 61761 +oid sha256:401fb9c009d48f287c649f768679d744a239cfa29f5c7dc189721a92db6c1b7a +size 61224 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_5_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_5_de.png index 50e51d4b3b..3185b50681 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_5_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc94524eb19fe2878558d3cef5da93247f83373b62175115f7d6ede815b2a404 -size 57045 +oid sha256:6aae5a7b6a524f389f3323fcac496efe946c6282254b941513a0bcec5493cf25 +size 56971 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_6_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_6_de.png index bbc9cdc6eb..860f86bacc 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_6_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:16b7d04c97f37253169364cb66712c70cab46548833b9a4249cfa8e3c56747a3 -size 32833 +oid sha256:8145f5bea2f63ac23c0cdf5f1b5275d8c0542670b6926c313cec6419e24995ce +size 32947 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_7_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_7_de.png index 6f1d20b710..31535d21a9 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_7_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:980dbcdfea227a2209e7738d846505f3b08ec3ca1e553f44e1a94cafec1127c5 -size 33461 +oid sha256:df47252dac646104a5e25f1063888786d88548fcca87fb4fb7309642cc088fe7 +size 33581 diff --git a/screenshots/de/features.space.impl.root_SpaceView_Day_8_de.png b/screenshots/de/features.space.impl.root_SpaceView_Day_8_de.png index 744202fb4e..6e6bf0ff61 100644 --- a/screenshots/de/features.space.impl.root_SpaceView_Day_8_de.png +++ b/screenshots/de/features.space.impl.root_SpaceView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4bd5b6d993849919a38fbe546673441e455def888463e9bcc3377404fc9adda -size 52228 +oid sha256:f9441c13f504ac70b19e1646c63a1672fa49bf59ec177675f38db08f34049d56 +size 52208 diff --git a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_0_de.png b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_0_de.png index 1d4e73cad0..e77553c02d 100644 --- a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_0_de.png +++ b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c199ffcaeeeca1bf620d301dfb41e33cc024495d9fac98d03fbb9d21eea3f3dc -size 23553 +oid sha256:867cddfa670bb04a5db6928710d438befa512a26c4cd2d3d71744fc8a6b629e6 +size 23576 diff --git a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_1_de.png b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_1_de.png index 2f509e46a7..160e7704ec 100644 --- a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_1_de.png +++ b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9b6545ea37304c28bc34236d0a0cb7b3abb82aafe4a08bc8fe88d16497019d4 -size 20055 +oid sha256:86b689b81d1043afbf10df9a9ed9e181ea97681795ef59397d6106f429f960f7 +size 20071 diff --git a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_2_de.png b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_2_de.png index e880bf7960..899c718a96 100644 --- a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_2_de.png +++ b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e7855002b56830821f23af09cd2140e85ed287e58e03d3d43a917d8157e9e32 -size 28416 +oid sha256:4b6e5a3b33f21c5028c15064c031c05ae0d43da0779ca5f77a73f858e2a76370 +size 28343 diff --git a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_3_de.png b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_3_de.png index 1cc6696667..705098ae3d 100644 --- a/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_3_de.png +++ b/screenshots/de/features.space.impl.settings_SpaceSettingsView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:412b32d3f78e6c8104cbc2c21191c7be9f1403bfcf36aeba19ae2652a5437d6a -size 28715 +oid sha256:71a2130fdf175df319ac8350ab5abb4ab019a9f6d0036c61c1eedd4cbec41e7f +size 28836 diff --git a/screenshots/de/features.startchat.impl.components_SearchMultipleUsersResultItem_de.png b/screenshots/de/features.startchat.impl.components_SearchMultipleUsersResultItem_de.png index e86f031a8e..a79a7476b8 100644 --- a/screenshots/de/features.startchat.impl.components_SearchMultipleUsersResultItem_de.png +++ b/screenshots/de/features.startchat.impl.components_SearchMultipleUsersResultItem_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa263cc9cfb7cc47dacfa4ea65a9f4e8660e1a17df61e357d5cf76928dd89100 -size 90714 +oid sha256:b2fb0b82618f1737d62753c53cb0d8e53f78378fc615350e9a39305af6a5d666 +size 90023 diff --git a/screenshots/de/features.startchat.impl.components_SearchSingleUserResultItem_de.png b/screenshots/de/features.startchat.impl.components_SearchSingleUserResultItem_de.png index 3eff580ee8..200f6a08cc 100644 --- a/screenshots/de/features.startchat.impl.components_SearchSingleUserResultItem_de.png +++ b/screenshots/de/features.startchat.impl.components_SearchSingleUserResultItem_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:caa936c590efb400eec2e3d238bec4e48b81883371057f34badf0abb1644554c -size 49654 +oid sha256:6593037282e1c8fe5714903bae79c0ec1a5abb3ac029605124bd54e5f84faf04 +size 48947 diff --git a/screenshots/de/features.startchat.impl.components_UserListView_Day_9_de.png b/screenshots/de/features.startchat.impl.components_UserListView_Day_9_de.png index a16bd08759..dc9a4453af 100644 --- a/screenshots/de/features.startchat.impl.components_UserListView_Day_9_de.png +++ b/screenshots/de/features.startchat.impl.components_UserListView_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d50d07da749a495a9eb57c29ad4d53286d0262b080aff11b9a9d4fac6d56f61 -size 37642 +oid sha256:0a32ec6615d3673e47eafb02da5d5d5ae58572bff5b627852f022f21533eb1c3 +size 37667 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png index e7254790cf..9f12c8c18d 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7bf1f5e039bdff2ba1da2678d57637564288733b9958042b86867350277ca9f -size 25025 +oid sha256:0c80ae6573c4d41b14827623890cb6b211783c708d7417c3b9f1e1ab29462098 +size 25198 diff --git a/screenshots/de/features.userprofile.shared_UserProfileView_Day_5_de.png b/screenshots/de/features.userprofile.shared_UserProfileView_Day_5_de.png index c7bfa31dae..81b5bb4a95 100644 --- a/screenshots/de/features.userprofile.shared_UserProfileView_Day_5_de.png +++ b/screenshots/de/features.userprofile.shared_UserProfileView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a73316a4090908c2c8db15fa408e132f3fc7308c898311008f59ff62fdb94801 -size 23050 +oid sha256:09404876c06fa55c2e01f48380f7a4767d8c55f0cd46bdec78f4d7687ba8101d +size 23150 diff --git a/screenshots/de/libraries.accountselect.impl_AccountSelectView_Day_1_de.png b/screenshots/de/libraries.accountselect.impl_AccountSelectView_Day_1_de.png index 42d3d9d22f..1d177e34e0 100644 --- a/screenshots/de/libraries.accountselect.impl_AccountSelectView_Day_1_de.png +++ b/screenshots/de/libraries.accountselect.impl_AccountSelectView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:83e0a2711e2a46a879d76a7ae6f13b7d294d0080de40f192d3fbb731f6314549 -size 43057 +oid sha256:f9ad7dc0a69f56e7b71e8b2e17b28f404605325c70405ed3e8846f0baba71037 +size 42320 diff --git a/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_de.png b/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_de.png index 030533ecdc..1b51febed4 100644 --- a/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_de.png +++ b/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7a87b58fe4bc087197b3639fb2e31fd884c45b0fae9dc3e57657fe7d3299360 -size 31013 +oid sha256:913cc4e9cfc3b519dc0b8827a889da93b31b8520edc86f186cd760263cc27538 +size 30995 diff --git a/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_de.png b/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_de.png index ba00c135ae..a50eac7fc1 100644 --- a/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_de.png +++ b/screenshots/de/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77ec7e6ad8dc1a9030d09b259221360ee3cd838e512b93f2ff165ec1eab7ed49 +oid sha256:02d340df0a979691166b315aeb152c0249a90058865824aceeb2165ffd73de2c size 31446 diff --git a/screenshots/de/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_de.png b/screenshots/de/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_de.png new file mode 100644 index 0000000000..83302d6ba4 --- /dev/null +++ b/screenshots/de/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16dee1dfe746cd40dac9fe8f0af3ecb42cd14bab5cc490917b589beed065ed1b +size 14686 diff --git a/screenshots/de/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_de.png b/screenshots/de/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_de.png index 4263d29577..012c3b1574 100644 --- a/screenshots/de/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_de.png +++ b/screenshots/de/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff83b8d841c355dcac18d1ba0c7a66d0927e23be66bfabe8bc791e6f2ff3db22 -size 14008 +oid sha256:fbebdd9012c183c27ed79a3cb1dd5b823f73025756d9875c0c5a7af6f126dfa1 +size 14153 diff --git a/screenshots/de/libraries.matrix.ui.components_CheckableUnresolvedUserRow_de.png b/screenshots/de/libraries.matrix.ui.components_CheckableUnresolvedUserRow_de.png index 5fc8b4a8fe..b016c4441b 100644 --- a/screenshots/de/libraries.matrix.ui.components_CheckableUnresolvedUserRow_de.png +++ b/screenshots/de/libraries.matrix.ui.components_CheckableUnresolvedUserRow_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:81e2d991659061d40047373c3b3aedff5a4bc2b42c2b1355448b73784891b2f5 -size 109822 +oid sha256:aa04bafc9c372c51d65404c7ac1f46f291c2b16dc41ac57ae38984ad3d5e122d +size 108049 diff --git a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_de.png b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_de.png index 5fa5394165..d85fe69c5f 100644 --- a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e2325778fc5bdaa5ffd421f77cb83d1927ad4ad6731337b4878a99d3fbfe8aa -size 46053 +oid sha256:e1cc73791a8414dade986244167c7d88ccd5bb536dc199e0f1e6736084c0bcee +size 46331 diff --git a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_de.png b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_de.png index 5fa5394165..7d8fe0b73d 100644 --- a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e2325778fc5bdaa5ffd421f77cb83d1927ad4ad6731337b4878a99d3fbfe8aa -size 46053 +oid sha256:8c1ff9cf31ea0032caef0627f33bfd9b8ddd58680dffb5e85dfaedc5468cf82a +size 44252 diff --git a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_de.png b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_de.png index 1e6c6d88eb..8505e6b854 100644 --- a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f845e0783b6f09ef7b0472f22465e8e5b086102d711e468f1466df45ff928ed -size 50410 +oid sha256:02c306b493d6c77de9e1e54467561cec9d39012e59a88c02b95efe9071b41061 +size 51630 diff --git a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_de.png b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_de.png index 79f832dcc3..67b61583b1 100644 --- a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2917a353e78569a92d5d276e99ebfce334ad8848d488f58312abb9d7bcf654b -size 33327 +oid sha256:2bc723ee90bcd7038d78ccf738422daca8a0b0d54f9e86512399230912281d9a +size 33332 diff --git a/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_4_de.png b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_4_de.png new file mode 100644 index 0000000000..5fba5a29ce --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_4_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac1909851db8c2ec3cf6e7a4238ba76108860ea72fe4c855e11b7df2358230c8 +size 45708 diff --git a/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_de.png b/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_de.png index 66cbed83df..8928a92111 100644 --- a/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:32cb860aab7664826061dedd491f544975da24fee715b94380e6704b36ffdedb -size 33857 +oid sha256:aa139ab4b3399dcce1147babe4a315a5813aaeaed484796dd372c3281a6240d1 +size 33699 diff --git a/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_de.png b/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_de.png index 1ec5f1ed66..65b515536b 100644 --- a/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0321ed8731d4867c59c482a8e631291537556f6003659b9e0c2aa77d61883a69 -size 45973 +oid sha256:aa0b269eebc66e7eabe746ed5ef0084d3bffad2917b68b923c115bbe8fa27ac2 +size 46267 diff --git a/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_de.png b/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_de.png new file mode 100644 index 0000000000..b45beedb7e --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f0a4907f2ebf197b1cec1715ac6682d21b7b1d0a80eb5d05108f1971b648126f +size 12445 diff --git a/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_de.png b/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_de.png new file mode 100644 index 0000000000..9541983cee --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e0d9c3194ce7ac6096be5007d9e4d3b8e3fc6784c0389b1d14a288b48677304 +size 13776 diff --git a/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_2_de.png b/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_2_de.png new file mode 100644 index 0000000000..d1207e09a2 --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.local.file_MediaFileView_Day_2_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f42dca3f4cdeb760ea11c3edcb8751518e7e42a423ffbafaf12cc97d9cd4861 +size 14965 diff --git a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_de.png b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_de.png index c4822fa433..b81a3c6a5c 100644 --- a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2c35cf93948bbc2c344bc678db1159e77769577054bee9ed168cd07ccea5de2 -size 28202 +oid sha256:73a6a48d04d86e9d5e9e546681863c32f651e6dc9af6d7f042e7e36b7fd98997 +size 28178 diff --git a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_de.png b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_de.png new file mode 100644 index 0000000000..d8118a67f0 --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6298eeaf8442246d35fcca3b9e46755353d12bd9d6bfaa8a1e0447ee5d730e92 +size 198311 diff --git a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_de.png b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_de.png new file mode 100644 index 0000000000..090a403022 --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ef79c13235d94887d873c42faa9b09c901efaeae7602336c81fcf7c62955ea5 +size 198916 diff --git a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_11_de.png b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_11_de.png index 16575bf2f5..e9ea5765e7 100644 --- a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_11_de.png +++ b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5300a530f5afb27d55369a9fec9af46e4ceccfe3ae6926d7bff90a7b8cbaa02d -size 44430 +oid sha256:86eb21eb729bda52ab36c8320e78a1ec8e9732edaf285c1c978614bb74a4537d +size 45015 diff --git a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_6_de.png b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_6_de.png new file mode 100644 index 0000000000..80d843ceda --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_6_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ebf8c21f8967a2bce2ef74ac896497e6732f8bbab5c895bc3d33e760791ea570 +size 126353 diff --git a/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_7_de.png b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_7_de.png new file mode 100644 index 0000000000..fdc521ed19 --- /dev/null +++ b/screenshots/de/libraries.mediaviewer.impl.viewer_MediaViewerView_7_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:783d90aa7ae58d39a2495c7728827f8ac3b91609b36a867a1dc6c49611ba886e +size 126735 diff --git a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_2_de.png b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_2_de.png index 8472e864c5..56e31eaa37 100644 --- a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_2_de.png +++ b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70b539e1b76e95f5995cb46527a54610c9b801e7b5c2685bd8de18cffa636e53 -size 32365 +oid sha256:f7fc9c7fb214f190f701921db8d9aecab6d2e5b33f16b4f181074cf08b02f871 +size 30282 diff --git a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_3_de.png b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_3_de.png index c4244e92a8..724051d10b 100644 --- a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_3_de.png +++ b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b90045bcd7d3521e20a1afb830cab6b8f76b2619a18f72cfcb2cf27ee2c87e99 -size 30436 +oid sha256:1e59b9b27891785f5ae3cca5ffba87f48d7220ca8a6158b704dbe934c4fe570c +size 28373 diff --git a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_4_de.png b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_4_de.png index 318c929115..3331a2941b 100644 --- a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_4_de.png +++ b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a42d28677c2048f08418fc4ad462e8610838824964aa15e96c4c92b34d48d77c -size 34757 +oid sha256:caae8a49c1ab004622594d40af22069fc76df184406e02afb91c5896692f79c5 +size 32519 diff --git a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_5_de.png b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_5_de.png index 84d2ab414d..9781177371 100644 --- a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_5_de.png +++ b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd908dc6c37c3de2cd500251bf72fc45f626e91fa272d5626bce9c5009789a41 -size 30074 +oid sha256:2926289b827b4de6d15430973a2b2da6e22188316a51e0f7f5749f6d267fcec0 +size 27989 diff --git a/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_6_de.png b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_6_de.png new file mode 100644 index 0000000000..8e1faa170c --- /dev/null +++ b/screenshots/de/libraries.roomselect.impl_RoomSelectView_Day_6_de.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1173c3f4034d600041a4a222d52493870805a850748e8e30a9fc2fcdcdd44d23 +size 32165 diff --git a/screenshots/de/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_de.png b/screenshots/de/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_de.png index 13aaccf97d..fec1852b42 100644 --- a/screenshots/de/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9690aaa942b7314d5c0342eb2f50112b3eb27393c47fdff451ff3f7501e96c57 -size 52058 +oid sha256:ffd8d4f4c76df4929ea331802d71c6cc00b844889ae8bd82eb757e5c6add157c +size 51911 diff --git a/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png index 6b9a41d3f7..36dded1577 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerAddCaption_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bed208bbf05ccce0169888e2c0ea44c2cfaafd56fe31af1ed6d0f61ac24dcae -size 57954 +oid sha256:5848b7a8e25540ae61754ab06825ee3a4e03b5714491ca9b52f90b65a9c8223c +size 57420 diff --git a/screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png index 4b54cbd8f1..2788ab858a 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerCaption_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cd33857c5c2c12ff5682c23fc10c351f7cab15631c67a915574c97834f6a4c98 -size 43353 +oid sha256:988e6682f03cdcdf6834add69188e7c7f4b2833680e7808c4a9e3158c80fe0d4 +size 42772 diff --git a/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png index b2657abb78..6ccee24175 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerEditCaption_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2cfa7073fce357505cb0aff9a44fa93d3c1ed36801c866d8c282743dade3bebb -size 55042 +oid sha256:998bfd0f79d61ffaebb77619acc52a6eb20d1afe8e383ade200fb7cb366f3e05 +size 55388 diff --git a/screenshots/de/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_de.png index 7aa4a3b10b..64325c919d 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08e8c143ca1006a997b90d2b91a54c56d7e6d4f75fee8fbab5435772c94c75f2 -size 65057 +oid sha256:e3d694f2381da38dbf032db3fabf889b78a464002b132798554d39d56c908d10 +size 64795 diff --git a/screenshots/de/libraries.textcomposer_TextComposerEdit_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerEdit_Day_0_de.png index 7124c2da84..04a63bfc30 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerEdit_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerEdit_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a92d298fe4665f641db42908bfdd884f6439e6ba49fecb58e3b0d4ffd365f65 -size 51880 +oid sha256:b90c8c258147fa5ba7bb8d6851161248193c6ea6f05209c52ea2fc8bc31f43e1 +size 52050 diff --git a/screenshots/de/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_de.png index 2b6c35435f..857bf537bc 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:311b767a0e3406c6f6e46045b573ccf8033421008c39bc5a95f25d55f92c26d6 -size 63391 +oid sha256:85d0dcc807d02f2f1d6711e0b48694e1c9292b9c5bfd14f361bbdbc0cc982611 +size 63258 diff --git a/screenshots/de/libraries.textcomposer_TextComposerFormatting_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerFormatting_Day_0_de.png index a883181de0..0938ae98ae 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerFormatting_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerFormatting_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e20f3e52edb21bc7ce9ea63724604d59b749b841855a0b1b3a124e262d9fcd50 -size 51125 +oid sha256:1a6f9dc7ca20c6ad863a8cdfb81e16de5d7943e1ccf49fd09173de61eb126a6a +size 50955 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_de.png index b473ee22c8..ac0cc44233 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:221bcb0d8c23c286d330fe945d90cf864a17b8b6b3728e5fad98781353aa6ab4 -size 72954 +oid sha256:7b8cc7c147720a5069b6dc52fd2b73fabc6ceeacb34971b6e4678fe9d3cdee7c +size 73163 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_de.png index b48cc48692..4a128e6519 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17ff7c0207c49e50e950f276d63a58c1837b98048e5300278962fab0dd8d4184 -size 59481 +oid sha256:1107d8275c397858594dae30ab60a2aaf024be42ce95c8622312c5db197fc3cd +size 59585 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_de.png index 7d95518cfd..12d60e3dde 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66f5fc6ad92fd7fea6d2c306cc666a4587cc1cdbc3aa98b45142cdf0c41e897f -size 72530 +oid sha256:a177473a350953b810a905a6d211ee2d25093df0d9f893fac1bd7f8845f180c8 +size 72685 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_de.png index 8f5381f932..539b9b8dd9 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f447bb8d44aa37b72de057afd9990f084efd60a11a2eb780c421a079e443903 -size 81106 +oid sha256:556bbddc7c251aaa5f4ebeba710542461c259623514f41bc2084ee84eb9a44ab +size 81452 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_de.png index e38e38a198..f549e77e82 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0581ab71b5d91f4308fce842d2374168cbfeeb92e60658e4cdbf2e62d54e0eaa -size 62378 +oid sha256:0abc80f87055b2389ef47dfefae1748402f31840c9f6cbe25d35c697ed8bf0e3 +size 62284 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_de.png index c670eff478..0fc2abd4e9 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e181b89dd2bf6ed1872e6a0fca74f7e335fc630015e4073b055da7a51426fd0 -size 61139 +oid sha256:5f87522288622a68d2731dd95fa3bd0f092fffe85b707eec807be215189f5ce0 +size 61184 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_de.png index 58301a23b1..cb2b57781d 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6cb0396eb3ffc95f88272f788542a7a1c6e3f7e63c76beb6bd7eddf46f7dc41e -size 66635 +oid sha256:0d87ab9985d4efa8bd2c430ed81e4650960ddd87a29a65cf015565853223cdde +size 66852 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_de.png index 6c68e65089..e94135d065 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e975a70bcdf6e57b0df77d9e301252a934ed70bd48f0469433434246a668a023 -size 89801 +oid sha256:25b9b92e7dbf734de4e82cf7aa8122f1ead30daac6c21fb1d4fccb6a5ee2ad37 +size 89960 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_de.png index 8588939a09..bfe14559db 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bec919f02167d8c094f84e0fba555000b1fc8ab69fcee16bd8e2a6ccf3fe8af4 -size 60444 +oid sha256:8c272dc0bfdd80edbc0e9804e4b0c37f9eac5191a17a3e30d4a91af8ad991e54 +size 60497 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_de.png index 824938172d..045576fd26 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b42a72b8a0c47c86f86c71ba6153e4fb96e6f7fe4e4c43d4dabd6f3c5bb0ea1d -size 60510 +oid sha256:a8c4c8e45da8d9f7cc30daa3fc451deb3880254396ac0981eda59a541b682c1e +size 60575 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_de.png index 23cf3ec660..cdd72552d0 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a7a065b41b1d91d778b802bc9ba58a9491efc339fc08365ee93a2ce546ff630d -size 69115 +oid sha256:3af4cb08487aca4a4c17fb1a4d4516c9d633ab581df24d28c11a88ce569bed3c +size 69191 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_de.png b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_de.png index a421bc4928..e287dca146 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ecc34684316796fbc9ca8ef51c51dffdd208cdba1fa3094bf9cc78032ff69c5b -size 59948 +oid sha256:bac50948e1bde9e5bcf5d7e06a3d5c31ac598db2fb762eee9bfc243d1906d238 +size 60048 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_0_de.png index 995c0bdbef..5d1695fefe 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c2c8b262ad96121c40ada406ff69eccae562dde53e6c443e998a1e9298af176 -size 72670 +oid sha256:e938e2ee657c86a35ef80713b6851b10bbfdf81f056b84a515cb7d09d2924227 +size 72280 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_10_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_10_de.png index 664c684c76..9139cfc084 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_10_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_10_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fea796dd9d77e3fdd8299c466ea7e288416139820e3d63160e14b602f8357fad -size 55744 +oid sha256:ca96ca3115b7630e87e67c1f65aae89348f9ab6386f6bbdfe6706bb498e29df1 +size 56098 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_11_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_11_de.png index d0f110d40f..d4e1216279 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_11_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_11_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0144461bd7e0076ef528a469ac99c7c8ca1d3473dbc18ebd635d430c3a2f13c -size 71061 +oid sha256:343644a8d2d9db799de9169a8e2feebb71f535dd18ca03460a774aeb230f473e +size 70592 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_1_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_1_de.png index cdbe3c1024..43013eaa67 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_1_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c91ce0f1fc215deeca1e07c92a25ea1ce3c67c7e22c2ec3c8a611b5ee8e2bec6 -size 82226 +oid sha256:22010f59f1eecd415b1053bfc39433a1fab5c7dc9fc91ae7d58677bafd818ff2 +size 81892 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_2_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_2_de.png index c0c96ebe50..d60e5a8065 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_2_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_2_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7537431b942cf13953936fc7be06a0e269e03ac601426e60e0de3646b4848250 -size 59027 +oid sha256:f8456372d40c2812ca55bb65be6cb2d84fbeec5108d33b9f6670887c95089184 +size 59224 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_3_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_3_de.png index 908b4f2e78..19f0bfef1e 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_3_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_3_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0490cb7ba961da251b82da2d4e248eb5e930e5cd853a0c0e4c184863483c1be3 -size 58094 +oid sha256:90957d3d22f355d00813010758d4c2cff75a58bd5446fd8e4a9e07aa5b815e23 +size 58221 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_4_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_4_de.png index f34df6b6a6..a33b90da60 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_4_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_4_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7bbd1bd20c2f1198e8e9681ce20a162586d4240ff8e6408675abad364f1e544 -size 65417 +oid sha256:386ca75ca2695fce27cba64e3dc7350f0fc13291a842b8ed75987abe4165a82f +size 65990 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_5_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_5_de.png index 9c1c251e28..1bd9e7c1ef 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_5_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_5_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a05a648bffe46f29a377bbf4ad548df153e3c17a0e8014a594d8314d4b85cf4b -size 101198 +oid sha256:3edb8f82e829c80cae739460d75967e10de58c5cd18f75dba90daf1fc61c2f20 +size 101215 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_6_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_6_de.png index 80150353ae..ffcd9cad1e 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_6_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_6_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4cc0e4d504ebda2d86e0c7ae557a89587d68957bacfcec9f918f740ab9ddcbe8 -size 57121 +oid sha256:af83e91f7fa2b45d7e70af1784873b3584c2313b35fd0e861bdce7e3d33b63ab +size 57426 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_7_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_7_de.png index 51f4051085..a80bc423e3 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_7_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_7_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b657f75efe8e75f2e8f0ca45ed0d9ecb62400e3b214764edc2e1915812742c3d -size 56980 +oid sha256:c48965981c80bf46726ec3fe33e3307e213726f002ba18263600d4cd07a92b4e +size 57282 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_8_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_8_de.png index abfdbcf57e..c1de8eb3b9 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_8_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_8_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb0220077eb2469994f899d9819baa3b4422525c306159f651f502cbebd24150 -size 67414 +oid sha256:86e8e15959f4e9a29a1320b9a586fb1877d7703e554ca730ea58c1f4c0b56e47 +size 67720 diff --git a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_9_de.png b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_9_de.png index 96f810d9ab..90b9927d64 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerReply_Day_9_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerReply_Day_9_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e9c42a7caed334e3da02c82d234b61ba95216d65e593ac8461c0649a0b032ab -size 56467 +oid sha256:92b0771d88f7e428e99fd8393d4c1e03da059403408ab5deec02a9e35df0f946 +size 56821 diff --git a/screenshots/de/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_de.png index 98ecbe8286..5264638d0c 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65a53d64c78f99ff6d36f8e6597ba7404a7e27581d823a5674d46459d15a97ca -size 55407 +oid sha256:dfef826337bf428fb835513db14caa4d78056ced5fe44e2a4ea5905a9beabe10 +size 54880 diff --git a/screenshots/de/libraries.textcomposer_TextComposerSimple_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerSimple_Day_0_de.png index fe5975ff4f..84ff4beabf 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerSimple_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerSimple_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea1736c6617804eb12450189db18dec3d1959b2d426aeb298c6164609f23319c -size 43565 +oid sha256:713ff7ecd0b47ccd2be58034e404b4e4a2ba02c51a0043d4de25f736ca8eb314 +size 43363 diff --git a/screenshots/de/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_de.png b/screenshots/de/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_de.png index 40b883d797..53278df302 100644 --- a/screenshots/de/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_de.png +++ b/screenshots/de/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b00a37e1fa846df8f8cf0d98be84b1a261fcb7b5b5cafdfe5a9726e7fc66b7d -size 36435 +oid sha256:b5be22c3549f187e9cd86b84d977b70b5fc393c8ecfea7d7b8669956a6b55e82 +size 35732 diff --git a/screenshots/de/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_de.png b/screenshots/de/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_de.png index 4e8aac17c6..73d93c43cd 100644 --- a/screenshots/de/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_de.png +++ b/screenshots/de/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_de.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:182141c01e8cd78a23f41d76c2d0c6bfb769722d243506c0463f2a5a968f8911 +oid sha256:b2acebb0b920c95403fd872f8cdfdb45bf0fcd5cba75600971c32569c65bb8d1 size 44559 diff --git a/screenshots/html/data.js b/screenshots/html/data.js index 119bc1e013..bb10f230a1 100644 --- a/screenshots/html/data.js +++ b/screenshots/html/data.js @@ -2,99 +2,107 @@ export const screenshots = [ ["en","en-dark","de",], ["features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en","features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en",0,], -["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",20595,], +["features.preferences.impl.about_AboutView_Day_0_en","features.preferences.impl.about_AboutView_Night_0_en",20630,], ["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_0_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_0_en",0,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_1_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_1_en",20595,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_2_en",20595,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en",20595,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en",20595,], -["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en",20595,], -["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20595,], -["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",20595,], -["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20595,], -["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20595,], -["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20595,], -["features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en","features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en",20595,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_1_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_1_en",20630,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_2_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_2_en",20630,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_3_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_3_en",20630,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_4_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_4_en",20630,], +["features.invite.impl.acceptdecline_AcceptDeclineInviteView_Day_5_en","features.invite.impl.acceptdecline_AcceptDeclineInviteView_Night_5_en",20630,], +["features.logout.impl_AccountDeactivationView_Day_0_en","features.logout.impl_AccountDeactivationView_Night_0_en",20630,], +["features.logout.impl_AccountDeactivationView_Day_1_en","features.logout.impl_AccountDeactivationView_Night_1_en",20630,], +["features.logout.impl_AccountDeactivationView_Day_2_en","features.logout.impl_AccountDeactivationView_Night_2_en",20630,], +["features.logout.impl_AccountDeactivationView_Day_3_en","features.logout.impl_AccountDeactivationView_Night_3_en",20630,], +["features.logout.impl_AccountDeactivationView_Day_4_en","features.logout.impl_AccountDeactivationView_Night_4_en",20630,], +["features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en","features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en",20630,], ["features.login.impl.accountprovider_AccountProviderView_Day_0_en","features.login.impl.accountprovider_AccountProviderView_Night_0_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_1_en","features.login.impl.accountprovider_AccountProviderView_Night_1_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_2_en","features.login.impl.accountprovider_AccountProviderView_Night_2_en",0,], ["features.login.impl.accountprovider_AccountProviderView_Day_3_en","features.login.impl.accountprovider_AccountProviderView_Night_3_en",0,], -["libraries.accountselect.impl_AccountSelectView_Day_0_en","libraries.accountselect.impl_AccountSelectView_Night_0_en",20595,], -["libraries.accountselect.impl_AccountSelectView_Day_1_en","libraries.accountselect.impl_AccountSelectView_Night_1_en",20595,], +["libraries.accountselect.impl_AccountSelectView_Day_0_en","libraries.accountselect.impl_AccountSelectView_Night_0_en",20630,], +["libraries.accountselect.impl_AccountSelectView_Day_1_en","libraries.accountselect.impl_AccountSelectView_Night_1_en",20630,], ["features.messages.impl.actionlist_ActionListViewContent_Day_0_en","features.messages.impl.actionlist_ActionListViewContent_Night_0_en",0,], -["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20595,], +["features.messages.impl.actionlist_ActionListViewContent_Day_10_en","features.messages.impl.actionlist_ActionListViewContent_Night_10_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_11_en","features.messages.impl.actionlist_ActionListViewContent_Night_11_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_12_en","features.messages.impl.actionlist_ActionListViewContent_Night_12_en",20630,], ["features.messages.impl.actionlist_ActionListViewContent_Day_1_en","features.messages.impl.actionlist_ActionListViewContent_Night_1_en",0,], -["features.messages.impl.actionlist_ActionListViewContent_Day_2_en","features.messages.impl.actionlist_ActionListViewContent_Night_2_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20595,], -["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20595,], -["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20595,], -["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20595,], -["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20595,], -["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",20595,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_0_en","features.space.impl.addroom_AddRoomToSpaceView_Night_0_en",20595,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_1_en","features.space.impl.addroom_AddRoomToSpaceView_Night_1_en",20595,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_2_en","features.space.impl.addroom_AddRoomToSpaceView_Night_2_en",20595,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_3_en","features.space.impl.addroom_AddRoomToSpaceView_Night_3_en",20595,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_4_en","features.space.impl.addroom_AddRoomToSpaceView_Night_4_en",20595,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_5_en","features.space.impl.addroom_AddRoomToSpaceView_Night_5_en",20595,], -["features.space.impl.addroom_AddRoomToSpaceView_Day_6_en","features.space.impl.addroom_AddRoomToSpaceView_Night_6_en",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en","",20595,], -["features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en","",20595,], -["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20595,], -["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20595,], +["features.messages.impl.actionlist_ActionListViewContent_Day_2_en","features.messages.impl.actionlist_ActionListViewContent_Night_2_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_3_en","features.messages.impl.actionlist_ActionListViewContent_Night_3_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_4_en","features.messages.impl.actionlist_ActionListViewContent_Night_4_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_5_en","features.messages.impl.actionlist_ActionListViewContent_Night_5_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_6_en","features.messages.impl.actionlist_ActionListViewContent_Night_6_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_7_en","features.messages.impl.actionlist_ActionListViewContent_Night_7_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_8_en","features.messages.impl.actionlist_ActionListViewContent_Night_8_en",20630,], +["features.messages.impl.actionlist_ActionListViewContent_Day_9_en","features.messages.impl.actionlist_ActionListViewContent_Night_9_en",20630,], +["features.createroom.impl.addpeople_AddPeopleView_Day_0_en","features.createroom.impl.addpeople_AddPeopleView_Night_0_en",20630,], +["features.createroom.impl.addpeople_AddPeopleView_Day_1_en","features.createroom.impl.addpeople_AddPeopleView_Night_1_en",20630,], +["features.createroom.impl.addpeople_AddPeopleView_Day_2_en","features.createroom.impl.addpeople_AddPeopleView_Night_2_en",20630,], +["features.createroom.impl.addpeople_AddPeopleView_Day_3_en","features.createroom.impl.addpeople_AddPeopleView_Night_3_en",20630,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_0_en","features.space.impl.addroom_AddRoomToSpaceView_Night_0_en",20630,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_1_en","features.space.impl.addroom_AddRoomToSpaceView_Night_1_en",20630,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_2_en","features.space.impl.addroom_AddRoomToSpaceView_Night_2_en",20630,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_3_en","features.space.impl.addroom_AddRoomToSpaceView_Night_3_en",20630,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_4_en","features.space.impl.addroom_AddRoomToSpaceView_Night_4_en",20630,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_5_en","features.space.impl.addroom_AddRoomToSpaceView_Night_5_en",20630,], +["features.space.impl.addroom_AddRoomToSpaceView_Day_6_en","features.space.impl.addroom_AddRoomToSpaceView_Night_6_en",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en","",20630,], +["features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en","",20630,], +["libraries.designsystem.components.dialogs_AlertDialogContent_Dialogs_en","",20630,], +["libraries.designsystem.components.dialogs_AlertDialog_Day_0_en","libraries.designsystem.components.dialogs_AlertDialog_Night_0_en",20630,], ["libraries.designsystem.theme.components_AllIcons_Icons_en","",0,], -["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20595,], -["features.analytics.impl_AnalyticsOptInView_Day_1_en","features.analytics.impl_AnalyticsOptInView_Night_1_en",20595,], -["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20595,], -["features.analytics.api.preferences_AnalyticsPreferencesView_Day_1_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_1_en",20595,], -["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20595,], +["features.analytics.impl_AnalyticsOptInView_Day_0_en","features.analytics.impl_AnalyticsOptInView_Night_0_en",20630,], +["features.analytics.impl_AnalyticsOptInView_Day_1_en","features.analytics.impl_AnalyticsOptInView_Night_1_en",20630,], +["features.analytics.api.preferences_AnalyticsPreferencesView_Day_0_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_0_en",20630,], +["features.analytics.api.preferences_AnalyticsPreferencesView_Day_1_en","features.analytics.api.preferences_AnalyticsPreferencesView_Night_1_en",20630,], +["features.preferences.impl.analytics_AnalyticsSettingsView_Day_0_en","features.preferences.impl.analytics_AnalyticsSettingsView_Night_0_en",20630,], ["libraries.designsystem.components_Announcement_Day_0_en","libraries.designsystem.components_Announcement_Night_0_en",0,], -["features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_en","features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Night_0_en",20595,], -["features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_en","features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_0_en",20595,], -["features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_en","features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_1_en",20595,], -["services.apperror.api_AppErrorView_Day_0_en","services.apperror.api_AppErrorView_Night_0_en",20595,], +["features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_en","features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Night_0_en",20630,], +["features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_en","features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_0_en",20630,], +["features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_en","features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_1_en",20630,], +["services.apperror.api_AppErrorView_Day_0_en","services.apperror.api_AppErrorView_Night_0_en",20630,], ["libraries.designsystem.components.async_AsyncActionView_Day_0_en","libraries.designsystem.components.async_AsyncActionView_Night_0_en",0,], -["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",20595,], +["libraries.designsystem.components.async_AsyncActionView_Day_1_en","libraries.designsystem.components.async_AsyncActionView_Night_1_en",20630,], ["libraries.designsystem.components.async_AsyncActionView_Day_2_en","libraries.designsystem.components.async_AsyncActionView_Night_2_en",0,], -["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",20595,], +["libraries.designsystem.components.async_AsyncActionView_Day_3_en","libraries.designsystem.components.async_AsyncActionView_Night_3_en",20630,], ["libraries.designsystem.components.async_AsyncActionView_Day_4_en","libraries.designsystem.components.async_AsyncActionView_Night_4_en",0,], -["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",20595,], +["libraries.designsystem.components.async_AsyncFailure_Day_0_en","libraries.designsystem.components.async_AsyncFailure_Night_0_en",20630,], ["libraries.designsystem.components.async_AsyncIndicatorFailure_Day_0_en","libraries.designsystem.components.async_AsyncIndicatorFailure_Night_0_en",0,], ["libraries.designsystem.components.async_AsyncIndicatorLoading_Day_0_en","libraries.designsystem.components.async_AsyncIndicatorLoading_Night_0_en",0,], ["libraries.designsystem.components.async_AsyncLoading_Day_0_en","libraries.designsystem.components.async_AsyncLoading_Night_0_en",0,], -["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",20595,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_en","",20630,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_en","",20630,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en","",20630,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_en","",20630,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_en","",20630,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en","",20630,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_6_en","",20630,], +["features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_7_en","",20630,], +["features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en","features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en",20630,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_0_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_0_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_1_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_1_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_2_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_2_en",0,], @@ -104,19 +112,20 @@ export const screenshots = [ ["libraries.matrix.ui.components_AttachmentThumbnail_Day_6_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_6_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_7_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_7_en",0,], ["libraries.matrix.ui.components_AttachmentThumbnail_Day_8_en","libraries.matrix.ui.components_AttachmentThumbnail_Night_8_en",0,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_2_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_4_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en","",20595,], -["features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en","",20595,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_2_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_4_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en","",20630,], +["features.messages.impl.attachments.preview_AttachmentsPreviewView_9_en","",20630,], ["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_1_en",0,], ["libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_2_en","libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_2_en",0,], -["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20595,], +["libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en","libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en",20630,], ["libraries.designsystem.components.avatar.internal_AvatarCluster_Avatars_en","",0,], ["libraries.matrix.ui.components_AvatarPickerSizes_Day_0_en","libraries.matrix.ui.components_AvatarPickerSizes_Night_0_en",0,], ["libraries.matrix.ui.components_AvatarPickerViewRtl_Day_0_en","libraries.matrix.ui.components_AvatarPickerViewRtl_Night_0_en",0,], @@ -146,22 +155,22 @@ export const screenshots = [ ["libraries.designsystem.modifiers_BackgroundVerticalGradientDisabled_Day_0_en","libraries.designsystem.modifiers_BackgroundVerticalGradientDisabled_Night_0_en",0,], ["libraries.designsystem.modifiers_BackgroundVerticalGradient_Day_0_en","libraries.designsystem.modifiers_BackgroundVerticalGradient_Night_0_en",0,], ["libraries.designsystem.components_Badge_Day_0_en","libraries.designsystem.components_Badge_Night_0_en",0,], -["features.home.impl.components_BatteryOptimizationBanner_Day_0_en","features.home.impl.components_BatteryOptimizationBanner_Night_0_en",20595,], +["features.home.impl.components_BatteryOptimizationBanner_Day_0_en","features.home.impl.components_BatteryOptimizationBanner_Night_0_en",20630,], ["libraries.designsystem.atomic.atoms_BetaLabel_Day_0_en","libraries.designsystem.atomic.atoms_BetaLabel_Night_0_en",0,], ["libraries.designsystem.components_BigIcon_Day_0_en","libraries.designsystem.components_BigIcon_Night_0_en",0,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",20595,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20595,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20595,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20595,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20595,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20595,], -["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20595,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_0_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_0_en",20630,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_1_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_1_en",20630,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_2_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_2_en",20630,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_3_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_3_en",20630,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en",20630,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en",20630,], +["features.preferences.impl.blockedusers_BlockedUsersView_Day_6_en","features.preferences.impl.blockedusers_BlockedUsersView_Night_6_en",20630,], ["libraries.designsystem.theme.components_BottomSheetDragHandle_Day_0_en","libraries.designsystem.theme.components_BottomSheetDragHandle_Night_0_en",0,], -["features.rageshake.impl.bugreport_BugReportViewDay_0_en","",20595,], -["features.rageshake.impl.bugreport_BugReportViewDay_1_en","",20595,], -["features.rageshake.impl.bugreport_BugReportViewDay_2_en","",20595,], -["features.rageshake.impl.bugreport_BugReportViewDay_3_en","",20595,], -["features.rageshake.impl.bugreport_BugReportViewDay_4_en","",20595,], +["features.rageshake.impl.bugreport_BugReportViewDay_0_en","",20630,], +["features.rageshake.impl.bugreport_BugReportViewDay_1_en","",20630,], +["features.rageshake.impl.bugreport_BugReportViewDay_2_en","",20630,], +["features.rageshake.impl.bugreport_BugReportViewDay_3_en","",20630,], +["features.rageshake.impl.bugreport_BugReportViewDay_4_en","",20630,], ["features.rageshake.impl.bugreport_BugReportViewNight_0_en","",0,], ["features.rageshake.impl.bugreport_BugReportViewNight_1_en","",0,], ["features.rageshake.impl.bugreport_BugReportViewNight_2_en","",0,], @@ -172,141 +181,141 @@ export const screenshots = [ ["features.messages.impl.timeline.components_CallMenuItem_Day_0_en","features.messages.impl.timeline.components_CallMenuItem_Night_0_en",0,], ["features.messages.impl.timeline.components_CallMenuItem_Day_1_en","features.messages.impl.timeline.components_CallMenuItem_Night_1_en",0,], ["features.messages.impl.timeline.components_CallMenuItem_Day_2_en","features.messages.impl.timeline.components_CallMenuItem_Night_2_en",0,], -["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20595,], -["features.messages.impl.timeline.components_CallMenuItem_Day_4_en","features.messages.impl.timeline.components_CallMenuItem_Night_4_en",20595,], +["features.messages.impl.timeline.components_CallMenuItem_Day_3_en","features.messages.impl.timeline.components_CallMenuItem_Night_3_en",20630,], +["features.messages.impl.timeline.components_CallMenuItem_Day_4_en","features.messages.impl.timeline.components_CallMenuItem_Night_4_en",20630,], ["features.messages.impl.timeline.components_CallMenuItem_Day_5_en","features.messages.impl.timeline.components_CallMenuItem_Night_5_en",0,], -["features.messages.impl.timeline.components_CallMenuItem_Day_6_en","features.messages.impl.timeline.components_CallMenuItem_Night_6_en",20595,], +["features.messages.impl.timeline.components_CallMenuItem_Day_6_en","features.messages.impl.timeline.components_CallMenuItem_Night_6_en",20630,], ["features.messages.impl.timeline.components_CallMenuItem_Day_7_en","features.messages.impl.timeline.components_CallMenuItem_Night_7_en",0,], ["features.call.impl.ui_CallScreenView_Day_0_en","features.call.impl.ui_CallScreenView_Night_0_en",0,], -["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20595,], -["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20595,], -["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20595,], -["libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en","libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en",20595,], -["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20595,], -["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_0_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_0_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en",20595,], +["features.call.impl.ui_CallScreenView_Day_1_en","features.call.impl.ui_CallScreenView_Night_1_en",20630,], +["features.call.impl.ui_CallScreenView_Day_2_en","features.call.impl.ui_CallScreenView_Night_2_en",20630,], +["features.call.impl.ui_CallScreenView_Day_3_en","features.call.impl.ui_CallScreenView_Night_3_en",20630,], +["libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en","libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en",20630,], +["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en",20630,], +["features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en","features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_0_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_0_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en",20630,], ["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_5_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_5_en",0,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en",20595,], -["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en",20595,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en",20595,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en",20595,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en",20595,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en",20595,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en",20595,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en",20595,], -["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en",20595,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en",20630,], +["features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en","features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en",20630,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en",20630,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en",20630,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en",20630,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en",20630,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en",20630,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en",20630,], +["features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en","features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en",20630,], ["features.login.impl.changeserver_ChangeServerView_Day_0_en","features.login.impl.changeserver_ChangeServerView_Night_0_en",0,], -["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",20595,], -["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20595,], -["features.login.impl.changeserver_ChangeServerView_Day_3_en","features.login.impl.changeserver_ChangeServerView_Night_3_en",20595,], -["features.login.impl.changeserver_ChangeServerView_Day_4_en","features.login.impl.changeserver_ChangeServerView_Night_4_en",20595,], -["features.login.impl.changeserver_ChangeServerView_Day_5_en","features.login.impl.changeserver_ChangeServerView_Night_5_en",20595,], +["features.login.impl.changeserver_ChangeServerView_Day_1_en","features.login.impl.changeserver_ChangeServerView_Night_1_en",20630,], +["features.login.impl.changeserver_ChangeServerView_Day_2_en","features.login.impl.changeserver_ChangeServerView_Night_2_en",20630,], +["features.login.impl.changeserver_ChangeServerView_Day_3_en","features.login.impl.changeserver_ChangeServerView_Night_3_en",20630,], +["features.login.impl.changeserver_ChangeServerView_Day_4_en","features.login.impl.changeserver_ChangeServerView_Night_4_en",20630,], +["features.login.impl.changeserver_ChangeServerView_Day_5_en","features.login.impl.changeserver_ChangeServerView_Night_5_en",20630,], ["libraries.matrix.ui.components_CheckableResolvedUserRow_en","",0,], -["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20595,], +["libraries.matrix.ui.components_CheckableUnresolvedUserRow_en","",20630,], ["libraries.designsystem.theme.components_Checkboxes_Toggles_en","",0,], -["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en",20595,], -["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en",20595,], -["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en",20595,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_0_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_0_en",20595,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_1_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_1_en",20595,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_2_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_2_en",20595,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_3_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_3_en",20595,], -["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_4_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_4_en",20595,], +["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en",20630,], +["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en",20630,], +["features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en","features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en",20630,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_0_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_0_en",20630,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_1_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_1_en",20630,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_2_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_2_en",20630,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_3_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_3_en",20630,], +["features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Day_4_en","features.ftue.impl.sessionverification.choosemode_ChooseSelfVerificationModeView_Night_4_en",20630,], ["libraries.designsystem.theme.components_CircularProgressIndicator_Progress_Indicators_en","",0,], ["libraries.designsystem.components_ClickableLinkText_Text_en","",0,], -["features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Day_0_en","features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Night_0_en",20595,], +["features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Day_0_en","features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Night_0_en",20630,], ["libraries.designsystem.theme_ColorAliases_Day_0_en","libraries.designsystem.theme_ColorAliases_Night_0_en",0,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20595,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20595,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en",20595,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en",20595,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en",20595,], -["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en",20595,], -["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20595,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_0_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_0_en",20630,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_1_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_1_en",20630,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_2_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_2_en",20630,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_3_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_3_en",20630,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_4_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_4_en",20630,], +["libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Day_5_en","libraries.designsystem.atomic.molecules_ComposerAlertMolecule_Night_5_en",20630,], +["libraries.textcomposer_ComposerModeView_Day_0_en","libraries.textcomposer_ComposerModeView_Night_0_en",20630,], ["libraries.textcomposer_ComposerModeView_Day_1_en","libraries.textcomposer_ComposerModeView_Night_1_en",0,], ["libraries.textcomposer_ComposerModeView_Day_2_en","libraries.textcomposer_ComposerModeView_Night_2_en",0,], ["libraries.textcomposer_ComposerModeView_Day_3_en","libraries.textcomposer_ComposerModeView_Night_3_en",0,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en","",20595,], -["features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en","",20595,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20595,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20595,], -["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20595,], -["features.home.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.home.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20595,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en","",20630,], +["features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en","",20630,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_0_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_0_en",20630,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_1_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_1_en",20630,], +["features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Day_2_en","features.login.impl.screens.confirmaccountprovider_ConfirmAccountProviderView_Night_2_en",20630,], +["features.home.impl.components_ConfirmRecoveryKeyBanner_Day_0_en","features.home.impl.components_ConfirmRecoveryKeyBanner_Night_0_en",20630,], ["libraries.designsystem.components.dialogs_ConfirmationDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_ConfirmationDialog_Day_0_en","libraries.designsystem.components.dialogs_ConfirmationDialog_Night_0_en",0,], ["features.networkmonitor.api.ui_ConnectivityIndicator_Day_0_en","features.networkmonitor.api.ui_ConnectivityIndicator_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_CounterAtom_Day_0_en","libraries.designsystem.atomic.atoms_CounterAtom_Night_0_en",0,], -["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20595,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20595,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20595,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20595,], -["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20595,], -["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en",20595,], -["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en",20595,], -["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20595,], -["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20595,], -["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20595,], -["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20595,], -["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20595,], -["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20595,], -["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20595,], -["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20595,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_0_en","",20595,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_1_en","",20595,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_2_en","",20595,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_3_en","",20595,], -["libraries.dateformatter.impl.previews_DateFormatterModeView_4_en","",20595,], +["features.rageshake.api.crash_CrashDetectionView_Day_0_en","features.rageshake.api.crash_CrashDetectionView_Night_0_en",20630,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_0_en","features.login.impl.screens.createaccount_CreateAccountView_Night_0_en",20630,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_1_en","features.login.impl.screens.createaccount_CreateAccountView_Night_1_en",20630,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_2_en","features.login.impl.screens.createaccount_CreateAccountView_Night_2_en",20630,], +["features.login.impl.screens.createaccount_CreateAccountView_Day_3_en","features.login.impl.screens.createaccount_CreateAccountView_Night_3_en",20630,], +["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en",20630,], +["libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en","libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en",20630,], +["features.poll.impl.create_CreatePollView_Day_0_en","features.poll.impl.create_CreatePollView_Night_0_en",20630,], +["features.poll.impl.create_CreatePollView_Day_1_en","features.poll.impl.create_CreatePollView_Night_1_en",20630,], +["features.poll.impl.create_CreatePollView_Day_2_en","features.poll.impl.create_CreatePollView_Night_2_en",20630,], +["features.poll.impl.create_CreatePollView_Day_3_en","features.poll.impl.create_CreatePollView_Night_3_en",20630,], +["features.poll.impl.create_CreatePollView_Day_4_en","features.poll.impl.create_CreatePollView_Night_4_en",20630,], +["features.poll.impl.create_CreatePollView_Day_5_en","features.poll.impl.create_CreatePollView_Night_5_en",20630,], +["features.poll.impl.create_CreatePollView_Day_6_en","features.poll.impl.create_CreatePollView_Night_6_en",20630,], +["features.poll.impl.create_CreatePollView_Day_7_en","features.poll.impl.create_CreatePollView_Night_7_en",20630,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_0_en","",20630,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_1_en","",20630,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_2_en","",20630,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_3_en","",20630,], +["libraries.dateformatter.impl.previews_DateFormatterModeView_4_en","",20630,], ["libraries.mediaviewer.impl.gallery.ui_DateItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_DateItemView_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_DateItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_DateItemView_Night_1_en",0,], -["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20595,], -["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20595,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_0_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_0_en",20595,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_1_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_1_en",20595,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_2_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_2_en",20595,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_3_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_3_en",20595,], -["features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_4_en",20595,], +["libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en","",20630,], +["libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en","",20630,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_0_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_0_en",20630,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_1_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_1_en",20630,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_2_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_2_en",20630,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_3_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_3_en",20630,], +["features.invite.impl.declineandblock_DeclineAndBlockView_Day_4_en","features.invite.impl.declineandblock_DeclineAndBlockView_Night_4_en",20630,], ["features.logout.impl.direct_DefaultDirectLogoutView_Day_0_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_0_en",0,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",20595,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20595,], -["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20595,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_1_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_1_en",20630,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_2_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_2_en",20630,], +["features.logout.impl.direct_DefaultDirectLogoutView_Day_3_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_3_en",20630,], ["features.logout.impl.direct_DefaultDirectLogoutView_Day_4_en","features.logout.impl.direct_DefaultDirectLogoutView_Night_4_en",0,], -["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",20595,], +["features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Day_0_en","features.preferences.impl.notifications.edit_DefaultNotificationSettingOption_Night_0_en",20630,], ["features.licenses.impl.details_DependenciesDetailsView_Day_0_en","features.licenses.impl.details_DependenciesDetailsView_Night_0_en",0,], -["features.licenses.impl.list_DependencyLicensesListView_Day_0_en","features.licenses.impl.list_DependencyLicensesListView_Night_0_en",20595,], -["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20595,], -["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20595,], -["features.licenses.impl.list_DependencyLicensesListView_Day_3_en","features.licenses.impl.list_DependencyLicensesListView_Night_3_en",20595,], -["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_0_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_0_en",20595,], -["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_1_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_1_en",20595,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20595,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20595,], -["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20595,], +["features.licenses.impl.list_DependencyLicensesListView_Day_0_en","features.licenses.impl.list_DependencyLicensesListView_Night_0_en",20630,], +["features.licenses.impl.list_DependencyLicensesListView_Day_1_en","features.licenses.impl.list_DependencyLicensesListView_Night_1_en",20630,], +["features.licenses.impl.list_DependencyLicensesListView_Day_2_en","features.licenses.impl.list_DependencyLicensesListView_Night_2_en",20630,], +["features.licenses.impl.list_DependencyLicensesListView_Day_3_en","features.licenses.impl.list_DependencyLicensesListView_Night_3_en",20630,], +["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_0_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_0_en",20630,], +["features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Day_1_en","features.linknewdevice.impl.screens.desktop_DesktopNoticeView_Night_1_en",20630,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_0_en","features.preferences.impl.developer_DeveloperSettingsView_Night_0_en",20630,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_1_en","features.preferences.impl.developer_DeveloperSettingsView_Night_1_en",20630,], +["features.preferences.impl.developer_DeveloperSettingsView_Day_2_en","features.preferences.impl.developer_DeveloperSettingsView_Night_2_en",20630,], ["libraries.designsystem.theme.components_DialogWithDestructiveButton_Dialog_with_destructive_button_Dialogs_en","",0,], ["libraries.designsystem.theme.components_DialogWithOnlyMessageAndOkButton_Dialog_with_only_message_and_ok_button_Dialogs_en","",0,], ["libraries.designsystem.theme.components_DialogWithThirdButton_Dialog_with_third_button_Dialogs_en","",0,], @@ -319,20 +328,20 @@ export const screenshots = [ ["libraries.designsystem.text_DpScale_1_0f__en","",0,], ["libraries.designsystem.text_DpScale_1_5f__en","",0,], ["libraries.designsystem.theme.components_DropdownMenuItem_Menus_en","",0,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",20595,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20595,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20595,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20595,], -["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20595,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_0_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_0_en",20595,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_1_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_1_en",20595,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_2_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_2_en",20595,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_3_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_3_en",20595,], -["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_4_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_4_en",20595,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20595,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_1_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_1_en",20595,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_2_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_2_en",20595,], -["features.preferences.impl.user.editprofile_EditUserProfileView_Day_3_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_3_en",20595,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en",20630,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en",20630,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en",20630,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en",20630,], +["features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en","features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en",20630,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_0_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_0_en",20630,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_1_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_1_en",20630,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_2_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_2_en",20630,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_3_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_3_en",20630,], +["features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Day_4_en","features.securityandprivacy.impl.editroomaddress_EditRoomAddressView_Night_4_en",20630,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_0_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_0_en",20630,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_1_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_1_en",20630,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_2_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_2_en",20630,], +["features.preferences.impl.user.editprofile_EditUserProfileView_Day_3_en","features.preferences.impl.user.editprofile_EditUserProfileView_Night_3_en",20630,], ["libraries.matrix.ui.components_EditableOrgAvatarRtl_Day_0_en","libraries.matrix.ui.components_EditableOrgAvatarRtl_Night_0_en",0,], ["libraries.matrix.ui.components_EditableOrgAvatar_Day_0_en","libraries.matrix.ui.components_EditableOrgAvatar_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_ElementLogoAtomLargeNoBlurShadow_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomLargeNoBlurShadow_Night_0_en",0,], @@ -340,29 +349,29 @@ export const screenshots = [ ["libraries.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMediumNoBlurShadow_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Day_0_en","libraries.designsystem.atomic.atoms_ElementLogoAtomMedium_Night_0_en",0,], ["features.messages.impl.timeline.components.customreaction_EmojiItem_Day_0_en","features.messages.impl.timeline.components.customreaction_EmojiItem_Night_0_en",0,], -["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_0_en",20595,], -["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_1_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_1_en",20595,], +["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_0_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_0_en",20630,], +["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_1_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_1_en",20630,], ["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_2_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_2_en",0,], ["features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Day_3_en","features.messages.impl.timeline.components.customreaction.picker_EmojiPicker_Night_3_en",0,], ["libraries.ui.common.nodes_EmptyView_Day_0_en","libraries.ui.common.nodes_EmptyView_Night_0_en",0,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en",20595,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en",20595,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en",20595,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en",20595,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en",20595,], -["features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en",20595,], -["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20595,], -["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20595,], -["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_0_en","features.linknewdevice.impl.screens.error_ErrorView_Night_0_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_1_en","features.linknewdevice.impl.screens.error_ErrorView_Night_1_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_2_en","features.linknewdevice.impl.screens.error_ErrorView_Night_2_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_3_en","features.linknewdevice.impl.screens.error_ErrorView_Night_3_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_4_en","features.linknewdevice.impl.screens.error_ErrorView_Night_4_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_5_en","features.linknewdevice.impl.screens.error_ErrorView_Night_5_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_6_en","features.linknewdevice.impl.screens.error_ErrorView_Night_6_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_7_en","features.linknewdevice.impl.screens.error_ErrorView_Night_7_en",20595,], -["features.linknewdevice.impl.screens.error_ErrorView_Day_8_en","features.linknewdevice.impl.screens.error_ErrorView_Night_8_en",20595,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en",20630,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en",20630,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en",20630,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en",20630,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en",20630,], +["features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en","features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en",20630,], +["libraries.designsystem.components.dialogs_ErrorDialogContent_Dialogs_en","",20630,], +["libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialogWithDoNotShowAgain_Night_0_en",20630,], +["libraries.designsystem.components.dialogs_ErrorDialog_Day_0_en","libraries.designsystem.components.dialogs_ErrorDialog_Night_0_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_0_en","features.linknewdevice.impl.screens.error_ErrorView_Night_0_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_1_en","features.linknewdevice.impl.screens.error_ErrorView_Night_1_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_2_en","features.linknewdevice.impl.screens.error_ErrorView_Night_2_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_3_en","features.linknewdevice.impl.screens.error_ErrorView_Night_3_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_4_en","features.linknewdevice.impl.screens.error_ErrorView_Night_4_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_5_en","features.linknewdevice.impl.screens.error_ErrorView_Night_5_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_6_en","features.linknewdevice.impl.screens.error_ErrorView_Night_6_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_7_en","features.linknewdevice.impl.screens.error_ErrorView_Night_7_en",20630,], +["features.linknewdevice.impl.screens.error_ErrorView_Day_8_en","features.linknewdevice.impl.screens.error_ErrorView_Night_8_en",20630,], ["features.messages.impl.timeline.debug_EventDebugInfoView_Day_0_en","features.messages.impl.timeline.debug_EventDebugInfoView_Night_0_en",0,], ["libraries.designsystem.components_ExpandableBottomSheetLayout_en","",0,], ["libraries.featureflag.ui_FeatureListView_Day_0_en","libraries.featureflag.ui_FeatureListView_Night_0_en",0,], @@ -382,52 +391,52 @@ export const screenshots = [ ["features.messages.impl.timeline.components_FloatingDateBadge_Day_0_en","features.messages.impl.timeline.components_FloatingDateBadge_Night_0_en",0,], ["libraries.designsystem.atomic.pages_FlowStepPage_Day_0_en","libraries.designsystem.atomic.pages_FlowStepPage_Night_0_en",0,], ["features.messages.impl.timeline.focus_FocusRequestStateView_Day_0_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_0_en",0,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",20595,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20595,], -["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20595,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_1_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_1_en",20630,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_2_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_2_en",20630,], +["features.messages.impl.timeline.focus_FocusRequestStateView_Day_3_en","features.messages.impl.timeline.focus_FocusRequestStateView_Night_3_en",20630,], ["features.messages.impl.timeline.components_FocusedEvent_Day_0_en","features.messages.impl.timeline.components_FocusedEvent_Night_0_en",0,], ["libraries.textcomposer.components_FormattingOption_Day_0_en","libraries.textcomposer.components_FormattingOption_Night_0_en",0,], ["features.forward.impl_ForwardMessagesView_Day_0_en","features.forward.impl_ForwardMessagesView_Night_0_en",0,], ["features.forward.impl_ForwardMessagesView_Day_1_en","features.forward.impl_ForwardMessagesView_Night_1_en",0,], ["features.forward.impl_ForwardMessagesView_Day_2_en","features.forward.impl_ForwardMessagesView_Night_2_en",0,], -["features.forward.impl_ForwardMessagesView_Day_3_en","features.forward.impl_ForwardMessagesView_Night_3_en",20595,], -["features.home.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.home.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20595,], +["features.forward.impl_ForwardMessagesView_Day_3_en","features.forward.impl_ForwardMessagesView_Night_3_en",20630,], +["features.home.impl.components_FullScreenIntentPermissionBanner_Day_0_en","features.home.impl.components_FullScreenIntentPermissionBanner_Night_0_en",20630,], ["features.announcement.impl.fullscreen_FullscreenAnnouncementView_Day_0_en","features.announcement.impl.fullscreen_FullscreenAnnouncementView_Night_0_en",0,], -["features.announcement.impl.fullscreen_FullscreenAnnouncementView_Day_1_en","features.announcement.impl.fullscreen_FullscreenAnnouncementView_Night_1_en",20595,], +["features.announcement.impl.fullscreen_FullscreenAnnouncementView_Day_1_en","features.announcement.impl.fullscreen_FullscreenAnnouncementView_Night_1_en",20630,], ["libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButtonCircleShape_Night_0_en",0,], ["libraries.designsystem.components.button_GradientFloatingActionButton_Day_0_en","libraries.designsystem.components.button_GradientFloatingActionButton_Night_0_en",0,], ["features.messages.impl.timeline.components.group_GroupHeaderView_Day_0_en","features.messages.impl.timeline.components.group_GroupHeaderView_Night_0_en",0,], ["libraries.designsystem.atomic.pages_HeaderFooterPageScrollable_Day_0_en","libraries.designsystem.atomic.pages_HeaderFooterPageScrollable_Night_0_en",0,], ["libraries.designsystem.atomic.pages_HeaderFooterPage_Day_0_en","libraries.designsystem.atomic.pages_HeaderFooterPage_Night_0_en",0,], -["features.home.impl.spaces_HomeSpacesView_Day_0_en","features.home.impl.spaces_HomeSpacesView_Night_0_en",20595,], -["features.home.impl.spaces_HomeSpacesView_Day_1_en","features.home.impl.spaces_HomeSpacesView_Night_1_en",20595,], -["features.home.impl.spaces_HomeSpacesView_Day_2_en","features.home.impl.spaces_HomeSpacesView_Night_2_en",20595,], -["features.home.impl.components_HomeTopBarMultiAccount_Day_0_en","features.home.impl.components_HomeTopBarMultiAccount_Night_0_en",20595,], -["features.home.impl.components_HomeTopBarSpaceFiltersSelected_Day_0_en","features.home.impl.components_HomeTopBarSpaceFiltersSelected_Night_0_en",20595,], +["features.home.impl.spaces_HomeSpacesView_Day_0_en","features.home.impl.spaces_HomeSpacesView_Night_0_en",20630,], +["features.home.impl.spaces_HomeSpacesView_Day_1_en","features.home.impl.spaces_HomeSpacesView_Night_1_en",20630,], +["features.home.impl.spaces_HomeSpacesView_Day_2_en","features.home.impl.spaces_HomeSpacesView_Night_2_en",20630,], +["features.home.impl.components_HomeTopBarMultiAccount_Day_0_en","features.home.impl.components_HomeTopBarMultiAccount_Night_0_en",20630,], +["features.home.impl.components_HomeTopBarSpaceFiltersSelected_Day_0_en","features.home.impl.components_HomeTopBarSpaceFiltersSelected_Night_0_en",20630,], ["features.home.impl.components_HomeTopBarSpaces_Day_0_en","features.home.impl.components_HomeTopBarSpaces_Night_0_en",0,], -["features.home.impl.components_HomeTopBarWithIndicator_Day_0_en","features.home.impl.components_HomeTopBarWithIndicator_Night_0_en",20595,], -["features.home.impl.components_HomeTopBar_Day_0_en","features.home.impl.components_HomeTopBar_Night_0_en",20595,], +["features.home.impl.components_HomeTopBarWithIndicator_Day_0_en","features.home.impl.components_HomeTopBarWithIndicator_Night_0_en",20630,], +["features.home.impl.components_HomeTopBar_Day_0_en","features.home.impl.components_HomeTopBar_Night_0_en",20630,], ["features.home.impl_HomeViewA11y_en","",0,], -["features.home.impl_HomeView_Day_0_en","features.home.impl_HomeView_Night_0_en",20595,], -["features.home.impl_HomeView_Day_10_en","features.home.impl_HomeView_Night_10_en",20595,], +["features.home.impl_HomeView_Day_0_en","features.home.impl_HomeView_Night_0_en",20630,], +["features.home.impl_HomeView_Day_10_en","features.home.impl_HomeView_Night_10_en",20630,], ["features.home.impl_HomeView_Day_11_en","features.home.impl_HomeView_Night_11_en",0,], ["features.home.impl_HomeView_Day_12_en","features.home.impl_HomeView_Night_12_en",0,], -["features.home.impl_HomeView_Day_13_en","features.home.impl_HomeView_Night_13_en",20595,], -["features.home.impl_HomeView_Day_14_en","features.home.impl_HomeView_Night_14_en",20595,], -["features.home.impl_HomeView_Day_15_en","features.home.impl_HomeView_Night_15_en",20595,], -["features.home.impl_HomeView_Day_16_en","features.home.impl_HomeView_Night_16_en",20595,], -["features.home.impl_HomeView_Day_1_en","features.home.impl_HomeView_Night_1_en",20595,], -["features.home.impl_HomeView_Day_2_en","features.home.impl_HomeView_Night_2_en",20595,], -["features.home.impl_HomeView_Day_3_en","features.home.impl_HomeView_Night_3_en",20595,], -["features.home.impl_HomeView_Day_4_en","features.home.impl_HomeView_Night_4_en",20595,], -["features.home.impl_HomeView_Day_5_en","features.home.impl_HomeView_Night_5_en",20595,], -["features.home.impl_HomeView_Day_6_en","features.home.impl_HomeView_Night_6_en",20595,], -["features.home.impl_HomeView_Day_7_en","features.home.impl_HomeView_Night_7_en",20595,], -["features.home.impl_HomeView_Day_8_en","features.home.impl_HomeView_Night_8_en",20595,], -["features.home.impl_HomeView_Day_9_en","features.home.impl_HomeView_Night_9_en",20595,], +["features.home.impl_HomeView_Day_13_en","features.home.impl_HomeView_Night_13_en",20630,], +["features.home.impl_HomeView_Day_14_en","features.home.impl_HomeView_Night_14_en",20630,], +["features.home.impl_HomeView_Day_15_en","features.home.impl_HomeView_Night_15_en",20630,], +["features.home.impl_HomeView_Day_16_en","features.home.impl_HomeView_Night_16_en",20630,], +["features.home.impl_HomeView_Day_1_en","features.home.impl_HomeView_Night_1_en",20630,], +["features.home.impl_HomeView_Day_2_en","features.home.impl_HomeView_Night_2_en",20630,], +["features.home.impl_HomeView_Day_3_en","features.home.impl_HomeView_Night_3_en",20630,], +["features.home.impl_HomeView_Day_4_en","features.home.impl_HomeView_Night_4_en",20630,], +["features.home.impl_HomeView_Day_5_en","features.home.impl_HomeView_Night_5_en",20630,], +["features.home.impl_HomeView_Day_6_en","features.home.impl_HomeView_Night_6_en",20630,], +["features.home.impl_HomeView_Day_7_en","features.home.impl_HomeView_Night_7_en",20630,], +["features.home.impl_HomeView_Day_8_en","features.home.impl_HomeView_Night_8_en",20630,], +["features.home.impl_HomeView_Day_9_en","features.home.impl_HomeView_Night_9_en",20630,], ["libraries.designsystem.theme.components_HorizontalDivider_Dividers_en","",0,], ["libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en","libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en",0,], -["libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en","libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en",0,], +["libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en","libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en",20630,], ["libraries.designsystem.ruler_HorizontalRuler_Day_0_en","libraries.designsystem.ruler_HorizontalRuler_Night_0_en",0,], ["libraries.designsystem.theme.components_IconButton_Buttons_en","",0,], ["libraries.designsystem.theme.components_IconColorButton_Day_0_en","libraries.designsystem.theme.components_IconColorButton_Night_0_en",0,], @@ -439,8 +448,8 @@ export const screenshots = [ ["appicon.enterprise_Icon_en","",0,], ["libraries.designsystem.icons_IconsOther_Day_0_en","libraries.designsystem.icons_IconsOther_Night_0_en",0,], ["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_0_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_0_en",0,], -["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20595,], -["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20595,], +["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_1_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_1_en",20630,], +["features.messages.impl.crypto.identity_IdentityChangeStateView_Day_2_en","features.messages.impl.crypto.identity_IdentityChangeStateView_Night_2_en",20630,], ["libraries.mediaviewer.impl.gallery.ui_ImageItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_ImageItemView_Night_0_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_0_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_0_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_10_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_10_en",0,], @@ -448,119 +457,119 @@ export const screenshots = [ ["libraries.matrix.ui.messages.reply_InReplyToView_Day_1_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_1_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_2_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_2_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_3_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_3_en",0,], -["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",20595,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_4_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_4_en",20630,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_5_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_5_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_6_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_6_en",0,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_7_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_7_en",0,], -["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",20595,], +["libraries.matrix.ui.messages.reply_InReplyToView_Day_8_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_8_en",20630,], ["libraries.matrix.ui.messages.reply_InReplyToView_Day_9_en","libraries.matrix.ui.messages.reply_InReplyToView_Night_9_en",0,], -["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",20595,], -["features.call.impl.ui_IncomingCallScreen_Day_1_en","features.call.impl.ui_IncomingCallScreen_Night_1_en",20595,], +["features.call.impl.ui_IncomingCallScreen_Day_0_en","features.call.impl.ui_IncomingCallScreen_Night_0_en",20630,], +["features.call.impl.ui_IncomingCallScreen_Day_1_en","features.call.impl.ui_IncomingCallScreen_Night_1_en",20630,], ["features.verifysession.impl.incoming_IncomingVerificationViewA11y_en","",0,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_10_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_10_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_11_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_11_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_12_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_12_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_13_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_13_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_8_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_8_en",20595,], -["features.verifysession.impl.incoming_IncomingVerificationView_Day_9_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_9_en",20595,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_0_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_0_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_10_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_10_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_11_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_11_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_12_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_12_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_13_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_13_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_1_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_1_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_2_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_2_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_3_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_3_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_4_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_4_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_5_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_5_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_6_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_6_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_7_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_7_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_8_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_8_en",20630,], +["features.verifysession.impl.incoming_IncomingVerificationView_Day_9_en","features.verifysession.impl.incoming_IncomingVerificationView_Night_9_en",20630,], ["libraries.designsystem.atomic.molecules_InfoListItemMolecule_Day_0_en","libraries.designsystem.atomic.molecules_InfoListItemMolecule_Night_0_en",0,], ["libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en","libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en",0,], ["libraries.matrix.ui.media_InitialsAvatarBitmapGenerator_Day_0_en","libraries.matrix.ui.media_InitialsAvatarBitmapGenerator_Night_0_en",0,], -["features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_en","features.call.impl.ui_InvalidAudioDeviceDialog_Night_0_en",20595,], -["features.invitepeople.impl_InvitePeopleView_Day_0_en","features.invitepeople.impl_InvitePeopleView_Night_0_en",20595,], -["features.invitepeople.impl_InvitePeopleView_Day_10_en","features.invitepeople.impl_InvitePeopleView_Night_10_en",20595,], +["features.call.impl.ui_InvalidAudioDeviceDialog_Day_0_en","features.call.impl.ui_InvalidAudioDeviceDialog_Night_0_en",20630,], +["features.invitepeople.impl_InvitePeopleView_Day_0_en","features.invitepeople.impl_InvitePeopleView_Night_0_en",20630,], +["features.invitepeople.impl_InvitePeopleView_Day_10_en","features.invitepeople.impl_InvitePeopleView_Night_10_en",20630,], ["features.invitepeople.impl_InvitePeopleView_Day_11_en","features.invitepeople.impl_InvitePeopleView_Night_11_en",0,], -["features.invitepeople.impl_InvitePeopleView_Day_1_en","features.invitepeople.impl_InvitePeopleView_Night_1_en",20595,], +["features.invitepeople.impl_InvitePeopleView_Day_1_en","features.invitepeople.impl_InvitePeopleView_Night_1_en",20630,], ["features.invitepeople.impl_InvitePeopleView_Day_2_en","features.invitepeople.impl_InvitePeopleView_Night_2_en",0,], ["features.invitepeople.impl_InvitePeopleView_Day_3_en","features.invitepeople.impl_InvitePeopleView_Night_3_en",0,], -["features.invitepeople.impl_InvitePeopleView_Day_4_en","features.invitepeople.impl_InvitePeopleView_Night_4_en",20595,], -["features.invitepeople.impl_InvitePeopleView_Day_5_en","features.invitepeople.impl_InvitePeopleView_Night_5_en",20595,], -["features.invitepeople.impl_InvitePeopleView_Day_6_en","features.invitepeople.impl_InvitePeopleView_Night_6_en",20595,], -["features.invitepeople.impl_InvitePeopleView_Day_7_en","features.invitepeople.impl_InvitePeopleView_Night_7_en",20595,], +["features.invitepeople.impl_InvitePeopleView_Day_4_en","features.invitepeople.impl_InvitePeopleView_Night_4_en",20630,], +["features.invitepeople.impl_InvitePeopleView_Day_5_en","features.invitepeople.impl_InvitePeopleView_Night_5_en",20630,], +["features.invitepeople.impl_InvitePeopleView_Day_6_en","features.invitepeople.impl_InvitePeopleView_Night_6_en",20630,], +["features.invitepeople.impl_InvitePeopleView_Day_7_en","features.invitepeople.impl_InvitePeopleView_Night_7_en",20630,], ["features.invitepeople.impl_InvitePeopleView_Day_8_en","features.invitepeople.impl_InvitePeopleView_Night_8_en",0,], -["features.invitepeople.impl_InvitePeopleView_Day_9_en","features.invitepeople.impl_InvitePeopleView_Night_9_en",20595,], -["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20595,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en",20595,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en",20595,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en",20595,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en",20595,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en",20595,], -["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en",20595,], +["features.invitepeople.impl_InvitePeopleView_Day_9_en","features.invitepeople.impl_InvitePeopleView_Night_9_en",20630,], +["libraries.matrix.ui.components_InviteSenderView_Day_0_en","libraries.matrix.ui.components_InviteSenderView_Night_0_en",20630,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en",20630,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en",20630,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en",20630,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en",20630,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en",20630,], +["features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en","features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en",20630,], ["features.joinroom.impl_JoinRoomView_Day_0_en","features.joinroom.impl_JoinRoomView_Night_0_en",0,], -["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_12_en","features.joinroom.impl_JoinRoomView_Night_12_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_13_en","features.joinroom.impl_JoinRoomView_Night_13_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_14_en","features.joinroom.impl_JoinRoomView_Night_14_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_15_en","features.joinroom.impl_JoinRoomView_Night_15_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_16_en","features.joinroom.impl_JoinRoomView_Night_16_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20595,], -["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",20595,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_0_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_0_en",20595,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_1_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_1_en",20595,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_2_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_2_en",20595,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_3_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_3_en",20595,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_4_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_4_en",20595,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_5_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en",20595,], -["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_6_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_6_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_0_en","features.knockrequests.impl.list_KnockRequestsListView_Night_0_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_10_en","features.knockrequests.impl.list_KnockRequestsListView_Night_10_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_1_en","features.knockrequests.impl.list_KnockRequestsListView_Night_1_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_2_en","features.knockrequests.impl.list_KnockRequestsListView_Night_2_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_3_en","features.knockrequests.impl.list_KnockRequestsListView_Night_3_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_4_en","features.knockrequests.impl.list_KnockRequestsListView_Night_4_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_5_en","features.knockrequests.impl.list_KnockRequestsListView_Night_5_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_6_en","features.knockrequests.impl.list_KnockRequestsListView_Night_6_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_7_en","features.knockrequests.impl.list_KnockRequestsListView_Night_7_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_8_en","features.knockrequests.impl.list_KnockRequestsListView_Night_8_en",20595,], -["features.knockrequests.impl.list_KnockRequestsListView_Day_9_en","features.knockrequests.impl.list_KnockRequestsListView_Night_9_en",20595,], +["features.joinroom.impl_JoinRoomView_Day_10_en","features.joinroom.impl_JoinRoomView_Night_10_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_11_en","features.joinroom.impl_JoinRoomView_Night_11_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_12_en","features.joinroom.impl_JoinRoomView_Night_12_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_13_en","features.joinroom.impl_JoinRoomView_Night_13_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_14_en","features.joinroom.impl_JoinRoomView_Night_14_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_15_en","features.joinroom.impl_JoinRoomView_Night_15_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_16_en","features.joinroom.impl_JoinRoomView_Night_16_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_1_en","features.joinroom.impl_JoinRoomView_Night_1_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_2_en","features.joinroom.impl_JoinRoomView_Night_2_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_3_en","features.joinroom.impl_JoinRoomView_Night_3_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_4_en","features.joinroom.impl_JoinRoomView_Night_4_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_5_en","features.joinroom.impl_JoinRoomView_Night_5_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_6_en","features.joinroom.impl_JoinRoomView_Night_6_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_7_en","features.joinroom.impl_JoinRoomView_Night_7_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_8_en","features.joinroom.impl_JoinRoomView_Night_8_en",20630,], +["features.joinroom.impl_JoinRoomView_Day_9_en","features.joinroom.impl_JoinRoomView_Night_9_en",20630,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_0_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_0_en",20630,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_1_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_1_en",20630,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_2_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_2_en",20630,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_3_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_3_en",20630,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_4_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_4_en",20630,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_5_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en",20630,], +["features.knockrequests.impl.banner_KnockRequestsBannerView_Day_6_en","features.knockrequests.impl.banner_KnockRequestsBannerView_Night_6_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_0_en","features.knockrequests.impl.list_KnockRequestsListView_Night_0_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_10_en","features.knockrequests.impl.list_KnockRequestsListView_Night_10_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_1_en","features.knockrequests.impl.list_KnockRequestsListView_Night_1_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_2_en","features.knockrequests.impl.list_KnockRequestsListView_Night_2_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_3_en","features.knockrequests.impl.list_KnockRequestsListView_Night_3_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_4_en","features.knockrequests.impl.list_KnockRequestsListView_Night_4_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_5_en","features.knockrequests.impl.list_KnockRequestsListView_Night_5_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_6_en","features.knockrequests.impl.list_KnockRequestsListView_Night_6_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_7_en","features.knockrequests.impl.list_KnockRequestsListView_Night_7_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_8_en","features.knockrequests.impl.list_KnockRequestsListView_Night_8_en",20630,], +["features.knockrequests.impl.list_KnockRequestsListView_Day_9_en","features.knockrequests.impl.list_KnockRequestsListView_Night_9_en",20630,], ["libraries.designsystem.components_LabelledCheckbox_Toggles_en","",0,], -["features.preferences.impl.labs_LabsView_Day_0_en","features.preferences.impl.labs_LabsView_Night_0_en",20595,], -["features.preferences.impl.labs_LabsView_Day_1_en","features.preferences.impl.labs_LabsView_Night_1_en",20595,], +["features.preferences.impl.labs_LabsView_Day_0_en","features.preferences.impl.labs_LabsView_Night_0_en",20630,], +["features.preferences.impl.labs_LabsView_Day_1_en","features.preferences.impl.labs_LabsView_Night_1_en",20630,], ["features.leaveroom.impl_LeaveRoomView_Day_0_en","features.leaveroom.impl_LeaveRoomView_Night_0_en",0,], -["features.leaveroom.impl_LeaveRoomView_Day_1_en","features.leaveroom.impl_LeaveRoomView_Night_1_en",20595,], -["features.leaveroom.impl_LeaveRoomView_Day_2_en","features.leaveroom.impl_LeaveRoomView_Night_2_en",20595,], -["features.leaveroom.impl_LeaveRoomView_Day_3_en","features.leaveroom.impl_LeaveRoomView_Night_3_en",20595,], -["features.leaveroom.impl_LeaveRoomView_Day_4_en","features.leaveroom.impl_LeaveRoomView_Night_4_en",20595,], -["features.leaveroom.impl_LeaveRoomView_Day_5_en","features.leaveroom.impl_LeaveRoomView_Night_5_en",20595,], -["features.leaveroom.impl_LeaveRoomView_Day_6_en","features.leaveroom.impl_LeaveRoomView_Night_6_en",20595,], -["features.leaveroom.impl_LeaveRoomView_Day_7_en","features.leaveroom.impl_LeaveRoomView_Night_7_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_0_en","features.space.impl.leave_LeaveSpaceView_Night_0_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_10_en","features.space.impl.leave_LeaveSpaceView_Night_10_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_1_en","features.space.impl.leave_LeaveSpaceView_Night_1_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_2_en","features.space.impl.leave_LeaveSpaceView_Night_2_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_3_en","features.space.impl.leave_LeaveSpaceView_Night_3_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_4_en","features.space.impl.leave_LeaveSpaceView_Night_4_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_5_en","features.space.impl.leave_LeaveSpaceView_Night_5_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_6_en","features.space.impl.leave_LeaveSpaceView_Night_6_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_7_en","features.space.impl.leave_LeaveSpaceView_Night_7_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_8_en","features.space.impl.leave_LeaveSpaceView_Night_8_en",20595,], -["features.space.impl.leave_LeaveSpaceView_Day_9_en","features.space.impl.leave_LeaveSpaceView_Night_9_en",20595,], +["features.leaveroom.impl_LeaveRoomView_Day_1_en","features.leaveroom.impl_LeaveRoomView_Night_1_en",20630,], +["features.leaveroom.impl_LeaveRoomView_Day_2_en","features.leaveroom.impl_LeaveRoomView_Night_2_en",20630,], +["features.leaveroom.impl_LeaveRoomView_Day_3_en","features.leaveroom.impl_LeaveRoomView_Night_3_en",20630,], +["features.leaveroom.impl_LeaveRoomView_Day_4_en","features.leaveroom.impl_LeaveRoomView_Night_4_en",20630,], +["features.leaveroom.impl_LeaveRoomView_Day_5_en","features.leaveroom.impl_LeaveRoomView_Night_5_en",20630,], +["features.leaveroom.impl_LeaveRoomView_Day_6_en","features.leaveroom.impl_LeaveRoomView_Night_6_en",20630,], +["features.leaveroom.impl_LeaveRoomView_Day_7_en","features.leaveroom.impl_LeaveRoomView_Night_7_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_0_en","features.space.impl.leave_LeaveSpaceView_Night_0_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_10_en","features.space.impl.leave_LeaveSpaceView_Night_10_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_1_en","features.space.impl.leave_LeaveSpaceView_Night_1_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_2_en","features.space.impl.leave_LeaveSpaceView_Night_2_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_3_en","features.space.impl.leave_LeaveSpaceView_Night_3_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_4_en","features.space.impl.leave_LeaveSpaceView_Night_4_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_5_en","features.space.impl.leave_LeaveSpaceView_Night_5_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_6_en","features.space.impl.leave_LeaveSpaceView_Night_6_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_7_en","features.space.impl.leave_LeaveSpaceView_Night_7_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_8_en","features.space.impl.leave_LeaveSpaceView_Night_8_en",20630,], +["features.space.impl.leave_LeaveSpaceView_Day_9_en","features.space.impl.leave_LeaveSpaceView_Night_9_en",20630,], ["libraries.designsystem.background_LightGradientBackground_Day_0_en","libraries.designsystem.background_LightGradientBackground_Night_0_en",0,], ["libraries.designsystem.theme.components_LinearProgressIndicator_Progress_Indicators_en","",0,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en",20595,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en",20595,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_2_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_2_en",20595,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en",20595,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en",20595,], -["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en",20595,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en",20630,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en",20630,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_2_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_2_en",20630,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en",20630,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en",20630,], +["features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en","features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en",20630,], ["features.messages.impl.link_LinkView_Day_0_en","features.messages.impl.link_LinkView_Night_0_en",0,], -["features.messages.impl.link_LinkView_Day_1_en","features.messages.impl.link_LinkView_Night_1_en",20595,], +["features.messages.impl.link_LinkView_Day_1_en","features.messages.impl.link_LinkView_Night_1_en",20630,], ["libraries.designsystem.components.dialogs_ListDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_ListDialog_Day_0_en","libraries.designsystem.components.dialogs_ListDialog_Night_0_en",0,], ["libraries.designsystem.theme.components_ListItemPrimaryActionWithIcon_List_item_-_Primary_action_&_Icon_List_items_en","",0,], @@ -613,48 +622,48 @@ export const screenshots = [ ["libraries.designsystem.theme.components_ListSupportingTextLargePadding_List_supporting_text_-_large_padding_List_sections_en","",0,], ["libraries.designsystem.theme.components_ListSupportingTextNoPadding_List_supporting_text_-_no_padding_List_sections_en","",0,], ["libraries.designsystem.theme.components_ListSupportingTextSmallPadding_List_supporting_text_-_small_padding_List_sections_en","",0,], -["features.location.api_LiveLocationSharingBanner_Day_0_en","features.location.api_LiveLocationSharingBanner_Night_0_en",20595,], +["features.location.api_LiveLocationSharingBanner_Day_0_en","features.location.api_LiveLocationSharingBanner_Night_0_en",20630,], ["libraries.textcomposer.components_LiveWaveformView_Day_0_en","libraries.textcomposer.components_LiveWaveformView_Night_0_en",0,], ["appnav.room.joined_LoadingRoomNodeView_Day_0_en","appnav.room.joined_LoadingRoomNodeView_Night_0_en",0,], -["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",20595,], +["appnav.room.joined_LoadingRoomNodeView_Day_1_en","appnav.room.joined_LoadingRoomNodeView_Night_1_en",20630,], ["libraries.designsystem.components_LocationPin_Day_0_en","libraries.designsystem.components_LocationPin_Night_0_en",0,], ["features.location.impl.common.ui_LocationShareRow_Day_0_en","features.location.impl.common.ui_LocationShareRow_Night_0_en",0,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20595,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20595,], -["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20595,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en",20630,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en",20630,], +["features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en","features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en",20630,], ["appnav.loggedin_LoggedInView_Day_0_en","appnav.loggedin_LoggedInView_Night_0_en",0,], -["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",20595,], -["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20595,], -["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20595,], -["features.login.impl.login_LoginModeView_Day_0_en","features.login.impl.login_LoginModeView_Night_0_en",20595,], -["features.login.impl.login_LoginModeView_Day_1_en","features.login.impl.login_LoginModeView_Night_1_en",20595,], -["features.login.impl.login_LoginModeView_Day_2_en","features.login.impl.login_LoginModeView_Night_2_en",20595,], -["features.login.impl.login_LoginModeView_Day_3_en","features.login.impl.login_LoginModeView_Night_3_en",20595,], -["features.login.impl.login_LoginModeView_Day_4_en","features.login.impl.login_LoginModeView_Night_4_en",20595,], -["features.login.impl.login_LoginModeView_Day_5_en","features.login.impl.login_LoginModeView_Night_5_en",20595,], -["features.login.impl.login_LoginModeView_Day_6_en","features.login.impl.login_LoginModeView_Night_6_en",20595,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20595,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20595,], -["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20595,], -["features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Day_0_en","features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Night_0_en",20595,], -["features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Day_1_en","features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Night_1_en",20595,], -["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20595,], -["features.logout.impl_LogoutView_Day_10_en","features.logout.impl_LogoutView_Night_10_en",20595,], -["features.logout.impl_LogoutView_Day_11_en","features.logout.impl_LogoutView_Night_11_en",20595,], -["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20595,], -["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20595,], -["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20595,], -["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20595,], -["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20595,], -["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20595,], -["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20595,], -["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20595,], -["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20595,], +["appnav.loggedin_LoggedInView_Day_1_en","appnav.loggedin_LoggedInView_Night_1_en",20630,], +["appnav.loggedin_LoggedInView_Day_2_en","appnav.loggedin_LoggedInView_Night_2_en",20630,], +["appnav.loggedin_LoggedInView_Day_3_en","appnav.loggedin_LoggedInView_Night_3_en",20630,], +["features.login.impl.login_LoginModeView_Day_0_en","features.login.impl.login_LoginModeView_Night_0_en",20630,], +["features.login.impl.login_LoginModeView_Day_1_en","features.login.impl.login_LoginModeView_Night_1_en",20630,], +["features.login.impl.login_LoginModeView_Day_2_en","features.login.impl.login_LoginModeView_Night_2_en",20630,], +["features.login.impl.login_LoginModeView_Day_3_en","features.login.impl.login_LoginModeView_Night_3_en",20630,], +["features.login.impl.login_LoginModeView_Day_4_en","features.login.impl.login_LoginModeView_Night_4_en",20630,], +["features.login.impl.login_LoginModeView_Day_5_en","features.login.impl.login_LoginModeView_Night_5_en",20630,], +["features.login.impl.login_LoginModeView_Day_6_en","features.login.impl.login_LoginModeView_Night_6_en",20630,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_0_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_0_en",20630,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_1_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_1_en",20630,], +["features.login.impl.screens.loginpassword_LoginPasswordView_Day_2_en","features.login.impl.screens.loginpassword_LoginPasswordView_Night_2_en",20630,], +["features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Day_0_en","features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Night_0_en",20630,], +["features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Day_1_en","features.login.impl.screens.classic.loginwithclassic_LoginWithClassicView_Night_1_en",20630,], +["features.logout.impl_LogoutView_Day_0_en","features.logout.impl_LogoutView_Night_0_en",20630,], +["features.logout.impl_LogoutView_Day_10_en","features.logout.impl_LogoutView_Night_10_en",20630,], +["features.logout.impl_LogoutView_Day_11_en","features.logout.impl_LogoutView_Night_11_en",20630,], +["features.logout.impl_LogoutView_Day_1_en","features.logout.impl_LogoutView_Night_1_en",20630,], +["features.logout.impl_LogoutView_Day_2_en","features.logout.impl_LogoutView_Night_2_en",20630,], +["features.logout.impl_LogoutView_Day_3_en","features.logout.impl_LogoutView_Night_3_en",20630,], +["features.logout.impl_LogoutView_Day_4_en","features.logout.impl_LogoutView_Night_4_en",20630,], +["features.logout.impl_LogoutView_Day_5_en","features.logout.impl_LogoutView_Night_5_en",20630,], +["features.logout.impl_LogoutView_Day_6_en","features.logout.impl_LogoutView_Night_6_en",20630,], +["features.logout.impl_LogoutView_Day_7_en","features.logout.impl_LogoutView_Night_7_en",20630,], +["features.logout.impl_LogoutView_Day_8_en","features.logout.impl_LogoutView_Night_8_en",20630,], +["features.logout.impl_LogoutView_Day_9_en","features.logout.impl_LogoutView_Night_9_en",20630,], ["libraries.designsystem.components.button_MainActionButton_Buttons_en","",0,], -["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_0_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_0_en",20595,], -["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_1_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_1_en",20595,], -["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_2_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_2_en",20595,], -["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20595,], +["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_0_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_0_en",20630,], +["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_1_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_1_en",20630,], +["features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Day_2_en","features.securityandprivacy.impl.manageauthorizedspaces_ManageAuthorizedSpacesView_Night_2_en",20630,], +["libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en","libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en",20630,], ["libraries.textcomposer.components.markdown_MarkdownTextInput_Day_0_en","libraries.textcomposer.components.markdown_MarkdownTextInput_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_MatrixBadgeAtomInfo_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomInfo_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Day_0_en","libraries.designsystem.atomic.atoms_MatrixBadgeAtomNegative_Night_0_en",0,], @@ -667,26 +676,29 @@ export const screenshots = [ ["libraries.matrix.ui.components_MatrixUserRow_Day_1_en","libraries.matrix.ui.components_MatrixUserRow_Night_1_en",0,], ["libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en","libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en",0,], ["libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en","libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_1_en",0,], -["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en",20595,], -["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_1_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_1_en",20595,], -["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en",20595,], -["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_1_en",20595,], -["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_2_en",20595,], -["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_3_en",20595,], -["libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en","libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en",0,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_0_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_0_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_10_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_10_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_11_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_11_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_12_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_12_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_1_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_1_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_2_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_2_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_3_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_3_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_4_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_4_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_5_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_5_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_6_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_6_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en",20595,], -["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_9_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_9_en",20595,], +["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en",20630,], +["libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_1_en","libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_1_en",20630,], +["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en",20630,], +["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_1_en",20630,], +["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_2_en",20630,], +["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_3_en",20630,], +["libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_4_en","libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_4_en",20630,], +["libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en","libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en",20630,], +["libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en","libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en",20630,], +["libraries.mediaviewer.impl.local.file_MediaFileView_Day_2_en","libraries.mediaviewer.impl.local.file_MediaFileView_Night_2_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_0_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_0_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_10_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_10_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_11_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_11_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_12_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_12_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_1_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_1_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_2_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_2_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_3_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_3_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_4_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_4_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_5_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_5_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_6_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_6_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en",20630,], +["libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_9_en","libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_9_en",20630,], ["libraries.mediaviewer.impl.local.image_MediaImageView_Day_0_en","libraries.mediaviewer.impl.local.image_MediaImageView_Night_0_en",0,], ["libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_0_en","libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_0_en",0,], ["libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_1_en","libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_1_en",0,], @@ -694,10 +706,10 @@ export const screenshots = [ ["libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en","libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_0_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_10_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_en","",20595,], -["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_12_en","",20595,], +["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_en","",20630,], +["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_12_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_13_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_14_en","",20595,], +["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_14_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_15_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_16_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_17_en","",0,], @@ -707,20 +719,20 @@ export const screenshots = [ ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_20_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_21_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_22_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_2_en","",20595,], +["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_2_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_3_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_5_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_en","",0,], +["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_en","",20630,], +["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_0_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_10_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_11_en","",20595,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_12_en","",20595,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_11_en","",20630,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_12_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_13_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_14_en","",20595,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_14_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_15_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_16_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_17_en","",0,], @@ -730,12 +742,12 @@ export const screenshots = [ ["libraries.mediaviewer.impl.viewer_MediaViewerView_20_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_21_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_22_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_2_en","",20595,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_2_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_3_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_4_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_5_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_6_en","",0,], -["libraries.mediaviewer.impl.viewer_MediaViewerView_7_en","",0,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_6_en","",20630,], +["libraries.mediaviewer.impl.viewer_MediaViewerView_7_en","",20630,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_8_en","",0,], ["libraries.mediaviewer.impl.viewer_MediaViewerView_9_en","",0,], ["libraries.designsystem.theme.components_MediumTopAppBar_App_Bars_en","",0,], @@ -744,7 +756,7 @@ export const screenshots = [ ["libraries.textcomposer.mentions_MentionSpanTheme_Day_0_en","libraries.textcomposer.mentions_MentionSpanTheme_Night_0_en",0,], ["libraries.designsystem.theme.components.previews_Menu_Menus_en","",0,], ["features.messages.impl.messagecomposer_MessageComposerViewVoice_Day_0_en","features.messages.impl.messagecomposer_MessageComposerViewVoice_Night_0_en",0,], -["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",20595,], +["features.messages.impl.messagecomposer_MessageComposerView_Day_0_en","features.messages.impl.messagecomposer_MessageComposerView_Night_0_en",20630,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_0_en","features.messages.impl.timeline.components_MessageEventBubble_Night_0_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_1_en","features.messages.impl.timeline.components_MessageEventBubble_Night_1_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_2_en","features.messages.impl.timeline.components_MessageEventBubble_Night_2_en",0,], @@ -753,7 +765,7 @@ export const screenshots = [ ["features.messages.impl.timeline.components_MessageEventBubble_Day_5_en","features.messages.impl.timeline.components_MessageEventBubble_Night_5_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_6_en","features.messages.impl.timeline.components_MessageEventBubble_Night_6_en",0,], ["features.messages.impl.timeline.components_MessageEventBubble_Day_7_en","features.messages.impl.timeline.components_MessageEventBubble_Night_7_en",0,], -["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20595,], +["features.messages.impl.timeline.components_MessageShieldView_Day_0_en","features.messages.impl.timeline.components_MessageShieldView_Night_0_en",20630,], ["features.messages.impl.timeline.components_MessageStateEventContainer_Day_0_en","features.messages.impl.timeline.components_MessageStateEventContainer_Night_0_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButtonAdd_Day_0_en","features.messages.impl.timeline.components_MessagesReactionButtonAdd_Night_0_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButtonExtra_Day_0_en","features.messages.impl.timeline.components_MessagesReactionButtonExtra_Night_0_en",0,], @@ -762,24 +774,24 @@ export const screenshots = [ ["features.messages.impl.timeline.components_MessagesReactionButton_Day_2_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_2_en",0,], ["features.messages.impl.timeline.components_MessagesReactionButton_Day_3_en","features.messages.impl.timeline.components_MessagesReactionButton_Night_3_en",0,], ["features.messages.impl_MessagesViewA11y_en","",0,], -["features.messages.impl.topbars_MessagesViewTopBar_Day_0_en","features.messages.impl.topbars_MessagesViewTopBar_Night_0_en",20595,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20595,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20595,], -["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20595,], -["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20595,], -["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20595,], -["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",20595,], -["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20595,], -["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20595,], -["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20595,], -["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20595,], -["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20595,], -["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20595,], -["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20595,], -["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20595,], -["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20595,], +["features.messages.impl.topbars_MessagesViewTopBar_Day_0_en","features.messages.impl.topbars_MessagesViewTopBar_Night_0_en",20630,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en",20630,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en",20630,], +["features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en","features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en",20630,], +["features.messages.impl_MessagesView_Day_0_en","features.messages.impl_MessagesView_Night_0_en",20630,], +["features.messages.impl_MessagesView_Day_10_en","features.messages.impl_MessagesView_Night_10_en",20630,], +["features.messages.impl_MessagesView_Day_11_en","features.messages.impl_MessagesView_Night_11_en",20630,], +["features.messages.impl_MessagesView_Day_1_en","features.messages.impl_MessagesView_Night_1_en",20630,], +["features.messages.impl_MessagesView_Day_2_en","features.messages.impl_MessagesView_Night_2_en",20630,], +["features.messages.impl_MessagesView_Day_3_en","features.messages.impl_MessagesView_Night_3_en",20630,], +["features.messages.impl_MessagesView_Day_4_en","features.messages.impl_MessagesView_Night_4_en",20630,], +["features.messages.impl_MessagesView_Day_5_en","features.messages.impl_MessagesView_Night_5_en",20630,], +["features.messages.impl_MessagesView_Day_6_en","features.messages.impl_MessagesView_Night_6_en",20630,], +["features.messages.impl_MessagesView_Day_7_en","features.messages.impl_MessagesView_Night_7_en",20630,], +["features.messages.impl_MessagesView_Day_8_en","features.messages.impl_MessagesView_Night_8_en",20630,], +["features.messages.impl_MessagesView_Day_9_en","features.messages.impl_MessagesView_Night_9_en",20630,], ["features.migration.impl_MigrationView_Day_0_en","features.migration.impl_MigrationView_Night_0_en",0,], -["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",20595,], +["features.migration.impl_MigrationView_Day_1_en","features.migration.impl_MigrationView_Night_1_en",20630,], ["features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Day_0_en","features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Night_0_en",0,], ["libraries.designsystem.theme.components_ModalBottomSheetDark_Bottom_Sheets_en","",0,], ["libraries.designsystem.theme.components_ModalBottomSheetLight_Bottom_Sheets_en","",0,], @@ -790,117 +802,128 @@ export const screenshots = [ ["libraries.designsystem.components.list_MutipleSelectionListItemSelected_Multiple_selection_List_item_-_selection_in_supporting_text_List_items_en","",0,], ["libraries.designsystem.components.list_MutipleSelectionListItem_Multiple_selection_List_item_-_no_selection_List_items_en","",0,], ["libraries.designsystem.theme.components_NavigationBar_App_Bars_en","",0,], -["features.home.impl.components_NewNotificationSoundBanner_Day_0_en","features.home.impl.components_NewNotificationSoundBanner_Night_0_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_13_en","features.preferences.impl.notifications_NotificationSettingsView_Night_13_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20595,], -["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20595,], -["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20595,], +["features.home.impl.components_NewNotificationSoundBanner_Day_0_en","features.home.impl.components_NewNotificationSoundBanner_Night_0_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_0_en","features.preferences.impl.notifications_NotificationSettingsView_Night_0_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_10_en","features.preferences.impl.notifications_NotificationSettingsView_Night_10_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_11_en","features.preferences.impl.notifications_NotificationSettingsView_Night_11_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_12_en","features.preferences.impl.notifications_NotificationSettingsView_Night_12_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_13_en","features.preferences.impl.notifications_NotificationSettingsView_Night_13_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_14_en","features.preferences.impl.notifications_NotificationSettingsView_Night_14_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_15_en","features.preferences.impl.notifications_NotificationSettingsView_Night_15_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_16_en","features.preferences.impl.notifications_NotificationSettingsView_Night_16_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_17_en","features.preferences.impl.notifications_NotificationSettingsView_Night_17_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_18_en","features.preferences.impl.notifications_NotificationSettingsView_Night_18_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_19_en","features.preferences.impl.notifications_NotificationSettingsView_Night_19_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_1_en","features.preferences.impl.notifications_NotificationSettingsView_Night_1_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_20_en","features.preferences.impl.notifications_NotificationSettingsView_Night_20_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_2_en","features.preferences.impl.notifications_NotificationSettingsView_Night_2_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_3_en","features.preferences.impl.notifications_NotificationSettingsView_Night_3_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_4_en","features.preferences.impl.notifications_NotificationSettingsView_Night_4_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_5_en","features.preferences.impl.notifications_NotificationSettingsView_Night_5_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_6_en","features.preferences.impl.notifications_NotificationSettingsView_Night_6_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_7_en","features.preferences.impl.notifications_NotificationSettingsView_Night_7_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_8_en","features.preferences.impl.notifications_NotificationSettingsView_Night_8_en",20630,], +["features.preferences.impl.notifications_NotificationSettingsView_Day_9_en","features.preferences.impl.notifications_NotificationSettingsView_Night_9_en",20630,], +["features.ftue.impl.notifications_NotificationsOptInView_Day_0_en","features.ftue.impl.notifications_NotificationsOptInView_Night_0_en",20630,], ["features.linknewdevice.impl.screens.number.component_NumberTextField_Day_0_en","features.linknewdevice.impl.screens.number.component_NumberTextField_Night_0_en",0,], ["libraries.designsystem.atomic.pages_OnBoardingPage_Day_0_en","libraries.designsystem.atomic.pages_OnBoardingPage_Night_0_en",0,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_0_en","features.login.impl.screens.onboarding_OnBoardingView_Night_0_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_1_en","features.login.impl.screens.onboarding_OnBoardingView_Night_1_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_2_en","features.login.impl.screens.onboarding_OnBoardingView_Night_2_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_3_en","features.login.impl.screens.onboarding_OnBoardingView_Night_3_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_4_en","features.login.impl.screens.onboarding_OnBoardingView_Night_4_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_5_en","features.login.impl.screens.onboarding_OnBoardingView_Night_5_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_6_en","features.login.impl.screens.onboarding_OnBoardingView_Night_6_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_7_en","features.login.impl.screens.onboarding_OnBoardingView_Night_7_en",20595,], -["features.login.impl.screens.onboarding_OnBoardingView_Day_8_en","features.login.impl.screens.onboarding_OnBoardingView_Night_8_en",20595,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_0_en","features.login.impl.screens.onboarding_OnBoardingView_Night_0_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_1_en","features.login.impl.screens.onboarding_OnBoardingView_Night_1_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_2_en","features.login.impl.screens.onboarding_OnBoardingView_Night_2_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_3_en","features.login.impl.screens.onboarding_OnBoardingView_Night_3_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_4_en","features.login.impl.screens.onboarding_OnBoardingView_Night_4_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_5_en","features.login.impl.screens.onboarding_OnBoardingView_Night_5_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_6_en","features.login.impl.screens.onboarding_OnBoardingView_Night_6_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_7_en","features.login.impl.screens.onboarding_OnBoardingView_Night_7_en",20630,], +["features.login.impl.screens.onboarding_OnBoardingView_Day_8_en","features.login.impl.screens.onboarding_OnBoardingView_Night_8_en",20630,], ["libraries.designsystem.background_OnboardingBackground_Day_0_en","libraries.designsystem.background_OnboardingBackground_Night_0_en",0,], -["libraries.matrix.ui.components_OrganizationHeader_Day_0_en","libraries.matrix.ui.components_OrganizationHeader_Night_0_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_0_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_0_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_10_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_10_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_11_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_11_en",20595,], +["libraries.matrix.ui.components_OrganizationHeader_Day_0_en","libraries.matrix.ui.components_OrganizationHeader_Night_0_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_0_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_0_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_10_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_10_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_11_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_11_en",20630,], ["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_12_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_12_en",0,], ["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_13_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_13_en",0,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_1_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_1_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_2_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_2_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_3_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_3_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_4_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_4_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_5_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_5_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_6_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_6_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_7_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_7_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_8_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_8_en",20595,], -["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_9_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_9_en",20595,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_1_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_1_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_2_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_2_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_3_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_3_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_4_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_4_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_5_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_5_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_6_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_6_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_7_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_7_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_8_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_8_en",20630,], +["features.verifysession.impl.outgoing_OutgoingVerificationView_Day_9_en","features.verifysession.impl.outgoing_OutgoingVerificationView_Night_9_en",20630,], ["libraries.designsystem.theme.components_OutlinedButtonLargeLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonLarge_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonMediumLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonMedium_Buttons_en","",0,], ["libraries.designsystem.theme.components_OutlinedButtonSmall_Buttons_en","",0,], -["libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en",20595,], -["features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Day_0_en","features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Night_0_en",20595,], -["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20595,], -["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20595,], -["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20595,], -["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20595,], +["libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Day_0_en","libraries.mediaviewer.impl.local.pdf_PdfPagesErrorView_Night_0_en",20630,], +["features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Day_0_en","features.rolesandpermissions.impl.roles_PendingMemberRowWithLongName_Night_0_en",20630,], +["libraries.permissions.api_PermissionsView_Day_0_en","libraries.permissions.api_PermissionsView_Night_0_en",20630,], +["libraries.permissions.api_PermissionsView_Day_1_en","libraries.permissions.api_PermissionsView_Night_1_en",20630,], +["libraries.permissions.api_PermissionsView_Day_2_en","libraries.permissions.api_PermissionsView_Night_2_en",20630,], +["libraries.permissions.api_PermissionsView_Day_3_en","libraries.permissions.api_PermissionsView_Night_3_en",20630,], ["features.lockscreen.impl.components_PinEntryTextField_Day_0_en","features.lockscreen.impl.components_PinEntryTextField_Night_0_en",0,], ["features.lockscreen.impl.unlock.keypad_PinKeypad_Day_0_en","features.lockscreen.impl.unlock.keypad_PinKeypad_Night_0_en",0,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_8_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_8_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_9_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_9_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_8_en","features.lockscreen.impl.unlock_PinUnlockView_Night_8_en",20595,], -["features.lockscreen.impl.unlock_PinUnlockView_Day_9_en","features.lockscreen.impl.unlock_PinUnlockView_Night_9_en",20595,], +["features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en","",20633,], +["features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en","",20633,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_0_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_0_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en",20633,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_1_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_1_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_2_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_2_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_3_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_3_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_4_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_4_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_5_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_5_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_6_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_6_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_7_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_7_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_8_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_8_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_9_en","features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_9_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_0_en","features.lockscreen.impl.unlock_PinUnlockView_Night_0_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_10_en","features.lockscreen.impl.unlock_PinUnlockView_Night_10_en",20633,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_1_en","features.lockscreen.impl.unlock_PinUnlockView_Night_1_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_2_en","features.lockscreen.impl.unlock_PinUnlockView_Night_2_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_3_en","features.lockscreen.impl.unlock_PinUnlockView_Night_3_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_4_en","features.lockscreen.impl.unlock_PinUnlockView_Night_4_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_5_en","features.lockscreen.impl.unlock_PinUnlockView_Night_5_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_6_en","features.lockscreen.impl.unlock_PinUnlockView_Night_6_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_7_en","features.lockscreen.impl.unlock_PinUnlockView_Night_7_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_8_en","features.lockscreen.impl.unlock_PinUnlockView_Night_8_en",20630,], +["features.lockscreen.impl.unlock_PinUnlockView_Day_9_en","features.lockscreen.impl.unlock_PinUnlockView_Night_9_en",20630,], ["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_0_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_0_en",0,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_10_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_10_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20595,], -["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20595,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20595,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20595,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20595,], -["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20595,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_10_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_10_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_1_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_1_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_2_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_2_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_3_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_3_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_4_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_4_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_5_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_5_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_6_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_6_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_7_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_7_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_8_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_8_en",20630,], +["features.messages.impl.pinned.banner_PinnedMessagesBannerView_Day_9_en","features.messages.impl.pinned.banner_PinnedMessagesBannerView_Night_9_en",20630,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_0_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_0_en",20630,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_1_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_1_en",20630,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_2_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_2_en",20630,], +["features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en","features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en",20630,], ["libraries.designsystem.atomic.atoms_PlaceholderAtom_Day_0_en","libraries.designsystem.atomic.atoms_PlaceholderAtom_Night_0_en",0,], ["libraries.designsystem.atomic.atoms_PlaybackSpeedButton_Day_0_en","libraries.designsystem.atomic.atoms_PlaybackSpeedButton_Night_0_en",0,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20595,], -["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20595,], -["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20595,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20595,], -["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20595,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en",20630,], +["features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en",20630,], +["features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en",20630,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en",20630,], +["features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en",20630,], ["features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en",0,], ["features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en","features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en",0,], -["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",20595,], -["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20595,], -["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20595,], -["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20595,], -["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20595,], -["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20595,], -["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20595,], -["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20595,], -["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20595,], -["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20595,], -["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20595,], +["features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en",20630,], +["features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en",20630,], +["features.poll.api.pollcontent_PollContentViewCreator_Day_0_en","features.poll.api.pollcontent_PollContentViewCreator_Night_0_en",20630,], +["features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en",20630,], +["features.poll.api.pollcontent_PollContentViewEnded_Day_0_en","features.poll.api.pollcontent_PollContentViewEnded_Night_0_en",20630,], +["features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en","features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en",20630,], +["features.poll.impl.history_PollHistoryView_Day_0_en","features.poll.impl.history_PollHistoryView_Night_0_en",20630,], +["features.poll.impl.history_PollHistoryView_Day_1_en","features.poll.impl.history_PollHistoryView_Night_1_en",20630,], +["features.poll.impl.history_PollHistoryView_Day_2_en","features.poll.impl.history_PollHistoryView_Night_2_en",20630,], +["features.poll.impl.history_PollHistoryView_Day_3_en","features.poll.impl.history_PollHistoryView_Night_3_en",20630,], +["features.poll.impl.history_PollHistoryView_Day_4_en","features.poll.impl.history_PollHistoryView_Night_4_en",20630,], ["features.poll.api.pollcontent_PollTitleView_Day_0_en","features.poll.api.pollcontent_PollTitleView_Night_0_en",0,], ["libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceCheckbox_Preferences_en","",0,], @@ -914,225 +937,227 @@ export const screenshots = [ ["libraries.designsystem.components.preferences_PreferenceRow_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceSlide_Preferences_en","",0,], ["libraries.designsystem.components.preferences_PreferenceSwitch_Preferences_en","",0,], -["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewDark_2_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewDark_3_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewDark_4_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewDark_5_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewLight_2_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewLight_3_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewLight_4_en","",20595,], -["features.preferences.impl.root_PreferencesRootViewLight_5_en","",20595,], +["features.preferences.impl.root_PreferencesRootViewDark_0_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewDark_1_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewDark_2_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewDark_3_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewDark_4_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewDark_5_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewLight_0_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewLight_1_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewLight_2_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewLight_3_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewLight_4_en","",20630,], +["features.preferences.impl.root_PreferencesRootViewLight_5_en","",20630,], ["features.messages.impl.timeline.components.event_ProgressButton_Day_0_en","features.messages.impl.timeline.components.event_ProgressButton_Night_0_en",0,], -["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",20595,], -["libraries.designsystem.components_ProgressDialogWithContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithContent_Night_0_en",20595,], +["libraries.designsystem.components_ProgressDialogContent_Dialogs_en","",20630,], +["libraries.designsystem.components_ProgressDialogWithContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithContent_Night_0_en",20630,], ["libraries.designsystem.components_ProgressDialogWithTextAndContent_Day_0_en","libraries.designsystem.components_ProgressDialogWithTextAndContent_Night_0_en",0,], -["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20595,], -["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",20595,], -["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",20595,], -["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",20595,], -["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",20595,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_0_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_0_en",20595,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en",20595,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_2_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_2_en",20595,], -["libraries.troubleshoot.impl.history_PushHistoryView_Day_3_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_3_en",20595,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20595,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20595,], -["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20595,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20595,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20595,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20595,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20595,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20595,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20595,], -["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20595,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20595,], -["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20595,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20595,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20595,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20595,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20595,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_4_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_4_en",20595,], -["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_5_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_5_en",20595,], +["libraries.designsystem.components_ProgressDialog_Day_0_en","libraries.designsystem.components_ProgressDialog_Night_0_en",20630,], +["features.messages.impl.timeline.protection_ProtectedView_Day_0_en","features.messages.impl.timeline.protection_ProtectedView_Night_0_en",20630,], +["features.messages.impl.timeline.protection_ProtectedView_Day_1_en","features.messages.impl.timeline.protection_ProtectedView_Night_1_en",20630,], +["features.messages.impl.timeline.protection_ProtectedView_Day_2_en","features.messages.impl.timeline.protection_ProtectedView_Night_2_en",20630,], +["features.messages.impl.timeline.protection_ProtectedView_Day_3_en","features.messages.impl.timeline.protection_ProtectedView_Night_3_en",20630,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_0_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_0_en",20630,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en",20630,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_2_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_2_en",20630,], +["libraries.troubleshoot.impl.history_PushHistoryView_Day_3_en","libraries.troubleshoot.impl.history_PushHistoryView_Night_3_en",20630,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en",20630,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en",20630,], +["features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en","features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en",20630,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_0_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_0_en",20630,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_1_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_1_en",20630,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_2_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_2_en",20630,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en",20630,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_4_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_4_en",20630,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en",20630,], +["features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en","features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en",20630,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en",20630,], +["features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en","features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en",20630,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_0_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_0_en",20630,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_1_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_1_en",20630,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_2_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_2_en",20630,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_3_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_3_en",20630,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_4_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_4_en",20630,], +["features.login.impl.screens.qrcode.scan_QrCodeScanView_Day_5_en","features.login.impl.screens.qrcode.scan_QrCodeScanView_Night_5_en",20630,], ["libraries.qrcode_QrCodeView_en","",0,], ["libraries.designsystem.theme.components_RadioButton_Toggles_en","",0,], -["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20595,], -["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20595,], +["features.rageshake.api.detection_RageshakeDialogContent_Day_0_en","features.rageshake.api.detection_RageshakeDialogContent_Night_0_en",20630,], +["features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en",20630,], ["features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en","features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en",0,], ["features.messages.impl.timeline.components.reactionsummary_ReactionSummaryViewContent_Day_0_en","features.messages.impl.timeline.components.reactionsummary_ReactionSummaryViewContent_Night_0_en",0,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",20595,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20595,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20595,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20595,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20595,], -["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_14_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_14_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20595,], -["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20595,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en",20630,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en",20630,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en",20630,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en",20630,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en",20630,], +["features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en","features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_0_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_0_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_10_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_10_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_11_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_11_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_12_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_12_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_13_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_13_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_14_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_14_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_1_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_1_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_2_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_2_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_3_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_3_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_4_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_4_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_5_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_5_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_6_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_6_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_7_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_7_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_8_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_8_en",20630,], +["features.securebackup.impl.setup.views_RecoveryKeyView_Day_9_en","features.securebackup.impl.setup.views_RecoveryKeyView_Night_9_en",20630,], ["libraries.designsystem.atomic.atoms_RedIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_RedIndicatorAtom_Night_0_en",0,], +["features.location.api_RenderingMapsNotSupportedDialog_Day_0_en","features.location.api_RenderingMapsNotSupportedDialog_Night_0_en",20630,], ["features.messages.impl.timeline.components_ReplySwipeIndicator_Day_0_en","features.messages.impl.timeline.components_ReplySwipeIndicator_Night_0_en",0,], -["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",20595,], -["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20595,], -["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20595,], -["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20595,], -["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20595,], -["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20595,], -["features.reportroom.impl_ReportRoomView_Day_0_en","features.reportroom.impl_ReportRoomView_Night_0_en",20595,], -["features.reportroom.impl_ReportRoomView_Day_1_en","features.reportroom.impl_ReportRoomView_Night_1_en",20595,], -["features.reportroom.impl_ReportRoomView_Day_2_en","features.reportroom.impl_ReportRoomView_Night_2_en",20595,], -["features.reportroom.impl_ReportRoomView_Day_3_en","features.reportroom.impl_ReportRoomView_Night_3_en",20595,], -["features.reportroom.impl_ReportRoomView_Day_4_en","features.reportroom.impl_ReportRoomView_Night_4_en",20595,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20595,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20595,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20595,], -["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20595,], -["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20595,], -["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20595,], +["features.messages.impl.report_ReportMessageView_Day_0_en","features.messages.impl.report_ReportMessageView_Night_0_en",20630,], +["features.messages.impl.report_ReportMessageView_Day_1_en","features.messages.impl.report_ReportMessageView_Night_1_en",20630,], +["features.messages.impl.report_ReportMessageView_Day_2_en","features.messages.impl.report_ReportMessageView_Night_2_en",20630,], +["features.messages.impl.report_ReportMessageView_Day_3_en","features.messages.impl.report_ReportMessageView_Night_3_en",20630,], +["features.messages.impl.report_ReportMessageView_Day_4_en","features.messages.impl.report_ReportMessageView_Night_4_en",20630,], +["features.messages.impl.report_ReportMessageView_Day_5_en","features.messages.impl.report_ReportMessageView_Night_5_en",20630,], +["features.reportroom.impl_ReportRoomView_Day_0_en","features.reportroom.impl_ReportRoomView_Night_0_en",20630,], +["features.reportroom.impl_ReportRoomView_Day_1_en","features.reportroom.impl_ReportRoomView_Night_1_en",20630,], +["features.reportroom.impl_ReportRoomView_Day_2_en","features.reportroom.impl_ReportRoomView_Night_2_en",20630,], +["features.reportroom.impl_ReportRoomView_Day_3_en","features.reportroom.impl_ReportRoomView_Night_3_en",20630,], +["features.reportroom.impl_ReportRoomView_Day_4_en","features.reportroom.impl_ReportRoomView_Night_4_en",20630,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en",20630,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en",20630,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en",20630,], +["features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en","features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en",20630,], +["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en",20630,], +["features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en","features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en",20630,], ["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_0_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_0_en",0,], -["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en",20595,], -["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20595,], -["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20595,], -["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en",20595,], -["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en",20595,], +["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en",20630,], +["features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en","features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en",20630,], +["libraries.designsystem.components.dialogs_RetryDialogContent_Dialogs_en","",20630,], +["libraries.designsystem.components.dialogs_RetryDialog_Day_0_en","libraries.designsystem.components.dialogs_RetryDialog_Night_0_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en",20630,], +["features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en","features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en",20630,], ["libraries.matrix.ui.room.address_RoomAddressField_Day_0_en","libraries.matrix.ui.room.address_RoomAddressField_Night_0_en",0,], ["features.roomaliasresolver.impl_RoomAliasResolverView_Day_0_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_0_en",0,], -["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",20595,], -["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20595,], +["features.roomaliasresolver.impl_RoomAliasResolverView_Day_1_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_1_en",20630,], +["features.roomaliasresolver.impl_RoomAliasResolverView_Day_2_en","features.roomaliasresolver.impl_RoomAliasResolverView_Night_2_en",20630,], ["features.roomdetails.impl_RoomDetailsA11y_en","",0,], -["features.roomdetails.impl_RoomDetailsDark_0_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_10_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_11_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_12_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_13_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_14_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_15_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_16_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_17_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_18_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_19_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_1_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_20_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_21_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_22_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_2_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_3_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_4_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_5_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_6_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_7_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_8_en","",20595,], -["features.roomdetails.impl_RoomDetailsDark_9_en","",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_0_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_0_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_1_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_1_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_2_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_2_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_3_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_3_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_4_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_4_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_5_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_5_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_6_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_6_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_7_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_7_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_8_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_8_en",20595,], -["features.roomdetailsedit.impl_RoomDetailsEditView_Day_9_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_9_en",20595,], -["features.roomdetails.impl_RoomDetails_0_en","",20595,], -["features.roomdetails.impl_RoomDetails_10_en","",20595,], -["features.roomdetails.impl_RoomDetails_11_en","",20595,], -["features.roomdetails.impl_RoomDetails_12_en","",20595,], -["features.roomdetails.impl_RoomDetails_13_en","",20595,], -["features.roomdetails.impl_RoomDetails_14_en","",20595,], -["features.roomdetails.impl_RoomDetails_15_en","",20595,], -["features.roomdetails.impl_RoomDetails_16_en","",20595,], -["features.roomdetails.impl_RoomDetails_17_en","",20595,], -["features.roomdetails.impl_RoomDetails_18_en","",20595,], -["features.roomdetails.impl_RoomDetails_19_en","",20595,], -["features.roomdetails.impl_RoomDetails_1_en","",20595,], -["features.roomdetails.impl_RoomDetails_20_en","",20595,], -["features.roomdetails.impl_RoomDetails_21_en","",20595,], -["features.roomdetails.impl_RoomDetails_22_en","",20595,], -["features.roomdetails.impl_RoomDetails_2_en","",20595,], -["features.roomdetails.impl_RoomDetails_3_en","",20595,], -["features.roomdetails.impl_RoomDetails_4_en","",20595,], -["features.roomdetails.impl_RoomDetails_5_en","",20595,], -["features.roomdetails.impl_RoomDetails_6_en","",20595,], -["features.roomdetails.impl_RoomDetails_7_en","",20595,], -["features.roomdetails.impl_RoomDetails_8_en","",20595,], -["features.roomdetails.impl_RoomDetails_9_en","",20595,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20595,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20595,], -["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20595,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20595,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20595,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20595,], -["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",20595,], -["features.home.impl.components_RoomListContentView_Day_0_en","features.home.impl.components_RoomListContentView_Night_0_en",20595,], -["features.home.impl.components_RoomListContentView_Day_1_en","features.home.impl.components_RoomListContentView_Night_1_en",20595,], +["features.roomdetails.impl_RoomDetailsDark_0_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_10_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_11_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_12_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_13_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_14_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_15_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_16_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_17_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_18_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_19_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_1_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_20_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_21_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_22_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_2_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_3_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_4_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_5_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_6_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_7_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_8_en","",20630,], +["features.roomdetails.impl_RoomDetailsDark_9_en","",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_0_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_0_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_1_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_1_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_2_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_2_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_3_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_3_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_4_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_4_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_5_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_5_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_6_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_6_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_7_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_7_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_8_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_8_en",20630,], +["features.roomdetailsedit.impl_RoomDetailsEditView_Day_9_en","features.roomdetailsedit.impl_RoomDetailsEditView_Night_9_en",20630,], +["features.roomdetails.impl_RoomDetails_0_en","",20630,], +["features.roomdetails.impl_RoomDetails_10_en","",20630,], +["features.roomdetails.impl_RoomDetails_11_en","",20630,], +["features.roomdetails.impl_RoomDetails_12_en","",20630,], +["features.roomdetails.impl_RoomDetails_13_en","",20630,], +["features.roomdetails.impl_RoomDetails_14_en","",20630,], +["features.roomdetails.impl_RoomDetails_15_en","",20630,], +["features.roomdetails.impl_RoomDetails_16_en","",20630,], +["features.roomdetails.impl_RoomDetails_17_en","",20630,], +["features.roomdetails.impl_RoomDetails_18_en","",20630,], +["features.roomdetails.impl_RoomDetails_19_en","",20630,], +["features.roomdetails.impl_RoomDetails_1_en","",20630,], +["features.roomdetails.impl_RoomDetails_20_en","",20630,], +["features.roomdetails.impl_RoomDetails_21_en","",20630,], +["features.roomdetails.impl_RoomDetails_22_en","",20630,], +["features.roomdetails.impl_RoomDetails_2_en","",20630,], +["features.roomdetails.impl_RoomDetails_3_en","",20630,], +["features.roomdetails.impl_RoomDetails_4_en","",20630,], +["features.roomdetails.impl_RoomDetails_5_en","",20630,], +["features.roomdetails.impl_RoomDetails_6_en","",20630,], +["features.roomdetails.impl_RoomDetails_7_en","",20630,], +["features.roomdetails.impl_RoomDetails_8_en","",20630,], +["features.roomdetails.impl_RoomDetails_9_en","",20630,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_0_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_0_en",20630,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_1_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_1_en",20630,], +["features.roomdirectory.impl.root_RoomDirectoryView_Day_2_en","features.roomdirectory.impl.root_RoomDirectoryView_Night_2_en",20630,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en",20630,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en",20630,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en",20630,], +["features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en","features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en",20630,], +["features.home.impl.components_RoomListContentView_Day_0_en","features.home.impl.components_RoomListContentView_Night_0_en",20630,], +["features.home.impl.components_RoomListContentView_Day_1_en","features.home.impl.components_RoomListContentView_Night_1_en",20630,], ["features.home.impl.components_RoomListContentView_Day_2_en","features.home.impl.components_RoomListContentView_Night_2_en",0,], -["features.home.impl.components_RoomListContentView_Day_3_en","features.home.impl.components_RoomListContentView_Night_3_en",20595,], -["features.home.impl.components_RoomListContentView_Day_4_en","features.home.impl.components_RoomListContentView_Night_4_en",20595,], -["features.home.impl.components_RoomListContentView_Day_5_en","features.home.impl.components_RoomListContentView_Night_5_en",20595,], -["features.home.impl.roomlist_RoomListContextMenu_Day_0_en","features.home.impl.roomlist_RoomListContextMenu_Night_0_en",20595,], -["features.home.impl.roomlist_RoomListContextMenu_Day_1_en","features.home.impl.roomlist_RoomListContextMenu_Night_1_en",20595,], -["features.home.impl.roomlist_RoomListContextMenu_Day_2_en","features.home.impl.roomlist_RoomListContextMenu_Night_2_en",20595,], -["features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_0_en","features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_0_en",20595,], -["features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_1_en","features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_1_en",20595,], -["features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_2_en","features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_2_en",20595,], -["features.home.impl.filters_RoomListFiltersView_Day_0_en","features.home.impl.filters_RoomListFiltersView_Night_0_en",20595,], -["features.home.impl.filters_RoomListFiltersView_Day_1_en","features.home.impl.filters_RoomListFiltersView_Night_1_en",20595,], +["features.home.impl.components_RoomListContentView_Day_3_en","features.home.impl.components_RoomListContentView_Night_3_en",20630,], +["features.home.impl.components_RoomListContentView_Day_4_en","features.home.impl.components_RoomListContentView_Night_4_en",20630,], +["features.home.impl.components_RoomListContentView_Day_5_en","features.home.impl.components_RoomListContentView_Night_5_en",20630,], +["features.home.impl.roomlist_RoomListContextMenu_Day_0_en","features.home.impl.roomlist_RoomListContextMenu_Night_0_en",20630,], +["features.home.impl.roomlist_RoomListContextMenu_Day_1_en","features.home.impl.roomlist_RoomListContextMenu_Night_1_en",20630,], +["features.home.impl.roomlist_RoomListContextMenu_Day_2_en","features.home.impl.roomlist_RoomListContextMenu_Night_2_en",20630,], +["features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_0_en","features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_0_en",20630,], +["features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_1_en","features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_1_en",20630,], +["features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_2_en","features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_2_en",20630,], +["features.home.impl.filters_RoomListFiltersView_Day_0_en","features.home.impl.filters_RoomListFiltersView_Night_0_en",20630,], +["features.home.impl.filters_RoomListFiltersView_Day_1_en","features.home.impl.filters_RoomListFiltersView_Night_1_en",20630,], ["features.home.impl.search_RoomListSearchContent_Day_0_en","features.home.impl.search_RoomListSearchContent_Night_0_en",0,], -["features.home.impl.search_RoomListSearchContent_Day_1_en","features.home.impl.search_RoomListSearchContent_Night_1_en",20595,], -["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20595,], -["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20595,], -["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20595,], -["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20595,], -["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20595,], -["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",20595,], -["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en",20595,], -["features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en",20595,], +["features.home.impl.search_RoomListSearchContent_Day_1_en","features.home.impl.search_RoomListSearchContent_Night_1_en",20630,], +["features.roomdetails.impl.members_RoomMemberListView_Day_0_en","features.roomdetails.impl.members_RoomMemberListView_Night_0_en",20630,], +["features.roomdetails.impl.members_RoomMemberListView_Day_1_en","features.roomdetails.impl.members_RoomMemberListView_Night_1_en",20630,], +["features.roomdetails.impl.members_RoomMemberListView_Day_2_en","features.roomdetails.impl.members_RoomMemberListView_Night_2_en",20630,], +["features.roomdetails.impl.members_RoomMemberListView_Day_3_en","features.roomdetails.impl.members_RoomMemberListView_Night_3_en",20630,], +["features.roomdetails.impl.members_RoomMemberListView_Day_4_en","features.roomdetails.impl.members_RoomMemberListView_Night_4_en",20630,], +["features.roomdetails.impl.members_RoomMemberListView_Day_5_en","features.roomdetails.impl.members_RoomMemberListView_Night_5_en",20630,], +["features.roomdetails.impl.members_RoomMemberListView_Day_6_en","features.roomdetails.impl.members_RoomMemberListView_Night_6_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en",20630,], +["features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en",20630,], ["features.roommembermoderation.impl_RoomMemberModerationView_Day_9_en","features.roommembermoderation.impl_RoomMemberModerationView_Night_9_en",0,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20595,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20595,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20595,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20595,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20595,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20595,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20595,], -["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20595,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsOption_Night_0_en",20630,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en",20630,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en",20630,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en",20630,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en",20630,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en",20630,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en",20630,], +["features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en","features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en",20630,], ["libraries.designsystem.atomic.atoms_RoomPreviewAliasAtom_Day_0_en","libraries.designsystem.atomic.atoms_RoomPreviewAliasAtom_Night_0_en",0,], -["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20595,], -["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20595,], -["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20595,], -["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20595,], -["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20595,], -["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20595,], +["libraries.roomselect.impl_RoomSelectView_Day_0_en","libraries.roomselect.impl_RoomSelectView_Night_0_en",20630,], +["libraries.roomselect.impl_RoomSelectView_Day_1_en","libraries.roomselect.impl_RoomSelectView_Night_1_en",20630,], +["libraries.roomselect.impl_RoomSelectView_Day_2_en","libraries.roomselect.impl_RoomSelectView_Night_2_en",20630,], +["libraries.roomselect.impl_RoomSelectView_Day_3_en","libraries.roomselect.impl_RoomSelectView_Night_3_en",20630,], +["libraries.roomselect.impl_RoomSelectView_Day_4_en","libraries.roomselect.impl_RoomSelectView_Night_4_en",20630,], +["libraries.roomselect.impl_RoomSelectView_Day_5_en","libraries.roomselect.impl_RoomSelectView_Night_5_en",20630,], +["libraries.roomselect.impl_RoomSelectView_Day_6_en","libraries.roomselect.impl_RoomSelectView_Night_6_en",20633,], ["features.home.impl.components_RoomSummaryPlaceholderRow_Day_0_en","features.home.impl.components_RoomSummaryPlaceholderRow_Night_0_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_0_en","features.home.impl.components_RoomSummaryRow_Night_0_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_10_en","features.home.impl.components_RoomSummaryRow_Night_10_en",0,], @@ -1155,16 +1180,16 @@ export const screenshots = [ ["features.home.impl.components_RoomSummaryRow_Day_26_en","features.home.impl.components_RoomSummaryRow_Night_26_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_27_en","features.home.impl.components_RoomSummaryRow_Night_27_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_28_en","features.home.impl.components_RoomSummaryRow_Night_28_en",0,], -["features.home.impl.components_RoomSummaryRow_Day_29_en","features.home.impl.components_RoomSummaryRow_Night_29_en",20595,], -["features.home.impl.components_RoomSummaryRow_Day_2_en","features.home.impl.components_RoomSummaryRow_Night_2_en",20595,], -["features.home.impl.components_RoomSummaryRow_Day_30_en","features.home.impl.components_RoomSummaryRow_Night_30_en",20595,], -["features.home.impl.components_RoomSummaryRow_Day_31_en","features.home.impl.components_RoomSummaryRow_Night_31_en",20595,], -["features.home.impl.components_RoomSummaryRow_Day_32_en","features.home.impl.components_RoomSummaryRow_Night_32_en",20595,], -["features.home.impl.components_RoomSummaryRow_Day_33_en","features.home.impl.components_RoomSummaryRow_Night_33_en",20595,], -["features.home.impl.components_RoomSummaryRow_Day_34_en","features.home.impl.components_RoomSummaryRow_Night_34_en",20595,], -["features.home.impl.components_RoomSummaryRow_Day_35_en","features.home.impl.components_RoomSummaryRow_Night_35_en",20595,], +["features.home.impl.components_RoomSummaryRow_Day_29_en","features.home.impl.components_RoomSummaryRow_Night_29_en",20630,], +["features.home.impl.components_RoomSummaryRow_Day_2_en","features.home.impl.components_RoomSummaryRow_Night_2_en",20630,], +["features.home.impl.components_RoomSummaryRow_Day_30_en","features.home.impl.components_RoomSummaryRow_Night_30_en",20630,], +["features.home.impl.components_RoomSummaryRow_Day_31_en","features.home.impl.components_RoomSummaryRow_Night_31_en",20630,], +["features.home.impl.components_RoomSummaryRow_Day_32_en","features.home.impl.components_RoomSummaryRow_Night_32_en",20630,], +["features.home.impl.components_RoomSummaryRow_Day_33_en","features.home.impl.components_RoomSummaryRow_Night_33_en",20630,], +["features.home.impl.components_RoomSummaryRow_Day_34_en","features.home.impl.components_RoomSummaryRow_Night_34_en",20630,], +["features.home.impl.components_RoomSummaryRow_Day_35_en","features.home.impl.components_RoomSummaryRow_Night_35_en",20630,], ["features.home.impl.components_RoomSummaryRow_Day_36_en","features.home.impl.components_RoomSummaryRow_Night_36_en",0,], -["features.home.impl.components_RoomSummaryRow_Day_37_en","features.home.impl.components_RoomSummaryRow_Night_37_en",20595,], +["features.home.impl.components_RoomSummaryRow_Day_37_en","features.home.impl.components_RoomSummaryRow_Night_37_en",20630,], ["features.home.impl.components_RoomSummaryRow_Day_38_en","features.home.impl.components_RoomSummaryRow_Night_38_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_3_en","features.home.impl.components_RoomSummaryRow_Night_3_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_4_en","features.home.impl.components_RoomSummaryRow_Night_4_en",0,], @@ -1173,119 +1198,119 @@ export const screenshots = [ ["features.home.impl.components_RoomSummaryRow_Day_7_en","features.home.impl.components_RoomSummaryRow_Night_7_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_8_en","features.home.impl.components_RoomSummaryRow_Night_8_en",0,], ["features.home.impl.components_RoomSummaryRow_Day_9_en","features.home.impl.components_RoomSummaryRow_Night_9_en",0,], +["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20630,], ["features.login.impl.screens.classic.root_RootView_Day_0_en","features.login.impl.screens.classic.root_RootView_Night_0_en",0,], -["appnav.root_RootView_Day_0_en","appnav.root_RootView_Night_0_en",20595,], -["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20595,], -["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20595,], +["appnav.root_RootView_Day_1_en","appnav.root_RootView_Night_1_en",20630,], +["appnav.root_RootView_Day_2_en","appnav.root_RootView_Night_2_en",20630,], ["appicon.element_RoundIcon_en","",0,], ["appicon.enterprise_RoundIcon_en","",0,], ["libraries.designsystem.atomic.atoms_RoundedIconAtom_Day_0_en","libraries.designsystem.atomic.atoms_RoundedIconAtom_Night_0_en",0,], -["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",20595,], -["libraries.designsystem.components.dialogs_SaveChangesDialog_Day_0_en","libraries.designsystem.components.dialogs_SaveChangesDialog_Night_0_en",20595,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_0_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_0_en",20595,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_1_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_1_en",20595,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_2_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_2_en",20595,], -["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_3_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_3_en",20595,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20595,], -["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20595,], +["features.verifysession.impl.emoji_SasEmojis_Day_0_en","features.verifysession.impl.emoji_SasEmojis_Night_0_en",20630,], +["libraries.designsystem.components.dialogs_SaveChangesDialog_Day_0_en","libraries.designsystem.components.dialogs_SaveChangesDialog_Night_0_en",20630,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_0_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_0_en",20630,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_1_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_1_en",20630,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_2_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_2_en",20630,], +["features.linknewdevice.impl.screens.scan_ScanQrCodeView_Day_3_en","features.linknewdevice.impl.screens.scan_ScanQrCodeView_Night_3_en",20630,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_0_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_0_en",20630,], +["features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en","features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en",20630,], ["libraries.designsystem.theme.components_SearchBarActiveNoneQuery_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchBarActiveWithContent_Search_views_en","",0,], -["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search_views_en","",20595,], +["libraries.designsystem.theme.components_SearchBarActiveWithNoResults_Search_views_en","",20630,], ["libraries.designsystem.theme.components_SearchBarActiveWithQueryNoBackButton_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchBarActiveWithQuery_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchBarInactive_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchFieldsDark_Search_views_en","",0,], ["libraries.designsystem.theme.components_SearchFieldsLight_Search_views_en","",0,], -["features.startchat.impl.components_SearchMultipleUsersResultItem_en","",20595,], -["features.startchat.impl.components_SearchSingleUserResultItem_en","",20595,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20595,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20595,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20595,], -["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20595,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20595,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20595,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20595,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20595,], -["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_4_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_4_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20595,], -["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20595,], -["features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_0_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_10_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_11_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_12_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_13_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_14_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_15_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_16_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_17_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_18_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_19_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_1_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_20_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_21_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_22_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_23_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_2_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_3_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_4_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_5_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_6_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_7_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_8_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_9_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_0_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_10_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_11_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_12_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_13_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_14_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_15_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_16_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_17_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_18_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_19_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_1_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_20_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_21_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_22_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_23_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_2_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_3_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_4_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_5_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_6_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_7_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_8_en","",20595,], -["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_9_en","",20595,], -["features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Day_0_en","features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Night_0_en",20595,], +["features.startchat.impl.components_SearchMultipleUsersResultItem_en","",20630,], +["features.startchat.impl.components_SearchSingleUserResultItem_en","",20630,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_0_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_0_en",20630,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_1_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_1_en",20630,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_2_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_2_en",20630,], +["features.securebackup.impl.disable_SecureBackupDisableView_Day_3_en","features.securebackup.impl.disable_SecureBackupDisableView_Night_3_en",20630,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_0_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_0_en",20630,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_1_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_1_en",20630,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_2_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_2_en",20630,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_3_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_3_en",20630,], +["features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Day_4_en","features.securebackup.impl.enter_SecureBackupEnterRecoveryKeyView_Night_4_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_0_en","features.securebackup.impl.root_SecureBackupRootView_Night_0_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_10_en","features.securebackup.impl.root_SecureBackupRootView_Night_10_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_11_en","features.securebackup.impl.root_SecureBackupRootView_Night_11_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_12_en","features.securebackup.impl.root_SecureBackupRootView_Night_12_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_13_en","features.securebackup.impl.root_SecureBackupRootView_Night_13_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_14_en","features.securebackup.impl.root_SecureBackupRootView_Night_14_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_15_en","features.securebackup.impl.root_SecureBackupRootView_Night_15_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_16_en","features.securebackup.impl.root_SecureBackupRootView_Night_16_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_17_en","features.securebackup.impl.root_SecureBackupRootView_Night_17_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_1_en","features.securebackup.impl.root_SecureBackupRootView_Night_1_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_2_en","features.securebackup.impl.root_SecureBackupRootView_Night_2_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_3_en","features.securebackup.impl.root_SecureBackupRootView_Night_3_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_4_en","features.securebackup.impl.root_SecureBackupRootView_Night_4_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_5_en","features.securebackup.impl.root_SecureBackupRootView_Night_5_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_6_en","features.securebackup.impl.root_SecureBackupRootView_Night_6_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_7_en","features.securebackup.impl.root_SecureBackupRootView_Night_7_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_8_en","features.securebackup.impl.root_SecureBackupRootView_Night_8_en",20630,], +["features.securebackup.impl.root_SecureBackupRootView_Day_9_en","features.securebackup.impl.root_SecureBackupRootView_Night_9_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_2_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_3_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_4_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_2_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_2_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_3_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_3_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_4_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_4_en",20630,], +["features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en","features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_0_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_10_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_11_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_12_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_13_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_14_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_15_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_16_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_17_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_18_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_19_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_1_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_20_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_21_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_22_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_23_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_2_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_3_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_4_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_5_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_6_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_7_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_8_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewDark_9_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_0_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_10_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_11_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_12_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_13_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_14_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_15_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_16_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_17_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_18_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_19_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_1_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_20_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_21_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_22_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_23_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_2_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_3_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_4_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_5_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_6_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_7_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_8_en","",20630,], +["features.securityandprivacy.impl.root_SecurityAndPrivacyViewLight_9_en","",20630,], +["features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Day_0_en","features.createroom.impl.configureroom_SelectParentSpaceBottomSheet_Night_0_en",20630,], ["libraries.designsystem.atomic.atoms_SelectedIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_SelectedIndicatorAtom_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedRoomRtl_Day_0_en","libraries.matrix.ui.components_SelectedRoomRtl_Night_0_en",0,], ["libraries.matrix.ui.components_SelectedRoomRtl_Day_1_en","libraries.matrix.ui.components_SelectedRoomRtl_Night_1_en",0,], @@ -1308,38 +1333,39 @@ export const screenshots = [ ["libraries.matrix.ui.messages.sender_SenderName_Day_6_en","libraries.matrix.ui.messages.sender_SenderName_Night_6_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_7_en","libraries.matrix.ui.messages.sender_SenderName_Night_7_en",0,], ["libraries.matrix.ui.messages.sender_SenderName_Day_8_en","libraries.matrix.ui.messages.sender_SenderName_Night_8_en",0,], -["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",20595,], -["features.home.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.home.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20595,], -["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20595,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20595,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20595,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20595,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20595,], -["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20595,], -["features.location.impl.share_ShareLocationView_Day_0_en","features.location.impl.share_ShareLocationView_Night_0_en",20595,], -["features.location.impl.share_ShareLocationView_Day_1_en","features.location.impl.share_ShareLocationView_Night_1_en",20595,], -["features.location.impl.share_ShareLocationView_Day_2_en","features.location.impl.share_ShareLocationView_Night_2_en",20595,], -["features.location.impl.share_ShareLocationView_Day_3_en","features.location.impl.share_ShareLocationView_Night_3_en",20595,], -["features.location.impl.share_ShareLocationView_Day_4_en","features.location.impl.share_ShareLocationView_Night_4_en",20595,], -["features.location.impl.share_ShareLocationView_Day_5_en","features.location.impl.share_ShareLocationView_Night_5_en",20595,], -["features.location.impl.share_ShareLocationView_Day_6_en","features.location.impl.share_ShareLocationView_Night_6_en",20595,], -["features.location.impl.share_ShareLocationView_Day_7_en","features.location.impl.share_ShareLocationView_Night_7_en",20595,], -["features.location.impl.share_ShareLocationView_Day_8_en","features.location.impl.share_ShareLocationView_Night_8_en",20595,], +["features.verifysession.impl.incoming.ui_SessionDetailsView_Day_0_en","features.verifysession.impl.incoming.ui_SessionDetailsView_Night_0_en",20630,], +["features.home.impl.components_SetUpRecoveryKeyBanner_Day_0_en","features.home.impl.components_SetUpRecoveryKeyBanner_Night_0_en",20630,], +["features.lockscreen.impl.setup.biometric_SetupBiometricView_Day_0_en","features.lockscreen.impl.setup.biometric_SetupBiometricView_Night_0_en",20630,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_0_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_0_en",20630,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_1_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_1_en",20630,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_2_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_2_en",20630,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_3_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_3_en",20630,], +["features.lockscreen.impl.setup.pin_SetupPinView_Day_4_en","features.lockscreen.impl.setup.pin_SetupPinView_Night_4_en",20630,], +["features.location.impl.share_ShareLocationView_Day_0_en","features.location.impl.share_ShareLocationView_Night_0_en",20630,], +["features.location.impl.share_ShareLocationView_Day_1_en","features.location.impl.share_ShareLocationView_Night_1_en",20630,], +["features.location.impl.share_ShareLocationView_Day_2_en","features.location.impl.share_ShareLocationView_Night_2_en",20630,], +["features.location.impl.share_ShareLocationView_Day_3_en","features.location.impl.share_ShareLocationView_Night_3_en",20630,], +["features.location.impl.share_ShareLocationView_Day_4_en","features.location.impl.share_ShareLocationView_Night_4_en",20630,], +["features.location.impl.share_ShareLocationView_Day_5_en","features.location.impl.share_ShareLocationView_Night_5_en",20630,], +["features.location.impl.share_ShareLocationView_Day_6_en","features.location.impl.share_ShareLocationView_Night_6_en",20630,], +["features.location.impl.share_ShareLocationView_Day_7_en","features.location.impl.share_ShareLocationView_Night_7_en",20630,], +["features.location.impl.share_ShareLocationView_Day_8_en","features.location.impl.share_ShareLocationView_Night_8_en",20630,], +["features.location.impl.share_ShareLocationView_Day_9_en","features.location.impl.share_ShareLocationView_Night_9_en",20630,], ["features.share.impl_ShareView_Day_0_en","features.share.impl_ShareView_Night_0_en",0,], ["features.share.impl_ShareView_Day_1_en","features.share.impl_ShareView_Night_1_en",0,], ["features.share.impl_ShareView_Day_2_en","features.share.impl_ShareView_Night_2_en",0,], -["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",20595,], -["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20595,], -["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20595,], -["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20595,], -["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20595,], -["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20595,], -["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20595,], -["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20595,], -["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20595,], -["features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en","features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Night_0_en",20595,], -["features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_1_en","features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Night_1_en",20598,], -["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20595,], +["features.share.impl_ShareView_Day_3_en","features.share.impl_ShareView_Night_3_en",20630,], +["features.location.impl.show_ShowLocationView_Day_0_en","features.location.impl.show_ShowLocationView_Night_0_en",20630,], +["features.location.impl.show_ShowLocationView_Day_1_en","features.location.impl.show_ShowLocationView_Night_1_en",20630,], +["features.location.impl.show_ShowLocationView_Day_2_en","features.location.impl.show_ShowLocationView_Night_2_en",20630,], +["features.location.impl.show_ShowLocationView_Day_3_en","features.location.impl.show_ShowLocationView_Night_3_en",20630,], +["features.location.impl.show_ShowLocationView_Day_4_en","features.location.impl.show_ShowLocationView_Night_4_en",20630,], +["features.location.impl.show_ShowLocationView_Day_5_en","features.location.impl.show_ShowLocationView_Night_5_en",20630,], +["features.location.impl.show_ShowLocationView_Day_6_en","features.location.impl.show_ShowLocationView_Night_6_en",20630,], +["features.location.impl.show_ShowLocationView_Day_7_en","features.location.impl.show_ShowLocationView_Night_7_en",20630,], +["features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en","features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Night_0_en",20630,], +["features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_1_en","features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Night_1_en",20630,], +["features.signedout.impl_SignedOutView_Day_0_en","features.signedout.impl_SignedOutView_Night_0_en",20630,], ["libraries.designsystem.components_SimpleModalBottomSheet_Day_0_en","libraries.designsystem.components_SimpleModalBottomSheet_Night_0_en",0,], ["libraries.designsystem.components.dialogs_SingleSelectionDialogContent_Dialogs_en","",0,], ["libraries.designsystem.components.dialogs_SingleSelectionDialog_Day_0_en","libraries.designsystem.components.dialogs_SingleSelectionDialog_Night_0_en",0,], @@ -1349,106 +1375,106 @@ export const screenshots = [ ["libraries.designsystem.components.list_SingleSelectionListItemUnselectedWithSupportingText_Single_selection_List_item_-_no_selection,_supporting_text_List_items_en","",0,], ["libraries.designsystem.components.list_SingleSelectionListItem_Single_selection_List_item_-_no_selection_List_items_en","",0,], ["libraries.designsystem.theme.components_Sliders_Sliders_en","",0,], -["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",20595,], +["features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Day_0_en","features.login.impl.dialogs_SlidingSyncNotSupportedDialog_Night_0_en",20630,], ["libraries.designsystem.theme.components_SnackbarWithActionAndCloseButton_Snackbar_with_action_and_close_button_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithActionOnNewLineAndCloseButton_Snackbar_with_action_and_close_button_on_new_line_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithActionOnNewLine_Snackbar_with_action_on_new_line_Snackbars_en","",0,], ["libraries.designsystem.theme.components_SnackbarWithAction_Snackbar_with_action_Snackbars_en","",0,], ["libraries.designsystem.theme.components_Snackbar_Snackbar_Snackbars_en","",0,], ["libraries.designsystem.components.avatar.internal_SpaceAvatar_Avatars_en","",0,], -["features.home.impl.spacefilters_SpaceFiltersView_Day_0_en","features.home.impl.spacefilters_SpaceFiltersView_Night_0_en",20595,], -["features.home.impl.spacefilters_SpaceFiltersView_Day_1_en","features.home.impl.spacefilters_SpaceFiltersView_Night_1_en",20595,], -["libraries.matrix.ui.components_SpaceHeaderRootView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderRootView_Night_0_en",20595,], -["libraries.matrix.ui.components_SpaceHeaderView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderView_Night_0_en",20595,], -["libraries.matrix.ui.components_SpaceInfoRow_Day_0_en","libraries.matrix.ui.components_SpaceInfoRow_Night_0_en",20595,], +["features.home.impl.spacefilters_SpaceFiltersView_Day_0_en","features.home.impl.spacefilters_SpaceFiltersView_Night_0_en",20630,], +["features.home.impl.spacefilters_SpaceFiltersView_Day_1_en","features.home.impl.spacefilters_SpaceFiltersView_Night_1_en",20630,], +["libraries.matrix.ui.components_SpaceHeaderRootView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderRootView_Night_0_en",20630,], +["libraries.matrix.ui.components_SpaceHeaderView_Day_0_en","libraries.matrix.ui.components_SpaceHeaderView_Night_0_en",20630,], +["libraries.matrix.ui.components_SpaceInfoRow_Day_0_en","libraries.matrix.ui.components_SpaceInfoRow_Night_0_en",20630,], ["libraries.matrix.ui.components_SpaceMembersViewNoHeroes_Day_0_en","libraries.matrix.ui.components_SpaceMembersViewNoHeroes_Night_0_en",0,], ["libraries.matrix.ui.components_SpaceMembersView_Day_0_en","libraries.matrix.ui.components_SpaceMembersView_Night_0_en",0,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en",20595,], -["libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en",20595,], -["features.space.impl.settings_SpaceSettingsView_Day_0_en","features.space.impl.settings_SpaceSettingsView_Night_0_en",20595,], -["features.space.impl.settings_SpaceSettingsView_Day_1_en","features.space.impl.settings_SpaceSettingsView_Night_1_en",20595,], -["features.space.impl.settings_SpaceSettingsView_Day_2_en","features.space.impl.settings_SpaceSettingsView_Night_2_en",20595,], -["features.space.impl.settings_SpaceSettingsView_Day_3_en","features.space.impl.settings_SpaceSettingsView_Night_3_en",20595,], -["features.space.impl.root_SpaceView_Day_0_en","features.space.impl.root_SpaceView_Night_0_en",20595,], -["features.space.impl.root_SpaceView_Day_1_en","features.space.impl.root_SpaceView_Night_1_en",20595,], -["features.space.impl.root_SpaceView_Day_2_en","features.space.impl.root_SpaceView_Night_2_en",20595,], -["features.space.impl.root_SpaceView_Day_3_en","features.space.impl.root_SpaceView_Night_3_en",20595,], -["features.space.impl.root_SpaceView_Day_4_en","features.space.impl.root_SpaceView_Night_4_en",20595,], -["features.space.impl.root_SpaceView_Day_5_en","features.space.impl.root_SpaceView_Night_5_en",20595,], -["features.space.impl.root_SpaceView_Day_6_en","features.space.impl.root_SpaceView_Night_6_en",20595,], -["features.space.impl.root_SpaceView_Day_7_en","features.space.impl.root_SpaceView_Night_7_en",20595,], -["features.space.impl.root_SpaceView_Day_8_en","features.space.impl.root_SpaceView_Night_8_en",20595,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en",20630,], +["libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en","libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en",20630,], +["features.space.impl.settings_SpaceSettingsView_Day_0_en","features.space.impl.settings_SpaceSettingsView_Night_0_en",20630,], +["features.space.impl.settings_SpaceSettingsView_Day_1_en","features.space.impl.settings_SpaceSettingsView_Night_1_en",20630,], +["features.space.impl.settings_SpaceSettingsView_Day_2_en","features.space.impl.settings_SpaceSettingsView_Night_2_en",20630,], +["features.space.impl.settings_SpaceSettingsView_Day_3_en","features.space.impl.settings_SpaceSettingsView_Night_3_en",20630,], +["features.space.impl.root_SpaceView_Day_0_en","features.space.impl.root_SpaceView_Night_0_en",20630,], +["features.space.impl.root_SpaceView_Day_1_en","features.space.impl.root_SpaceView_Night_1_en",20630,], +["features.space.impl.root_SpaceView_Day_2_en","features.space.impl.root_SpaceView_Night_2_en",20630,], +["features.space.impl.root_SpaceView_Day_3_en","features.space.impl.root_SpaceView_Night_3_en",20630,], +["features.space.impl.root_SpaceView_Day_4_en","features.space.impl.root_SpaceView_Night_4_en",20630,], +["features.space.impl.root_SpaceView_Day_5_en","features.space.impl.root_SpaceView_Night_5_en",20630,], +["features.space.impl.root_SpaceView_Day_6_en","features.space.impl.root_SpaceView_Night_6_en",20630,], +["features.space.impl.root_SpaceView_Day_7_en","features.space.impl.root_SpaceView_Night_7_en",20630,], +["features.space.impl.root_SpaceView_Day_8_en","features.space.impl.root_SpaceView_Night_8_en",20630,], ["libraries.designsystem.modifiers_SquareSizeModifierInsideSquare_en","",0,], ["libraries.designsystem.modifiers_SquareSizeModifierLargeHeight_en","",0,], ["libraries.designsystem.modifiers_SquareSizeModifierLargeWidth_en","",0,], -["features.startchat.impl.root_StartChatView_Day_0_en","features.startchat.impl.root_StartChatView_Night_0_en",20595,], -["features.startchat.impl.root_StartChatView_Day_1_en","features.startchat.impl.root_StartChatView_Night_1_en",20595,], -["features.startchat.impl.root_StartChatView_Day_2_en","features.startchat.impl.root_StartChatView_Night_2_en",20595,], -["features.startchat.impl.root_StartChatView_Day_3_en","features.startchat.impl.root_StartChatView_Night_3_en",20595,], -["features.startchat.impl.root_StartChatView_Day_4_en","features.startchat.impl.root_StartChatView_Night_4_en",20595,], -["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",20595,], +["features.startchat.impl.root_StartChatView_Day_0_en","features.startchat.impl.root_StartChatView_Night_0_en",20630,], +["features.startchat.impl.root_StartChatView_Day_1_en","features.startchat.impl.root_StartChatView_Night_1_en",20630,], +["features.startchat.impl.root_StartChatView_Day_2_en","features.startchat.impl.root_StartChatView_Night_2_en",20630,], +["features.startchat.impl.root_StartChatView_Day_3_en","features.startchat.impl.root_StartChatView_Night_3_en",20630,], +["features.startchat.impl.root_StartChatView_Day_4_en","features.startchat.impl.root_StartChatView_Night_4_en",20630,], +["features.location.api.internal_StaticMapPlaceholder_Day_0_en","features.location.api.internal_StaticMapPlaceholder_Night_0_en",20630,], ["features.location.api_StaticMapView_Day_0_en","features.location.api_StaticMapView_Night_0_en",0,], -["features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en","features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en",20595,], +["features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en","features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en",20630,], ["libraries.designsystem.atomic.pages_SunsetPage_Day_0_en","libraries.designsystem.atomic.pages_SunsetPage_Night_0_en",0,], ["libraries.designsystem.components.button_SuperButton_Day_0_en","libraries.designsystem.components.button_SuperButton_Night_0_en",0,], ["libraries.designsystem.theme.components_Surface_en","",0,], ["libraries.designsystem.theme.components_Switch_Toggles_en","",0,], -["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",20595,], +["appnav.loggedin_SyncStateView_Day_0_en","appnav.loggedin_SyncStateView_Night_0_en",20630,], ["libraries.designsystem.components.avatar.internal_TextAvatar_Avatars_en","",0,], ["libraries.designsystem.theme.components_TextButtonLargeLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonLarge_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonMediumLowPadding_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonMedium_Buttons_en","",0,], ["libraries.designsystem.theme.components_TextButtonSmall_Buttons_en","",0,], -["libraries.textcomposer_TextComposerAddCaption_Day_0_en","libraries.textcomposer_TextComposerAddCaption_Night_0_en",20595,], -["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",20595,], -["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20595,], -["libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en",20595,], -["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20595,], -["libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en",20595,], -["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20595,], -["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20595,], -["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20595,], -["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en",20595,], -["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20595,], -["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20595,], -["libraries.textcomposer_TextComposerScaledDensityWithReply_en","",20595,], -["libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en",20595,], -["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20595,], -["libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en",20595,], +["libraries.textcomposer_TextComposerAddCaption_Day_0_en","libraries.textcomposer_TextComposerAddCaption_Night_0_en",20630,], +["libraries.textcomposer_TextComposerCaption_Day_0_en","libraries.textcomposer_TextComposerCaption_Night_0_en",20630,], +["libraries.textcomposer_TextComposerEditCaption_Day_0_en","libraries.textcomposer_TextComposerEditCaption_Night_0_en",20630,], +["libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en",20630,], +["libraries.textcomposer_TextComposerEdit_Day_0_en","libraries.textcomposer_TextComposerEdit_Night_0_en",20630,], +["libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en",20630,], +["libraries.textcomposer_TextComposerFormatting_Day_0_en","libraries.textcomposer_TextComposerFormatting_Night_0_en",20630,], +["libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLinkWithoutText_Night_0_en",20630,], +["libraries.textcomposer_TextComposerLinkDialogCreateLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogCreateLink_Night_0_en",20630,], +["libraries.textcomposer_TextComposerLinkDialogEditLink_Day_0_en","libraries.textcomposer_TextComposerLinkDialogEditLink_Night_0_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en",20630,], +["libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en","libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_0_en","libraries.textcomposer_TextComposerReply_Night_0_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_10_en","libraries.textcomposer_TextComposerReply_Night_10_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_11_en","libraries.textcomposer_TextComposerReply_Night_11_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_1_en","libraries.textcomposer_TextComposerReply_Night_1_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_2_en","libraries.textcomposer_TextComposerReply_Night_2_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_3_en","libraries.textcomposer_TextComposerReply_Night_3_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_4_en","libraries.textcomposer_TextComposerReply_Night_4_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_5_en","libraries.textcomposer_TextComposerReply_Night_5_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_6_en","libraries.textcomposer_TextComposerReply_Night_6_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_7_en","libraries.textcomposer_TextComposerReply_Night_7_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_8_en","libraries.textcomposer_TextComposerReply_Night_8_en",20630,], +["libraries.textcomposer_TextComposerReply_Day_9_en","libraries.textcomposer_TextComposerReply_Night_9_en",20630,], +["libraries.textcomposer_TextComposerScaledDensityWithReply_en","",20630,], +["libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en",20630,], +["libraries.textcomposer_TextComposerSimple_Day_0_en","libraries.textcomposer_TextComposerSimple_Night_0_en",20630,], +["libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en","libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en",20630,], ["libraries.textcomposer_TextComposerVoice_Day_0_en","libraries.textcomposer_TextComposerVoice_Night_0_en",0,], ["libraries.designsystem.theme.components_TextDark_Text_en","",0,], -["libraries.designsystem.components.dialogs_TextFieldDialogWithError_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialogWithError_Night_0_en",20595,], -["libraries.designsystem.components.dialogs_TextFieldDialog_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialog_Night_0_en",20595,], +["libraries.designsystem.components.dialogs_TextFieldDialogWithError_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialogWithError_Night_0_en",20630,], +["libraries.designsystem.components.dialogs_TextFieldDialog_Day_0_en","libraries.designsystem.components.dialogs_TextFieldDialog_Night_0_en",20630,], ["libraries.designsystem.components.list_TextFieldListItemEmpty_Text_field_List_item_-_empty_List_items_en","",0,], ["libraries.designsystem.components.list_TextFieldListItemTextFieldValue_Text_field_List_item_-_textfieldvalue_List_items_en","",0,], ["libraries.designsystem.components.list_TextFieldListItem_Text_field_List_item_-_text_List_items_en","",0,], @@ -1461,103 +1487,103 @@ export const screenshots = [ ["libraries.textcomposer.components_TextFormatting_Day_0_en","libraries.textcomposer.components_TextFormatting_Night_0_en",0,], ["libraries.designsystem.theme.components_TextLight_Text_en","",0,], ["features.messages.impl.threads.list_ThreadListItemRow_Day_0_en","features.messages.impl.threads.list_ThreadListItemRow_Night_0_en",0,], -["features.messages.impl.timeline.components_ThreadSummaryView_Day_0_en","features.messages.impl.timeline.components_ThreadSummaryView_Night_0_en",20595,], -["features.messages.impl.topbars_ThreadTopBar_Day_0_en","features.messages.impl.topbars_ThreadTopBar_Night_0_en",20595,], +["features.messages.impl.timeline.components_ThreadSummaryView_Day_0_en","features.messages.impl.timeline.components_ThreadSummaryView_Night_0_en",20630,], +["features.messages.impl.topbars_ThreadTopBar_Day_0_en","features.messages.impl.topbars_ThreadTopBar_Night_0_en",20630,], ["features.messages.impl.threads.list_ThreadsListView_Day_0_en","features.messages.impl.threads.list_ThreadsListView_Night_0_en",0,], -["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20595,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20595,], -["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20595,], +["libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en","",20630,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en","",20630,], +["libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en","",20630,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_0_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_1_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_2_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",20595,], -["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20595,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_3_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_3_en",20630,], +["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_4_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_4_en",20630,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_5_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_5_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_6_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_6_en",0,], ["features.messages.impl.timeline.components_TimelineEventTimestampView_Day_7_en","features.messages.impl.timeline.components_TimelineEventTimestampView_Night_7_en",0,], -["features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en",0,], +["features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Night_0_en",20633,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_4_en",0,], -["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",20595,], +["features.messages.impl.timeline.components_TimelineItemCallNotifyView_Day_0_en","features.messages.impl.timeline.components_TimelineItemCallNotifyView_Night_0_en",20630,], ["features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Night_0_en",0,], ["features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Day_1_en","features.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_Night_1_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_8_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_8_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en",0,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_0_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_1_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_5_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_6_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_6_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_7_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_7_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_8_en","features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_8_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en",20633,], ["features.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowForDirectRoom_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowLongSenderName_en","",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowShield_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowShield_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20595,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_3_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_4_en",20630,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_5_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_5_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_6_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_6_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_7_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20595,], +["features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowTimestamp_Night_7_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithManyReactions_Night_0_en",20630,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_0_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_1_en",0,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithRR_Night_2_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en",0,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en",20633,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en",20630,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en",0,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en",20633,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en",20630,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en",0,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en",20633,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en",20630,], ["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",20595,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en",20595,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en",20630,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en","features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en",20633,], +["features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRowWithThreadSummary_Night_0_en",20630,], ["features.messages.impl.timeline.components_TimelineItemEventRow_Day_0_en","features.messages.impl.timeline.components_TimelineItemEventRow_Night_0_en",0,], -["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",20595,], +["features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en","",20630,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemFileView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemFileView_Night_4_en",0,], -["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",20595,], -["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",20595,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentCollapse_Night_0_en",20630,], +["features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Day_0_en","features.messages.impl.timeline.components_TimelineItemGroupedEventsRowContentExpanded_Night_0_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageViewHideMediaContent_Night_0_en",20630,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_2_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemImageView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemImageView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemInformativeView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemInformativeView_Night_0_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",20595,], +["features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLegacyCallInviteView_Night_0_en",20630,], ["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_0_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_2_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_3_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_4_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20595,], -["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20595,], +["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_2_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_3_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_4_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en",20630,], +["features.messages.impl.timeline.components_TimelineItemReactionsLayout_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsLayout_Night_0_en",20630,], ["features.messages.impl.timeline.components_TimelineItemReactionsViewFew_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewFew_Night_0_en",0,], -["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",20595,], -["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20595,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewIncoming_Night_0_en",20630,], +["features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsViewOutgoing_Night_0_en",20630,], ["features.messages.impl.timeline.components_TimelineItemReactionsView_Day_0_en","features.messages.impl.timeline.components_TimelineItemReactionsView_Night_0_en",0,], -["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",20595,], +["features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en",20630,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_0_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_0_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_1_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_1_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_2_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_2_en",0,], @@ -1566,8 +1592,8 @@ export const screenshots = [ ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_5_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_5_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_6_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_6_en",0,], ["features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Day_7_en","features.messages.impl.timeline.components.receipt_TimelineItemReadReceiptView_Night_7_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",20595,], -["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20595,], +["features.messages.impl.timeline.components.event_TimelineItemRedactedView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemRedactedView_Night_0_en",20630,], +["features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_Night_0_en",20630,], ["features.messages.impl.timeline.components_TimelineItemStateEventRow_Day_0_en","features.messages.impl.timeline.components_TimelineItemStateEventRow_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemStateView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemStateView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemStickerView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemStickerView_Night_0_en",0,], @@ -1582,8 +1608,8 @@ export const screenshots = [ ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_3_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_3_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_4_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_4_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemTextView_Day_5_en","features.messages.impl.timeline.components.event_TimelineItemTextView_Night_5_en",0,], -["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",20595,], -["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",20595,], +["features.messages.impl.timeline.components.event_TimelineItemUnknownView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemUnknownView_Night_0_en",20630,], +["features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoViewHideMediaContent_Night_0_en",20630,], ["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_0_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_0_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_1_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_1_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemVideoView_Day_2_en","features.messages.impl.timeline.components.event_TimelineItemVideoView_Night_2_en",0,], @@ -1605,85 +1631,85 @@ export const screenshots = [ ["features.messages.impl.timeline.components.event_TimelineItemVoiceView_Day_8_en","features.messages.impl.timeline.components.event_TimelineItemVoiceView_Night_8_en",0,], ["features.messages.impl.timeline.components.event_TimelineItemVoiceView_Day_9_en","features.messages.impl.timeline.components.event_TimelineItemVoiceView_Night_9_en",0,], ["features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Day_0_en","features.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_Night_0_en",0,], -["features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en",0,], -["features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en","features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_10_en","features.messages.impl.timeline_TimelineView_Night_10_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20595,], -["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20595,], +["features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en","features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Night_0_en",20633,], +["features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en","features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_0_en","features.messages.impl.timeline_TimelineView_Night_0_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_10_en","features.messages.impl.timeline_TimelineView_Night_10_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_11_en","features.messages.impl.timeline_TimelineView_Night_11_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_12_en","features.messages.impl.timeline_TimelineView_Night_12_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_13_en","features.messages.impl.timeline_TimelineView_Night_13_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_14_en","features.messages.impl.timeline_TimelineView_Night_14_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_15_en","features.messages.impl.timeline_TimelineView_Night_15_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_16_en","features.messages.impl.timeline_TimelineView_Night_16_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_17_en","features.messages.impl.timeline_TimelineView_Night_17_en",20630,], +["features.messages.impl.timeline_TimelineView_Day_1_en","features.messages.impl.timeline_TimelineView_Night_1_en",20630,], ["features.messages.impl.timeline_TimelineView_Day_2_en","features.messages.impl.timeline_TimelineView_Night_2_en",0,], ["features.messages.impl.timeline_TimelineView_Day_3_en","features.messages.impl.timeline_TimelineView_Night_3_en",0,], -["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",20595,], +["features.messages.impl.timeline_TimelineView_Day_4_en","features.messages.impl.timeline_TimelineView_Night_4_en",20630,], ["features.messages.impl.timeline_TimelineView_Day_5_en","features.messages.impl.timeline_TimelineView_Night_5_en",0,], -["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",20595,], +["features.messages.impl.timeline_TimelineView_Day_6_en","features.messages.impl.timeline_TimelineView_Night_6_en",20630,], ["features.messages.impl.timeline_TimelineView_Day_7_en","features.messages.impl.timeline_TimelineView_Night_7_en",0,], ["features.messages.impl.timeline_TimelineView_Day_8_en","features.messages.impl.timeline_TimelineView_Night_8_en",0,], ["features.messages.impl.timeline_TimelineView_Day_9_en","features.messages.impl.timeline_TimelineView_Night_9_en",0,], ["libraries.designsystem.components.avatar.internal_TombstonedRoomAvatar_Avatars_en","",0,], ["libraries.designsystem.theme.components_TopAppBarStr_App_Bars_en","",0,], ["libraries.designsystem.theme.components_TopAppBar_App_Bars_en","",0,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20595,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20595,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20595,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20595,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20595,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20595,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20595,], -["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20595,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_0_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_0_en",20630,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_1_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_1_en",20630,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_2_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_2_en",20630,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_3_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_3_en",20630,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_4_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_4_en",20630,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_5_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_5_en",20630,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_6_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_6_en",20630,], +["libraries.troubleshoot.impl_TroubleshootNotificationsView_Day_7_en","libraries.troubleshoot.impl_TroubleshootNotificationsView_Night_7_en",20630,], ["features.messages.impl.typing_TypingNotificationView_Day_0_en","features.messages.impl.typing_TypingNotificationView_Night_0_en",0,], -["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",20595,], -["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20595,], -["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20595,], -["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20595,], -["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20595,], -["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20595,], +["features.messages.impl.typing_TypingNotificationView_Day_1_en","features.messages.impl.typing_TypingNotificationView_Night_1_en",20630,], +["features.messages.impl.typing_TypingNotificationView_Day_2_en","features.messages.impl.typing_TypingNotificationView_Night_2_en",20630,], +["features.messages.impl.typing_TypingNotificationView_Day_3_en","features.messages.impl.typing_TypingNotificationView_Night_3_en",20630,], +["features.messages.impl.typing_TypingNotificationView_Day_4_en","features.messages.impl.typing_TypingNotificationView_Night_4_en",20630,], +["features.messages.impl.typing_TypingNotificationView_Day_5_en","features.messages.impl.typing_TypingNotificationView_Night_5_en",20630,], +["features.messages.impl.typing_TypingNotificationView_Day_6_en","features.messages.impl.typing_TypingNotificationView_Night_6_en",20630,], ["features.messages.impl.typing_TypingNotificationView_Day_7_en","features.messages.impl.typing_TypingNotificationView_Night_7_en",0,], ["features.messages.impl.typing_TypingNotificationView_Day_8_en","features.messages.impl.typing_TypingNotificationView_Night_8_en",0,], ["libraries.designsystem.atomic.atoms_UnreadIndicatorAtom_Day_0_en","libraries.designsystem.atomic.atoms_UnreadIndicatorAtom_Night_0_en",0,], -["libraries.matrix.ui.components_UnresolvedUserRow_en","",20595,], +["libraries.matrix.ui.components_UnresolvedUserRow_en","",20630,], ["libraries.designsystem.components.avatar.internal_UserAvatarColors_Day_0_en","libraries.designsystem.components.avatar.internal_UserAvatarColors_Night_0_en",0,], -["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20595,], -["features.startchat.impl.components_UserListView_Day_0_en","features.startchat.impl.components_UserListView_Night_0_en",20595,], -["features.startchat.impl.components_UserListView_Day_1_en","features.startchat.impl.components_UserListView_Night_1_en",20595,], -["features.startchat.impl.components_UserListView_Day_2_en","features.startchat.impl.components_UserListView_Night_2_en",20595,], +["features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Day_0_en","features.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettingsView_Night_0_en",20630,], +["features.startchat.impl.components_UserListView_Day_0_en","features.startchat.impl.components_UserListView_Night_0_en",20630,], +["features.startchat.impl.components_UserListView_Day_1_en","features.startchat.impl.components_UserListView_Night_1_en",20630,], +["features.startchat.impl.components_UserListView_Day_2_en","features.startchat.impl.components_UserListView_Night_2_en",20630,], ["features.startchat.impl.components_UserListView_Day_3_en","features.startchat.impl.components_UserListView_Night_3_en",0,], ["features.startchat.impl.components_UserListView_Day_4_en","features.startchat.impl.components_UserListView_Night_4_en",0,], ["features.startchat.impl.components_UserListView_Day_5_en","features.startchat.impl.components_UserListView_Night_5_en",0,], ["features.startchat.impl.components_UserListView_Day_6_en","features.startchat.impl.components_UserListView_Night_6_en",0,], -["features.startchat.impl.components_UserListView_Day_7_en","features.startchat.impl.components_UserListView_Night_7_en",20595,], +["features.startchat.impl.components_UserListView_Day_7_en","features.startchat.impl.components_UserListView_Night_7_en",20630,], ["features.startchat.impl.components_UserListView_Day_8_en","features.startchat.impl.components_UserListView_Night_8_en",0,], -["features.startchat.impl.components_UserListView_Day_9_en","features.startchat.impl.components_UserListView_Night_9_en",20595,], +["features.startchat.impl.components_UserListView_Day_9_en","features.startchat.impl.components_UserListView_Night_9_en",20630,], ["features.preferences.impl.user_UserPreferences_Day_0_en","features.preferences.impl.user_UserPreferences_Night_0_en",0,], ["features.preferences.impl.user_UserPreferences_Day_1_en","features.preferences.impl.user_UserPreferences_Night_1_en",0,], -["features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Day_0_en","features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Night_0_en",20595,], -["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",20595,], -["features.userprofile.shared_UserProfileMainActionsSection_Day_0_en","features.userprofile.shared_UserProfileMainActionsSection_Night_0_en",20595,], -["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20595,], -["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20595,], -["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20595,], -["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20595,], -["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20595,], -["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20595,], -["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20595,], -["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20595,], -["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",20595,], -["features.userprofile.shared_UserProfileView_Day_9_en","features.userprofile.shared_UserProfileView_Night_9_en",20595,], +["features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Day_0_en","features.userprofile.shared_UserProfileHeaderSectionWithVerificationViolation_Night_0_en",20630,], +["features.userprofile.shared_UserProfileHeaderSection_Day_0_en","features.userprofile.shared_UserProfileHeaderSection_Night_0_en",20630,], +["features.userprofile.shared_UserProfileMainActionsSection_Day_0_en","features.userprofile.shared_UserProfileMainActionsSection_Night_0_en",20630,], +["features.userprofile.shared_UserProfileView_Day_0_en","features.userprofile.shared_UserProfileView_Night_0_en",20630,], +["features.userprofile.shared_UserProfileView_Day_1_en","features.userprofile.shared_UserProfileView_Night_1_en",20630,], +["features.userprofile.shared_UserProfileView_Day_2_en","features.userprofile.shared_UserProfileView_Night_2_en",20630,], +["features.userprofile.shared_UserProfileView_Day_3_en","features.userprofile.shared_UserProfileView_Night_3_en",20630,], +["features.userprofile.shared_UserProfileView_Day_4_en","features.userprofile.shared_UserProfileView_Night_4_en",20630,], +["features.userprofile.shared_UserProfileView_Day_5_en","features.userprofile.shared_UserProfileView_Night_5_en",20630,], +["features.userprofile.shared_UserProfileView_Day_6_en","features.userprofile.shared_UserProfileView_Night_6_en",20630,], +["features.userprofile.shared_UserProfileView_Day_7_en","features.userprofile.shared_UserProfileView_Night_7_en",20630,], +["features.userprofile.shared_UserProfileView_Day_8_en","features.userprofile.shared_UserProfileView_Night_8_en",20630,], +["features.userprofile.shared_UserProfileView_Day_9_en","features.userprofile.shared_UserProfileView_Night_9_en",20630,], ["features.verifysession.impl.ui_VerificationUserProfileContent_Day_0_en","features.verifysession.impl.ui_VerificationUserProfileContent_Night_0_en",0,], ["libraries.designsystem.ruler_VerticalRuler_Day_0_en","libraries.designsystem.ruler_VerticalRuler_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_VideoItemView_Day_0_en","libraries.mediaviewer.impl.gallery.ui_VideoItemView_Night_0_en",0,], ["libraries.mediaviewer.impl.gallery.ui_VideoItemView_Day_1_en","libraries.mediaviewer.impl.gallery.ui_VideoItemView_Night_1_en",0,], -["features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_en","features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Night_0_en",20595,], -["features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_en","features.preferences.impl.advanced_VideoQualitySelectorDialog_Night_0_en",20595,], +["features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Day_0_en","features.messages.impl.attachments.preview_VideoQualitySelectorDialog_Night_0_en",20630,], +["features.preferences.impl.advanced_VideoQualitySelectorDialog_Day_0_en","features.preferences.impl.advanced_VideoQualitySelectorDialog_Night_0_en",20630,], ["features.viewfolder.impl.file_ViewFileView_Day_0_en","features.viewfolder.impl.file_ViewFileView_Night_0_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_1_en","features.viewfolder.impl.file_ViewFileView_Night_1_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_2_en","features.viewfolder.impl.file_ViewFileView_Night_2_en",0,], -["features.viewfolder.impl.file_ViewFileView_Day_3_en","features.viewfolder.impl.file_ViewFileView_Night_3_en",20595,], +["features.viewfolder.impl.file_ViewFileView_Day_3_en","features.viewfolder.impl.file_ViewFileView_Night_3_en",20630,], ["features.viewfolder.impl.file_ViewFileView_Day_4_en","features.viewfolder.impl.file_ViewFileView_Night_4_en",0,], ["features.viewfolder.impl.file_ViewFileView_Day_5_en","features.viewfolder.impl.file_ViewFileView_Night_5_en",0,], ["features.viewfolder.impl.folder_ViewFolderView_Day_0_en","features.viewfolder.impl.folder_ViewFolderView_Night_0_en",0,], diff --git a/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProvider.kt b/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProvider.kt index 0843c97a78..4e4f08b632 100644 --- a/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProvider.kt +++ b/services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProvider.kt @@ -33,7 +33,6 @@ import io.sentry.Sentry import io.sentry.SentryOptions import io.sentry.android.core.SentryAndroid import io.sentry.protocol.SentryTransaction -import kotlinx.coroutines.runBlocking import timber.log.Timber @ContributesIntoSet(AppScope::class) @@ -132,7 +131,7 @@ class SentryAnalyticsProvider( if (sessionId != null) { // This runs in a separate thread, so although using `runBlocking` is not great, at least it shouldn't freeze the app // Also, the method is fairly quick, so the blocking shouldn't take longer than a few ms - val databaseSizes = runBlocking { getDatabaseSizesUseCase(sessionId) }.getOrNull() + val databaseSizes = getDatabaseSizesUseCase(sessionId).getOrNull() databaseSizes?.stateStore?.let { transaction.setExtra(AnalyticsUserData.STATE_STORE_SIZE, it.into(ByteUnit.MB)) } databaseSizes?.eventCacheStore?.let { transaction.setExtra(AnalyticsUserData.EVENT_CACHE_SIZE, it.into(ByteUnit.MB)) } diff --git a/services/analyticsproviders/sentry/src/test/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProviderTest.kt b/services/analyticsproviders/sentry/src/test/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProviderTest.kt index a8dc9f3086..ae1ac82dda 100644 --- a/services/analyticsproviders/sentry/src/test/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProviderTest.kt +++ b/services/analyticsproviders/sentry/src/test/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProviderTest.kt @@ -9,7 +9,6 @@ package io.element.android.services.analyticsproviders.sentry -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.itf.VectorAnalyticsEvent @@ -27,15 +26,14 @@ import io.element.android.services.analyticsproviders.api.AnalyticsUserData import io.element.android.services.appnavstate.api.AppNavigationState import io.element.android.services.appnavstate.api.NavigationState import io.element.android.services.appnavstate.test.FakeAppNavigationStateService +import io.element.android.tests.testutils.robolectric.RobolectricTest import io.sentry.Sentry import io.sentry.SentryTracer import io.sentry.protocol.SentryId import io.sentry.protocol.SentryTransaction import org.junit.Test -import org.junit.runner.RunWith -@RunWith(AndroidJUnit4::class) -class SentryAnalyticsProviderTest { +class SentryAnalyticsProviderTest : RobolectricTest() { @Test fun `init enables Sentry if DSN is present`() { createSentryAnalyticsProvider().run { diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt index 631def9f75..93b3200acc 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt @@ -140,7 +140,10 @@ class KonsistClassNameTest { Konsist.scopeFromProject() .classes() .withNameEndingWith("Impl") - .withoutName("MediaUploadHandlerImpl") + .withoutName( + "MediaUploadHandlerImpl", + "GalleryMediaUploadHandlerImpl", + ) .assertEmpty(additionalMessage = "Class implementing interface should have name not end with 'Impl' but start with 'Default'") } diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt index ddd1082ace..fdb4e27ef0 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt @@ -150,6 +150,7 @@ class KonsistPreviewTest { "TimelineItemEventRowShieldPreview", "TimelineItemEventRowTimestampPreview", "TimelineItemEventRowUtdPreview", + "TimelineItemEventRowWithGalleryPreview", "TimelineItemEventRowWithManyReactionsPreview", "TimelineItemEventRowWithRRPreview", "TimelineItemEventRowWithReplyPreview", @@ -161,6 +162,8 @@ class KonsistPreviewTest { "TimelineItemVoiceViewUnifiedPreview", "TimelineVideoWithCaptionRowPreview", "TimelineViewMessageShieldPreview", + "TimelineViewWithReadMarkerBothIndicatorsPreview", + "TimelineViewWithReadMarkerJumpToUnreadIndicatorOnlyPreview", "UserAvatarColorsPreview", "UserProfileHeaderSectionWithVerificationViolationPreview", "VoiceItemViewPlayPreview", diff --git a/tests/testutils/build.gradle.kts b/tests/testutils/build.gradle.kts index 4acb06305f..848777464c 100644 --- a/tests/testutils/build.gradle.kts +++ b/tests/testutils/build.gradle.kts @@ -20,6 +20,7 @@ android { dependencies { implementation(libs.test.junit) implementation(libs.test.truth) + implementation(libs.test.robolectric) implementation(libs.coroutines.test) implementation(projects.libraries.androidutils) implementation(projects.libraries.architecture) diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt index 7c3d4ec600..f910285b52 100644 --- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt @@ -45,3 +45,9 @@ class EnsureNeverCalledWithThreeParams : (T, U, V) -> Unit { lambdaError("Should not be called and is called with $p1, $p2 and $p3") } } + +class EnsureNeverCalledWithThreeParamsAndResult : (T, U, V) -> R { + override fun invoke(p1: T, p2: U, p3: V): R { + lambdaError("Should not be called and is called with $p1, $p2 and $p3") + } +} diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/robolectric/RobolectricTest.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/robolectric/RobolectricTest.kt new file mode 100644 index 0000000000..cf5f584f7e --- /dev/null +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/robolectric/RobolectricTest.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.tests.testutils.robolectric + +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** + * Base class for all Robolectric tests. + * + * It is now configured to run by default on Android API 36, + * waiting for Robolectric to support API 37. + */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [36]) +open class RobolectricTest diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/robolectric/RobolectricTestParameter.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/robolectric/RobolectricTestParameter.kt new file mode 100644 index 0000000000..e8866d5685 --- /dev/null +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/robolectric/RobolectricTestParameter.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.tests.testutils.robolectric + +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestParameterInjector +import org.robolectric.annotation.Config + +/** + * Base class for all Robolectric tests with parameter injector. + * + * It is now configured to run by default on Android API 36, + * waiting for Robolectric to support API 37. + */ +@RunWith(RobolectricTestParameterInjector::class) +@Config(sdk = [36]) +open class RobolectricTestParameter diff --git a/tests/uitests/src/test/kotlin/ui/LayoutLibErrorFilterStatement.kt b/tests/uitests/src/test/kotlin/ui/LayoutLibErrorFilterStatement.kt new file mode 100644 index 0000000000..9f91f30816 --- /dev/null +++ b/tests/uitests/src/test/kotlin/ui/LayoutLibErrorFilterStatement.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package ui + +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +/** + * Workaround for Paparazzi 2.0.0-alpha05 / LayoutLib 16.2.1 bug where + * HandlerThread_Delegate calls Thread.setPosixNicenessInternal which doesn't exist on JVM. + * Tracked in https://github.com/cashapp/paparazzi/issues/2342 — fixed in layoutlib 16.2.3. + * Remove this workaround once Paparazzi ships with layoutlib >= 16.2.3. + * + * Paparazzi's PaparazziLogger collects background thread errors and re-throws them via + * assertNoErrors(). This Statement wrapper catches the known NoSuchMethodError so the test + * can pass despite the LayoutLib bug. + */ +class LayoutLibErrorFilterStatement : TestRule { + override fun apply(base: Statement, description: Description): Statement { + return object : Statement() { + @Throws(Throwable::class) + override fun evaluate() { + try { + base.evaluate() + } catch (e: NoSuchMethodError) { + if (e.message?.contains("setPosixNicenessInternal") != true) throw e + } catch (npe: NullPointerException) { + // Also catch this error on `HorizontalFloatingToolbarPreview` and `HorizontalFloatingToolbarNoFabPreview` + if (npe.message?.contains("""Cannot invoke "java.util.ArrayList.size()" because "childrenList" is null""") != true) throw npe + } + } + } + } +} diff --git a/tests/uitests/src/test/kotlin/ui/PreviewA11yTest.kt b/tests/uitests/src/test/kotlin/ui/PreviewA11yTest.kt index 6f8fe2f506..f420110f31 100644 --- a/tests/uitests/src/test/kotlin/ui/PreviewA11yTest.kt +++ b/tests/uitests/src/test/kotlin/ui/PreviewA11yTest.kt @@ -29,7 +29,10 @@ class PreviewA11yTest( @TestParameter(valuesProvider = ComposableA11yPreviewProvider::class) val preview: ComposablePreview, ) { - @get:Rule + @get:Rule(order = 0) + val layoutLibErrorFilterStatement = LayoutLibErrorFilterStatement() + + @get:Rule(order = 1) val paparazziRule = PaparazziPreviewRule.createFor( preview = preview, locale = "en", diff --git a/tests/uitests/src/test/kotlin/ui/PreviewShard1Test.kt b/tests/uitests/src/test/kotlin/ui/PreviewShard1Test.kt index efb1a82cba..17632c212d 100644 --- a/tests/uitests/src/test/kotlin/ui/PreviewShard1Test.kt +++ b/tests/uitests/src/test/kotlin/ui/PreviewShard1Test.kt @@ -28,7 +28,10 @@ class PreviewShard1Test( @TestParameter(valuesProvider = Shard1ComposablePreviewProvider::class) val preview: ComposablePreview, ) { - @get:Rule + @get:Rule(order = 0) + val layoutLibErrorFilterStatement = LayoutLibErrorFilterStatement() + + @get:Rule(order = 1) val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en") @Test diff --git a/tests/uitests/src/test/kotlin/ui/PreviewShard2Test.kt b/tests/uitests/src/test/kotlin/ui/PreviewShard2Test.kt index c3312bad3b..cec2b028ac 100644 --- a/tests/uitests/src/test/kotlin/ui/PreviewShard2Test.kt +++ b/tests/uitests/src/test/kotlin/ui/PreviewShard2Test.kt @@ -28,7 +28,10 @@ class PreviewShard2Test( @TestParameter(valuesProvider = Shard2ComposablePreviewProvider::class) val preview: ComposablePreview, ) { - @get:Rule + @get:Rule(order = 0) + val layoutLibErrorFilterStatement = LayoutLibErrorFilterStatement() + + @get:Rule(order = 1) val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en") @Test diff --git a/tests/uitests/src/test/kotlin/ui/PreviewShard3Test.kt b/tests/uitests/src/test/kotlin/ui/PreviewShard3Test.kt index d4508fb821..c752d0b321 100644 --- a/tests/uitests/src/test/kotlin/ui/PreviewShard3Test.kt +++ b/tests/uitests/src/test/kotlin/ui/PreviewShard3Test.kt @@ -28,7 +28,10 @@ class PreviewShard3Test( @TestParameter(valuesProvider = Shard3ComposablePreviewProvider::class) val preview: ComposablePreview, ) { - @get:Rule + @get:Rule(order = 0) + val layoutLibErrorFilterStatement = LayoutLibErrorFilterStatement() + + @get:Rule(order = 1) val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en") @Test diff --git a/tests/uitests/src/test/kotlin/ui/PreviewShard4Test.kt b/tests/uitests/src/test/kotlin/ui/PreviewShard4Test.kt index c0e3b807b7..55881de079 100644 --- a/tests/uitests/src/test/kotlin/ui/PreviewShard4Test.kt +++ b/tests/uitests/src/test/kotlin/ui/PreviewShard4Test.kt @@ -28,7 +28,10 @@ class PreviewShard4Test( @TestParameter(valuesProvider = Shard4ComposablePreviewProvider::class) val preview: ComposablePreview, ) { - @get:Rule + @get:Rule(order = 0) + val layoutLibErrorFilterStatement = LayoutLibErrorFilterStatement() + + @get:Rule(order = 1) val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en") @Test diff --git a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_0_en.png index cf887d2057..de47dcabf4 100644 --- a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44caa90be72f8ff87f5e7c9a4fa7ff18254e09e0ff8086b6cd69c6c4827f3b1a -size 82510 +oid sha256:58f84b7eb0039b81f7bf1a879042095ecbd99412d48cdd8072df1486ca9d78a5 +size 81677 diff --git a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_1_en.png index e4710507e8..7329a2e799 100644 --- a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5657c3ce5c5928c082fde832939637cb6201d8299d31360df160a37ed70eab90 -size 81391 +oid sha256:e7f402ad83c4032217f22048b59de363ab1a1a19c1c4fb81ec8fd3402698c4d8 +size 79607 diff --git a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_0_en.png index b241662e21..7419f8df30 100644 --- a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d6cbfa0e9218e49009e13af0d2ebffc826770f17745b6b22c18a6650bc817391 -size 75776 +oid sha256:08c97bcb1ad81d7aab93c619bebaac4ec9ca860b2e71ae2648ebfab41cbdeca8 +size 74832 diff --git a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_1_en.png index 9533025b72..b15f5ca22e 100644 --- a/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.analytics.impl_AnalyticsOptInView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a1cbb9cd3f47cfb7710cf50718e9987e2479d61b006e45a4d8fd005b963df93 -size 73987 +oid sha256:fa8c26e98e9cefb8e33902615f5b18c1931e0816d4a047715ef6cad2229b10dc +size 72245 diff --git a/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Day_1_en.png index d8b961c49b..05fa99ba62 100644 --- a/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:219cb8f4e6eb3231b70758b3e749ea035ef46178520e7133659d378f8399f153 -size 59974 +oid sha256:33e4ea9bc6269d6ac5ce7ff6a76cdd1011e0f3dff96b920714b7f97d1aa1bf12 +size 62540 diff --git a/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Night_1_en.png index d0a711bd4c..77cac5fc57 100644 --- a/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.announcement.impl.fullscreen_FullscreenAnnouncementView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71085b7d41122d58311cfac1b0660d36b76b364253e0a5053456ad4a1a91c3dc -size 58788 +oid sha256:4e0406e368a19e1bc445b70c3b14128ed7c8bc02bd0e5da9c53611714e627a05 +size 61706 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png index 13a1a88a4c..ceb4413a16 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf9aa6f47084124e7c774ae78bc98404d960805bb1338784f3641251e33ac7c6 -size 29426 +oid sha256:a79354416a9a99eeb652b0a9381e694529b10e930d82bb04ae175223fe4ee4a2 +size 28736 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png index 2e3058ac63..c762b76dd2 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d40447ece02c06d429d52138550c73e559f89dfd99f6dff7a92cfc3103f2dbe -size 34093 +oid sha256:145e1ac30630e4f13df29fc92b2e4f305ec014fe85a4c178e6bc0bb76041587d +size 33942 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png index a581a42dfd..6aee832eb6 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:654d8e0acd3b3bbfb856414b5e5ca5615f3febacd8bebaa9af5a1e4d96c5d035 -size 41543 +oid sha256:f9adf6cd9c1d5a0afaa94228037646835c4c22d4ab664d44405f387c6546bec3 +size 41019 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png index 33c4f82363..7f77ca2730 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea98589cd86e69ae6d57566b205b4dab70f5f4b5c8b0fee09c7e690cafa7f914 -size 42514 +oid sha256:47121746126e9d867c80a6426d851100ab81db82e9585d3e5219a2b677d26ce3 +size 42009 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png index 7600487323..0f5c6846f7 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:37ffab3c3805f0bdafaca9035af6e4f706286f45a05a761ba7e7c160d45463c1 -size 44226 +oid sha256:02fefe256f1a0f9c5c0ad464eeddd70e8335a11cc6e73bbc5d04ff3a3ff0ea0f +size 43728 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png index a581a42dfd..6aee832eb6 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:654d8e0acd3b3bbfb856414b5e5ca5615f3febacd8bebaa9af5a1e4d96c5d035 -size 41543 +oid sha256:f9adf6cd9c1d5a0afaa94228037646835c4c22d4ab664d44405f387c6546bec3 +size 41019 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en.png index 05a54538a4..6f7fced7b2 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c20f293ba37e9af3e9f045de2ff1746af5e265d5dcf5bce5dc396da5c29387a6 -size 42482 +oid sha256:1b9f48a2166442bb5a3555128af31d79acf82746517b1352021289a852864061 +size 41981 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en.png index 5ff5af29b1..144166d170 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fea7e63fd1d31db6500c4b110b9c05190da7b7201e1029177f8b5a61e728e100 -size 37458 +oid sha256:d7b55ab3959b1189d0af772f47da0751844e8ea59fa65705baba0d6828fc3c03 +size 36858 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en.png index e51dd98b4f..577de0f744 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:edc093b514b7e648d176a17b0c368fbed82e9c46d3f584fdb9c6094a6e5aba55 -size 40420 +oid sha256:f4c3e7f20ce61d54845022afef017edcd1d8df5f15116ad3ba04a6529a5900c7 +size 39765 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png index 4dd2b02ce3..63547859f9 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e4dfa9c766681c750383863450aff0052f3083d495fcea1be74446ceed1cc4b -size 30462 +oid sha256:5de69f76240ae56cb28d4819f9e787f280c8a2cc4cc61aab2505f144414c6488 +size 29810 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png index 79155ebbfd..85071dc677 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49309d3b55bf7a4313ab100d54f2d13b741b5bace7fec7d03e8e30765d8e100b -size 35329 +oid sha256:631fe0c5bfdecb8782a46005edfd92e1b42fd323a316b2084a48118e0ad49c35 +size 35260 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png index 5baf7f75b8..a1dbe81d8e 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea38acc7ef6fb8307b83453eae80ec7c3154a80d0591c4f1fc1a87aa581a7926 -size 43124 +oid sha256:55c66afbe31070cb85746b2ff1897517b4839a9d5767caf1050265f3c10d195c +size 42701 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png index 920269d44d..765f6713e3 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7fd71e26763fb648a7b6ac898f2b354056354d1deee3d3712786a0c36e0cf476 -size 44168 +oid sha256:508a81fa57693cfd414db0b16e81fe9441b0fb06b43b4ef9a4b4b685a7ab1b08 +size 43752 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png index 65bd6527c1..463bf3963a 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d355371ce78c9a78900a6d76899289844c687b794c2afe127580a7c50b25935 -size 45949 +oid sha256:bd5d3ee7b7b5c5f08c9461fa79e98dd08ac791f29f3ef3637b9a8ddd54f036bc +size 45561 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png index 5baf7f75b8..a1dbe81d8e 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea38acc7ef6fb8307b83453eae80ec7c3154a80d0591c4f1fc1a87aa581a7926 -size 43124 +oid sha256:55c66afbe31070cb85746b2ff1897517b4839a9d5767caf1050265f3c10d195c +size 42701 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en.png index 875f4a71a3..e652f66e33 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c73b89404caa0fda5233c7dfed5810276a5cb1c1efd5843484b80c7f859b99a -size 44209 +oid sha256:d7fb6d97314e612541c29bde743190a8b6ecafb22abfb9257b4b3351010acbb7 +size 43774 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en.png index 27b3f41f26..4854bb4608 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:005c6520e884641ca1ca4e1248627937806328fc4ae527b811c65ee933a5616e -size 38889 +oid sha256:bc921fdd55417c80aaf9ed33b9b30b623120c6aec0aa0f19810f4ed91435bba0 +size 38304 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en.png index c29181ca85..560ddb5530 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4fac6f85109de1b6beb4cff51a91dec8e34ed8ed50820829b63584226e611d5d -size 42064 +oid sha256:cee85a4b9f76fef13813cc0a8542d5c0e767e9be529c5c877c30158225767c45 +size 41406 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_0_en.png index 934cf82e03..c6103fdd16 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:501543b209eb2f4a28d0368ae49ef9703a6dff8af67194412b3efe51ea140146 -size 41455 +oid sha256:1da296f6409e018bf6e36d4bf8d0183327e2da1730008721476397a3398a2e13 +size 41382 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_2_en.png index adab865ffd..cc54eeeef0 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:152c46640d6bef83fb6c2950a9f54e81314fbe912133cd852f53392ff87dde2f -size 13749 +oid sha256:b3fdd076498f0a2cc41104b6098005a9418e7eb16863e6c9040e0a49d6dc3922 +size 13739 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_5_en.png index 273750675e..1f93f01826 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:422607aface1a2f436431ea431111f5a003cf75e4eac4d2e27687b45e10c0c05 -size 59476 +oid sha256:7456163ece98c73691a5147e3c7b183189a545389699bb9fe33a8ce68bb125e3 +size 59685 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_0_en.png index d05a334223..73c8da0c71 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8f87cd003427ebc919ccf0a5679849eddb210231257d1c78af202ff761425cd -size 41145 +oid sha256:bbfb4004f0c9b017a86096d9a45c1793ef32d5117f6a17c59a41920264e95399 +size 41099 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_2_en.png index fa444dd818..bbca53db2a 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac359458a55030fda5714e1e513fd5e45a837df48f6234c6d61fcd3c783e4b76 -size 13310 +oid sha256:7afac8b6173f573544b987363e1ecf5fe2251ac23182128bcf2c27e290253dc2 +size 13319 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_5_en.png index a80c52a517..f293dd7cfd 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.components_RoomListContentView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b56cf113f934b6e882a21e25596cfba606fdbc7cab1853bf37d365f192d47908 -size 58581 +oid sha256:683568f509c83c24f506924e7a715f6ff9530d3f6ae28e041436288a510785cf +size 58742 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_0_en.png index 6b4037b3eb..1eedab5750 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c755a7dcfc2c9f48d449e570a3f1af1cde299fd90ddd4478e9a4c315cf03128 -size 23810 +oid sha256:6f199ef24dbc9d8c89b5b28503a887f489a6970355d591aa05d08968f25ddfce +size 23900 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_1_en.png index e64ae4c3cf..1a5b97b2b5 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efa5408c3af0fcd39659b8d30b21ace43be46d2876815ad592f802a7887b5eb9 -size 23678 +oid sha256:002bb9faa2d3222cf1b5ef4adb44e9a711ff778a6b6c9f7480620a3c3e69bd21 +size 23822 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_2_en.png index 82b04fc045..49e0ab6f86 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1fc512e71e168473e0e976be3e3e6cd24b455273257ad0adf970fc2641da43bb -size 25679 +oid sha256:47accbc1fbd8a7d238cd540036bacc5233d9feb5499a1a1f0c9d0cb48ec6748c +size 25862 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_0_en.png index f52d785548..28ccf10710 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de71af50bba66a285b5ef44e1a4fe76ce6dc2e094c4c09ddf701deb9a5db898d -size 22025 +oid sha256:afdd57a26c55f80a987c6d1e1b7c0f19728fcf99613630897e92ba29423f9f87 +size 22212 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_1_en.png index eef2177c3b..9b7d08cec9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:88b3583d55c6855027f13a152a6fc414f6b9e11d65e5b5403463b84fafe38c3f -size 21891 +oid sha256:1c91577d10dfa10f11c2fed1781559c513b5b376ce7636a6ce3dfab73933b6d2 +size 22095 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_2_en.png index 87d3f56720..cba5142ec9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e64367832735139b68269a8c679b9c6f2b929b906124a0ee93735cbdd9202d6d -size 23826 +oid sha256:20c44f88a9b347569b4f8ced10b29104541637661134c1a82e2746fa00bd1a25 +size 23968 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_0_en.png index 54f8482510..81deb50d77 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d12f0060a972296de175c7e8ea7900e3710366cb97a5a9b58065f456ddb201ba -size 32062 +oid sha256:720bc9c24ee9e17a79ff9588420558b9c57ac0e50c39ec2729bd1974fbd2187f +size 31947 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_1_en.png index 1a19b6d735..28c72b6ca2 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1edcd2abb480c46a6c10369fe05ba6e7764b0fe4f94690239dba36b4e13989ff -size 18465 +oid sha256:62d389c95049ac094d227083eeeddf36d82654e5f84a2fb92e9a62ec72db23e6 +size 18357 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_0_en.png index 08c65d9bc7..e361719a8b 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b3d3a5a7255368a0722a024ae72b8f864556e9da5dfd6204b8cea3504bd22a9 -size 30645 +oid sha256:19fffb5f139f9b0af134eb108b0b19238010a18ae32e87ae673b8b1aa8f6d246 +size 30488 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_1_en.png index 168113e84c..4ca69dee85 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spacefilters_SpaceFiltersView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8a451f8da02325bf3dd0815fa2fb76d55fb7baaa4e602b82339bd79f22bfb9a -size 17497 +oid sha256:28d6a11ab288b0750b6eef0e1f2488d4a150aebb5dd3184a66c4af14f3685c71 +size 17340 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png index 526bd69d4e..c69cba2125 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35c1709b912da1102a50aaa4f8470cbf05a75b03669aec51b90354ccb2b09ba9 -size 85336 +oid sha256:09c0613d19abd7673223bc5eac12b4e87c73e66e7ff9d437c5f97ae8bcaf9303 +size 85239 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png index de86c4285d..bd9fa30de2 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d69d687090971ab7e9b87f959521109fbed48413ef217e1be3da8d7d985038b -size 38751 +oid sha256:df0dc04b3946a58dda5c3499d965ab23cd3c172eedcb8a23461201c2aca95934 +size 38713 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png index 0b5629c139..8ec9b1585e 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f60372df2ed22a4c52624e16324f7da1f6000eafdd519f84d42a29acec016ee -size 83600 +oid sha256:e28f120a919db7c7a0ced5ca0d56239197785a0ecfbd37af0c5dacb5f8316c1f +size 83583 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png index 07e9ef1e28..72e173c493 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2a6a7f3188eb9635ade7c0bbc2239257cfbe3166f4a6fb7917a1e5578f51d9e -size 37436 +oid sha256:cc37ee6efade5947d0fdc25f6925cf45ba55442eb3fb715f942178513a00e8fc +size 37416 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png index 1bec9cf123..344bd350d6 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeViewA11y_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f2357a181fcea22deb153e4d4c570421354cbc74f3e272a6e94c7795cf29c4c -size 144183 +oid sha256:b5dde8ed5c776f4701f24dd7d411dd78f48adab261efad71e961c845e24d12f3 +size 144367 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png index 3a262e8d47..b5f80f2faf 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 -size 67756 +oid sha256:8247dedc9811f2b325568973a2b714cd4b46322bcd0bf89af0e662518fa77747 +size 67694 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png index 6eed7b2e94..f2a69ea475 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2339985aba8128dd562491d6575b92338be2338c090d978f553a1e50b44b24f6 -size 32073 +oid sha256:6b493bc5151f15d6ba91bfb0c27b41f3abcf13ee7d511aa59db171cecdbd95f3 +size 31958 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png index 4feecf5107..f4dff45422 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8c5c2fed11674afda7ec3a838d749a4f688a2979f934970d2b2d3ff7a837f89 -size 94736 +oid sha256:1a33681fe064d5e12f53273bfd9262af8c7b902e237cb8d0641573b0645e291c +size 94687 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png index da72b71928..bdad242551 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5b54ba16e7e2413dd994bedcc31e5ffdf6c291487ccc5ae17178d2572a4fb0ea -size 87282 +oid sha256:022954bdca89572b74bc70f6d91820e99eef8826409c0a06e6145a5c3ec8eaf4 +size 87268 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png index 3a262e8d47..b5f80f2faf 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 -size 67756 +oid sha256:8247dedc9811f2b325568973a2b714cd4b46322bcd0bf89af0e662518fa77747 +size 67694 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png index 3a262e8d47..b5f80f2faf 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 -size 67756 +oid sha256:8247dedc9811f2b325568973a2b714cd4b46322bcd0bf89af0e662518fa77747 +size 67694 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png index 5c05d6e633..e01335907a 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69fd2195c4d0203b602ba91b822c5e9dc0e902b77dcf1352daabaf91aaea1768 -size 65301 +oid sha256:25e5ac35ddf79fdc78c21dbd031f506da04caac7bdd53f279c88fd4574f72a82 +size 64644 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png index c33ecadd3d..fe41a54fcc 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e64f044d19a709056de64976c6902baba7821885f35cd88873d5462fd52c3e4c -size 57343 +oid sha256:8c1245da0a4cf56aba8e102e7f297996ed58fc8c50165288dea11ca86fbc0dcc +size 57235 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png index 3a262e8d47..b5f80f2faf 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96ce82255e49c97179a216124ccfcbc6726a8053acef767041ba44304e7f4735 -size 67756 +oid sha256:8247dedc9811f2b325568973a2b714cd4b46322bcd0bf89af0e662518fa77747 +size 67694 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_6_en.png index 99940a4489..91f02401b5 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e74b9b1819bf778ddb397a40113f71b2eb0ada0dcb26af85dab26bbc53ed079 -size 54210 +oid sha256:2f19f7f9fd7675dd46fd61764e54ffa02cfacd08173aee0d86512bcdc5f30fb2 +size 54466 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_7_en.png index 2532044b27..f72667b724 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4e56509b4f10e97283d25432edd7be4b511987f0879acc3026ac16dab25b75c -size 54012 +oid sha256:31217a40625020e07d4f6d6d98d1d5db9d9fabbf0a9f3e4461e72c26e5447925 +size 54272 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_8_en.png index 0baf9cf023..f64c1b8a19 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe76cc652842cce967d975fae7a387f5cff118153b345bda452d5dbc618b22f8 -size 52255 +oid sha256:4e3c83b95b9b5fbcc07e5d84cbc6d3b54d08e1c5964bfc461be1a9c9c33e6e18 +size 52539 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png index 36b337448b..b6779aca93 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bcd14b5720ecc9a80f6f2cc7133d6c8695096b9c90d3504380464c46c91048c8 -size 87131 +oid sha256:0769e243dc60de52c16df23a86eb62167bb60cb756d113f88b9b476c025e402b +size 87117 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png index 63ff6e0ae9..fe171e26b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 -size 62676 +oid sha256:8a7b2a6ccb43dc572140e2ce658967cd273d1122bf0216269a648920099a68d0 +size 62572 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png index ad828b778a..f36b5c2f83 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14d762574470814f5b37cc05a2167d546f92460bd016206e71ba43026d00f9cc -size 26743 +oid sha256:6c3fb8ae530989e5a6d6e4193fbac4d4356af34076b684b782a0f8fec31226f1 +size 26657 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png index 5af2cae9e7..48b07fc9bd 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41252714e511c1c63b43edd35c2f443a7a791a2b2f29885efc1f2384764edac3 -size 88578 +oid sha256:5d302be6dbaef08b501f4f33d3e01338e068767702a7018bd5bb24ade6eee2cb +size 88558 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png index 280257f53d..5cb7d766cd 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e841a58c50c98444bcc48316654ee5c664cf845e3c38f4bd02e80ce8d3c9366 -size 81261 +oid sha256:6be5cd35eec917bf1c96d03079df8235d0bc7b52159f54c8a177a64f648e58c2 +size 81212 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png index 63ff6e0ae9..fe171e26b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 -size 62676 +oid sha256:8a7b2a6ccb43dc572140e2ce658967cd273d1122bf0216269a648920099a68d0 +size 62572 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png index 63ff6e0ae9..fe171e26b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 -size 62676 +oid sha256:8a7b2a6ccb43dc572140e2ce658967cd273d1122bf0216269a648920099a68d0 +size 62572 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png index a709ce6a75..89c4934dd9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c10e44c82a7412fd51a651a69b9c643a7b1eafcc4251227009e44a47e9649bb5 -size 60656 +oid sha256:8172ca867a8c2e827ead36a22cefe967a5b57c69cae6d5aca1c941e4dd2ba16f +size 60160 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png index c2dc739e38..390c9f6818 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d923c6e3503af723269dbe5c03f1024e7e3fb6ba746fb979f7735c0ad3b8e32 -size 52322 +oid sha256:13740b4fc4cbd24075606e45bf070a8fbb762d298857bc071399def91dda7175 +size 52189 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png index 63ff6e0ae9..fe171e26b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8518ca0e40ddff8b8f8cd1960a5cc8c4419a7f7381459f2bca782df80cb0094 -size 62676 +oid sha256:8a7b2a6ccb43dc572140e2ce658967cd273d1122bf0216269a648920099a68d0 +size 62572 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_6_en.png index ead9ed0d6d..66f1bc4364 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f2d17c9021392f93fc022ce0ba4305f0739acaeab3ebfd51b7d3294ace365807 -size 51156 +oid sha256:9bd841b458babd88d364e4906d199e48491407547430269dfb7b95a5d3055de6 +size 51527 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_7_en.png index 33f2b46a34..1264ea44d8 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:286af36457c34621e10b91226b13c5a9fde77af6b63827d39a0a95697972d4ab -size 50896 +oid sha256:5828d3c51711976aaf8906eee401866baa6683e879d5f29da27a2d2110ab1a14 +size 51291 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_8_en.png index 733a66bb38..89af663213 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:34a5fe14ee5ede42d962e657e4338f58f56e79e0f9a3f65ba24e37810a9c1250 -size 49205 +oid sha256:4fdf0d6bbb3a760fdfc93e13c4acbe5703d1fe1b99c1e859897a8dcd319eca3b +size 49559 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png index a408245bae..1092dcd1b9 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b09c1c639b12b0521da9e4b403530d4bd33f6e79823903091870fba56477153 -size 81113 +oid sha256:bce0bc8590037705369735e83e576f0818f4528298b4b2face999c8802f855b9 +size 81081 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png index b658085113..31e1e4049e 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:948478d8dd340d0cb5facf43af64d726587be6ebf07314b854cb562aab7a47e5 -size 37273 +oid sha256:673519b0fde86c46908d614cf116041c1bd27a81d5a87955febc33187398559b +size 37304 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_10_en.png index 7281594c56..9a4dbeeee5 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c81c5e7e1a62ed5fc55d672de612c5ace83561f70a3e363ecc851a0ae3658b81 -size 54766 +oid sha256:4ec919634968a61656ff3668937cc49a6de659e265ca0e4a1a3c03533bbd9981 +size 54751 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png index 52949fb4a2..ae37022419 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c81346eada72651d9400de736e56fc94330ffd014ab762a9abb1890bfab1f75 -size 50285 +oid sha256:6e77a040286b900514440d410ca2bf0ce826e0e1364ccae6e1c34d7f0204631d +size 50615 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_9_en.png index 52949fb4a2..ae37022419 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c81346eada72651d9400de736e56fc94330ffd014ab762a9abb1890bfab1f75 -size 50285 +oid sha256:6e77a040286b900514440d410ca2bf0ce826e0e1364ccae6e1c34d7f0204631d +size 50615 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png index 6910d23bd0..e102a3934d 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:965946244a5a38f44fd34d4383448b3b92ce5481d2f992f7f72b69ded951c375 -size 37617 +oid sha256:06ab4c46d877199855b0901ec96adb74fe9ca3fc484c71a0fd472d388a7dafd0 +size 37518 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_10_en.png index c66df232c2..df970a313c 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d143c9fb43b79e3a6248b4eb179228b91652f43013da73d10fc5ec09384c20a9 -size 52486 +oid sha256:6855898359711e2d2bc80403e063ac8c51ad7e09bec9fae6ad5d765d9e3cd129 +size 52497 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png index 5092d9cb3e..0a8f04940b 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:601916fd979efa36104cb252a76a523e25a86cdfdca1cbd4e6f35314ab977d26 -size 51358 +oid sha256:7aa0ca8af987ba61d12a52f8298ab344ef7f5464a1f33c55607e559919da5a31 +size 51764 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_9_en.png index 5092d9cb3e..0a8f04940b 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:601916fd979efa36104cb252a76a523e25a86cdfdca1cbd4e6f35314ab977d26 -size 51358 +oid sha256:7aa0ca8af987ba61d12a52f8298ab344ef7f5464a1f33c55607e559919da5a31 +size 51764 diff --git a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en.png index 33110584a9..f0bfd0f2b4 100644 --- a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.banner_KnockRequestsBannerView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dbdf9740221b82aaaf332c95e7299594f0b4fdd258b2e9c733133bdd4a01f692 -size 28378 +oid sha256:e82c6e4ff563e7ae870431528d9413ac915e16ca0151aa3c86ff5081bfc72478 +size 27563 diff --git a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_4_en.png index d7e2d0a3f9..9a2a2a4a0c 100644 --- a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ccea3d95f047fffdada68e6ed02c359a552d5c2c2f6be488c96f759bc208f37 -size 52830 +oid sha256:1cb6be576055a020b5c5c6a996e5923490d6a36ad5ea8246cd6fca9707affda1 +size 52987 diff --git a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_3_en.png index 42ecbe8a68..438d96608d 100644 --- a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:471abc7c54d0f90ad5a923bd21abbf0960bbb9cbbdb22313a779083baf61ab3f -size 40671 +oid sha256:ae0b92a52a7f2c0533af7d7f0fbddc6497778e7c5dcedc3344a2ba60a6a948f8 +size 40439 diff --git a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_4_en.png index e07bbc74b5..eead87f8f4 100644 --- a/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.knockrequests.impl.list_KnockRequestsListView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f588a2d2299825159380a42df4acff302a8b50b7dbc3cb02e145b596ead20061 -size 51525 +oid sha256:7041e20c1d2b83b6ef199fda02f594c4406fb6061b1706d6530d36b3007bc582 +size 51574 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png index 19a824127e..ee619462ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d30e200c3e73775ed7081d3fbdc9f8843c5a5bf9e5f1b9ab3535cc6f0ea7f1f6 -size 35946 +oid sha256:17c58ce74a1b198f8659636d180a98152bd66be212f381afd652f615bd847a7f +size 28795 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png index f1f3896ab8..21fe725606 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a78b0677d896de960ce8ce7c5818b1d52004c91917c73c460a605e5e1342554f -size 35129 +oid sha256:5493215960a23d305a2f9f26e39b307c735167583c20ac3fafb1b67e89aa1d12 +size 28124 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en.png index d9b4151b77..5bc0a7e57a 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.qrcode_ShowQrCodeView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f91ec4d46970dd80c97efc76361ce26b3e705b037b99bc032205ace3d2c8749 -size 31953 +oid sha256:da71297e7073c5c592dc154af7f137c4eb500bf528e1509b95da869a2c61cbd2 +size 30488 diff --git a/tests/uitests/src/test/snapshots/images/features.location.api_RenderingMapsNotSupportedDialog_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.location.api_RenderingMapsNotSupportedDialog_Day_0_en.png new file mode 100644 index 0000000000..cf35ad0fa8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.location.api_RenderingMapsNotSupportedDialog_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f64455657f0f8a5ac7eec71ee206721a79b25dacf470d105a0e6497e570204a +size 23954 diff --git a/tests/uitests/src/test/snapshots/images/features.location.api_RenderingMapsNotSupportedDialog_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.location.api_RenderingMapsNotSupportedDialog_Night_0_en.png new file mode 100644 index 0000000000..41cdb80dc8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.location.api_RenderingMapsNotSupportedDialog_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43bd5f04f170372b120fa2223c632d6a969c45b6d4fe61b161a7109318f9941f +size 22658 diff --git a/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Day_0_en.png index cedf0b1b7c..0473be6edd 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56a86695d2c25c94a8e79c27c8f525229cc348201073566909f83a681b37ac30 -size 251329 +oid sha256:69ffc87be8fc643d3cd553eb86140a9654ccac92d205b93e428d8631f2a770a3 +size 408053 diff --git a/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Night_0_en.png index dea0d3f21c..7b248fd2a1 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.api_StaticMapView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c2b2a7071bd1c21ff706525e2416169507fef364485c651c429baefa15d4c9f -size 104240 +oid sha256:7b2af9381e91c470a87d5585fd211b1f1ffdc4d56876285f73765a5ccd5ce72c +size 147867 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_1_en.png index 8957a012f2..ba69ac150d 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d950639a9cc9961210b449e5c975b6f6bc890a47f4977eeaaa19b837458f66e -size 36475 +oid sha256:17ad972930d2b563e278c5eb1296ce12781b85e939d6769131de08fbab9f3f7b +size 38760 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_2_en.png index bf25a07679..a7ce4c15ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a52d39cb27572c49ab64b1534ead353687d83870b5d5cfe7158859925b4717f3 -size 34926 +oid sha256:ffd4f5b8fece04b00ad5d866f6fc11e753e800f956c966e703d1dfc66f1ce8e7 +size 37257 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_5_en.png index 74d6ac15ca..d70cd4ccd3 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2621fef4175ad0f0982270284ffbbdb6b3b0534b09013c1cc378504a85d13068 -size 22385 +oid sha256:6ef91ce622a66945ef5475adbe04164635ca155a2a9e1682bc03459e9a6e289b +size 22356 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_6_en.png index 0c9a67252c..db11b33396 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9f3fb75974ce37fc3ce5e303ab5573a0d9a769f3c079de5b0f6462b40e53c1cd -size 26713 +oid sha256:a1ffc8d536a239ca11de23f3f8e5fb14b429b9beee03c80bbca0321ec853f5e0 +size 26638 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_9_en.png index f4ff1a611e..41a52e602c 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc36d1f05a6035dd4775dda0592d5557d45314c24d638738401eb910b6ba719c -size 21719 +oid sha256:d9f4d7292e5bfb5bdcc699aa3a5d9e065ce66f232a3175294850539b70a2be6b +size 21674 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_0_en.png index dbd4836467..aa539ed8a1 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3260d344a065f1710aff1450dbdaaa0bd1fbd963d5304167124d845c46be433 -size 19903 +oid sha256:dc1e9df75619bde2571bad0362f147c627ee44a780fbaa9a2c0e5a49e252d14b +size 19881 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_3_en.png index 2c8c53dc1e..08d4da7504 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8901e7adb15ff01e9c696729f1abc52c5fc8666bca030f449f8caf5a22615f53 -size 29196 +oid sha256:931f79cf0cabfe533162ad5b633c7261d06339073f3bd6c7044761aecc27ea42 +size 31143 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_4_en.png index dbd4836467..aa539ed8a1 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3260d344a065f1710aff1450dbdaaa0bd1fbd963d5304167124d845c46be433 -size 19903 +oid sha256:dc1e9df75619bde2571bad0362f147c627ee44a780fbaa9a2c0e5a49e252d14b +size 19881 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_7_en.png index 7761c87d2e..7ce1496b52 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9ed7610fbdabb3e88c35e2832d06566431d472ad95890c2fdcbb6d1b43d8feb -size 36751 +oid sha256:580ee0fe2b1dd97496850efd8d8f852046473f5acf3cb42dcf862ac3f6de2f59 +size 40266 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_8_en.png index 541b2a97e1..1f8c2d110d 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.share_ShareLocationView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:038e12f3caeef6ac8d5389b7cdc68138e089dcac335d0a5904adc55c9bcb7b1c -size 40642 +oid sha256:f139526f69881e08b17d15013d78fb3eeca76eea5b18d378953c37fbd9d76921 +size 44064 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_6_en.png index 46226555db..ceb1513af6 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cdf7b194a075902ab9434e272865293535ef39370fbb9cb172b3cf8774850c73 -size 19104 +oid sha256:8988c700db517eef71d7f42c8e21ac819f51c92fb88c0c25cb400be7a5326c22 +size 19228 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_7_en.png index ceb1513af6..e01e90f7d0 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8988c700db517eef71d7f42c8e21ac819f51c92fb88c0c25cb400be7a5326c22 -size 19228 +oid sha256:dea2fa898a6f9b921eca0931d7380814b31ba858b88c90ba1fbab6332b4c8ebb +size 20722 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_8_en.png deleted file mode 100644 index e01e90f7d0..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Day_8_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dea2fa898a6f9b921eca0931d7380814b31ba858b88c90ba1fbab6332b4c8ebb -size 20722 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_6_en.png index eed60f472d..d3ee3b9e22 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da601c01dd487f9c66f78ada91954398e1dcdf699f1ba4f6d8f7661f7b8cc4b7 -size 18715 +oid sha256:ca86fd5eea8c05a52fee801e1ca61c2e4e205ad9874e06d69b1d1f674585f87b +size 18842 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_7_en.png index d3ee3b9e22..547e7ba364 100644 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca86fd5eea8c05a52fee801e1ca61c2e4e205ad9874e06d69b1d1f674585f87b -size 18842 +oid sha256:f9f64bc6bb5956459f8943c05bbf0aa6ee9e97e3103713f34d49c013f86376a9 +size 18878 diff --git a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_8_en.png deleted file mode 100644 index 547e7ba364..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.location.impl.show_ShowLocationView_Night_8_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f9f64bc6bb5956459f8943c05bbf0aa6ee9e97e3103713f34d49c013f86376a9 -size 18878 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en.png index 515976516f..3206f5061d 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ee51d6f3454f52bc4afe5d90245b853fb621b097afb1a2588a91e4d9dd69133 -size 16590 +oid sha256:c5d291053aab6e5781e4b252d11a36e596d4dd22a08a2b82e381bcf395f86e42 +size 16622 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en.png index 5081175acc..295525d526 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:164b662bc38dc07e7995879b2ed0c9ef685498d1082e27d8d28d372809a6afe2 -size 18886 +oid sha256:916649bc7621d7580c579b3520195eab03f32c174f3cfa5f32f95a19b234c316 +size 18941 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png index 5eb1b68db4..851adf4f5f 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e872428460462ac33f00c6cd903ce7345ac9afd9a3d02b37d763d129f7ff304c -size 28572 +oid sha256:fcb4dea012f06580b17e6406e862ff40e42486c30d00213f8161333dc2e57a32 +size 28565 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en.png index 5c9f60137a..34c22546a3 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:919a87e26608070d11faf06fca878643fd4090fb708f8b8e2127b8f49b6d4efa -size 15970 +oid sha256:cee47e791377ebd2eebda92de0127e5c04b64d84113f459abd731fe49b672804 +size 16000 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en.png index 24649e54f0..52081c426c 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:641d43a9325286e3d7facb4fe0e53a13fc89c3394c702699b2b5ed7db534bbee -size 18237 +oid sha256:f06158293bb8ce12435eb7b78c5d8aef3f92e6c847ab389de82e931dd6d3bfba +size 18254 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png index ab6d3a7fcd..b5e2a2576c 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.settings_LockScreenSettingsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c981543a80612ff3460bf4460b552218f8453a9b8981c57e41d9c89fe7e550f4 -size 27138 +oid sha256:27879114748c757e4e666151b953747c1cc0369e7d5ac1eb3f81e459e4928b70 +size 27168 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png new file mode 100644 index 0000000000..10076e1c68 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7790ba46051ba39863f057bc53c937f513f91b6094094b2b449794d7de3aa875 +size 32833 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png new file mode 100644 index 0000000000..eeddc7261f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewCompact_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc7032e0d69a44d8ab2d3187183eb77cc28d7a5669fd7e56ee99d4f90ee05d62 +size 33137 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png new file mode 100644 index 0000000000..0dd66f5feb --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Day_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25ca16b3574c5cf850e06099312d4af294561c8c9833742a0b3902bc3b35cb39 +size 20669 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png new file mode 100644 index 0000000000..e03c2f9cc3 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockViewInApp_Night_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e58621f378a1abac78c5bdfb6a31675c1f762f53434f28b869ac8c7b6f9ad8ad +size 20109 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png index dd05b7e17f..88034ab8ba 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:011c3caceeb03e9162c5e60dd71d53212971e13b7a6b58692feb901ac13b79e1 -size 35844 +oid sha256:131578839b180f129a15d080c5580f255f52536dc3a6b595bee27574e8be0e66 +size 35847 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png new file mode 100644 index 0000000000..adb9484e70 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a60781d3bc38ed6c2ed830464f447d509f88a9767b81dea3acbd29ea21b5c0f6 +size 36212 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png index 680f363dca..8a66c7b727 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aef835a050377afd05e6a517107586160a86fce4f32344fd92d00a08b4a2c660 -size 36250 +oid sha256:3d6fdf4c5e49a9f29d10f8500cd0b0ac080cfed3e3776510ffd8ec8413be2a40 +size 36251 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png index 8e99b487cf..73267ca9c3 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f36922d058b19410a38456a9e29760f9b890c1fc0549b3aba2a0e76d3dc64c54 -size 37079 +oid sha256:0b3753087c932d0cc83277959546c7d288592853479eb3f718bb552bd4f87995 +size 37073 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png index 6a8ae3dc0d..74eb3256e7 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a90bdec84019b24913e647f61a5223d9283a8e9604e8446032acce2a71b6da21 -size 40871 +oid sha256:01a4a3a8a4552e068adb3c45f71479120506ff5f84b0938d44174e03b271c9f5 +size 40867 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png index 0af4ff0fcf..aafb60d1a5 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec435ce434370cb5ca711458b955e8843872b01675234eab15cad4ab6e08dc38 -size 33542 +oid sha256:93d813e1f76cf2576be1063b4ea91474014fe57eefab1e277c277c19f44b0900 +size 33549 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png index 3bc7a1d72e..d2b52d0095 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:412549704d3c5007a46b3b3a115a7cb7f89a687f427436236d4b51efa09c9bad -size 38247 +oid sha256:17bca98e4f7c0a17a9a990ec968634eabd2b774c561a43fa6a0be0ad0697c8a5 +size 38240 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png index e8ad13d33f..0654018b0a 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3f4d74da073c904db3f7ddd9a5be9e49161c64b0210fbc2c09dd755d2fadacc -size 29238 +oid sha256:00757d73357d0f1cf217cdec35c514a519af008514f2d4d8e2c3b540a84d7950 +size 29218 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png index 9dd19fc627..346d6053b4 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98252e4f345d6b34e37a8b065cb570f85b5678f6d81b36ef96ca3c5df9433a23 -size 29804 +oid sha256:cb8ee0599cbd6774b6ce9fe48ef532e93f07b1e726799482a1c265ca5a6733a2 +size 29778 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_8_en.png index 8b7fa8b77c..4a24e4d762 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80246e3957a0e3f98bce55ddd6d8fe09b5f140eee3837d80ca20253f6bcfb876 -size 37738 +oid sha256:e142a576df4b442c3e10a6347510ff8a8e243cada0bba35ee94ceaef6a349995 +size 37700 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_9_en.png index 266dae3c81..4d65f3c480 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60dd90eb571f473b78ecc629573bcf2faca02819022bdf57f05cc8b0876f4ab8 -size 31440 +oid sha256:0d39b8e5898470ee8802bb15ae0433bcdde60b982e88ac823f5d5baaec40a641 +size 31436 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png index 9d1bd22ef5..08a43fe01b 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e87b9820e45b16a13d2f9fb0a470b5f57abf0e45f48d16e5049c4abca04e94ea -size 34629 +oid sha256:df7a30ab0bc53d84bd7c0848795c7b1e55140b1c40162f16fa54ac6495730de7 +size 34642 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png new file mode 100644 index 0000000000..1831605a28 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_10_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d115c0f6d4c705dce1062aa2dbb026980df5efed8d8b2500774e6f75cbe366f +size 34987 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png index bf74b3022e..b8f5c8a44b 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74e88064bd3817c79443b6ed2df9b68e9e455d7bef2d94590854ce0d937e2107 -size 34997 +oid sha256:a2ec9d1e862444773b670c51f0ae18093fcb4a3900403ac041389b9d7b70eb36 +size 35010 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png index d5087096c0..4b25422e6b 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:23d3ded6d54724df9d03d382e12b58fc23970c354de52dc90cb0b13b66c9c614 -size 35729 +oid sha256:b7d2a247664c21d28a5554a3a720cf1de59a31ad58474b0d78e3e845b04e22be +size 35731 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png index 7a4a9fac87..7276bf4f44 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de86916ae6798afbc59dae5075a5f678010e6bff78a91cd06d40a7cc19187e83 -size 38344 +oid sha256:b732e81b6e9691182e441d1c83906f62dcfe93a41d871ff0f8b7a27bd9a0b817 +size 38366 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png index 22553fcf66..7ff75baf69 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94ed59c67dacb5066006189c0daf6d55704495ecffd145d69ea3ba968ffda246 -size 32467 +oid sha256:66e164942227a9209a928fbd0eba211818f0c53b25ca65886fe95ef1c0bc4cfc +size 32482 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png index d807d65d99..a19beaca81 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:daadf3522ac14a9ad2d0d5d497e6e688e69cc1e2ff824eaa5a0002adef1a980c -size 35888 +oid sha256:97bb8124c590e9e4f33203853abbb41aa672871e03c548209ada0ee39e97a824 +size 35913 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png index 913655b87d..8c62f0546b 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d090ac1696261be94b5073faf8e7864fc36ffa378bbf22e62e201cca4e7da3c1 -size 27869 +oid sha256:d8dfd1e4ab4eac0b6208bd33332e5b2537bae6dc74d6ba8f0654c1c995b65519 +size 27894 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png index 9de7f9b9b3..c90256c1d8 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d98c1f00e81a318d5df078cb91f88b1a16fe01bf37b835d9c8b976045d4b3023 -size 27860 +oid sha256:d7c66a024081eff6dfe43f72087651351290c66fe8cd6a3f1d98f31f7800ca8b +size 27894 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_8_en.png index 8a8d15acf9..8080cdb8a0 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d60a8caa2441ff0618636d307d32d0944bdb77fb3b579c0959dc951b0318ad72 -size 35429 +oid sha256:71d30a04330bc8d5c6332c2f741ace766f6942d40a4641362088ca4819a79366 +size 35413 diff --git a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_9_en.png index fe27573765..aee389854a 100644 --- a/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.lockscreen.impl.unlock_PinUnlockView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bfe8b59b8d5d7a1c33285072dec437060faae55bfa2a42687bd8895dd90409a6 -size 30310 +oid sha256:5bd95ec6a8977e259b568d824b9ea70915d93b53ac81df333e799c8aa62edd37 +size 30322 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en.png index f35d541afc..c9bf9e3c1c 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b768e63862ed7f9c355a907b80bc144d012e66c012438ffdfc65652a8d6318bd -size 5992 +oid sha256:0990301d92d4862054ba5e54103dac359df37997242498766854d7bb13431657 +size 6068 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en.png index e82d91a78f..fb829c4873 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderOtherView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7945b3bcbe86c2adf888c89f23e0cfb76f5ac30d3f37408ad376af35f5b5fd3 -size 5920 +oid sha256:3022b2b813d9a3f77b0ba72706f0fb870a1c3f7b4a8efc90e611b66b6e9bdf8e +size 5926 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png index 747a677a5d..0b20380cd5 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8217f8ca87864ecc8184ac665adfa31c461b42ec4313c349363b824dc6138235 -size 17795 +oid sha256:49371b85e60a5e0465c0ba1537293f6c071962c498579bd71b42763671c8dc01 +size 18148 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png index bc7a9c237c..cbe30336d4 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6e6e4c1b666db69ae67b0ae4bc84756e490c02cf7c3e261c2897637f90d642e -size 7681 +oid sha256:78ef17d2f96d5544ecc8213fe1b7f78ddf263557855901f00f152a0b543c1a6f +size 7746 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png index f902686235..447de4de32 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce2b95b979aa2406bcca270b49131aa24b11b325333cf3827e93df03758a3d85 -size 6839 +oid sha256:ce777b1c6895caacc21adf4f6c10c71f75a2c6d31a617afe1c7f49d10c5141b3 +size 6929 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png index 7b111f303d..ae99061ada 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e5cce43ca6b6dcfc1461164145279bb8e4bb1f3d2d2976a8ed22edb030fc50e0 -size 5713 +oid sha256:f49c89cde78d8d8971d5866f3cef2fef51bc36d1844b0364c950dc2afb188c5b +size 5707 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png index 345e7d769d..359e866105 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de7f8d4bcf900c38e3a8f16f317a9a16c352977f2dbe9213937f09f1990a54be -size 17004 +oid sha256:759f68aae091a43f54d597e386a5503692f99ed9c3908450dfadf59999047d01 +size 17272 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png index c0c462a052..3f58435f8a 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:83bbd72e29e24256bfd907334f8603f56c306eaba520f03d21ca5bc6388047dc -size 7395 +oid sha256:0591f839e4605cbc51746f9d479a0bfc37e078178e6b2d1395db07dc8a7e1261 +size 7382 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png index 2963e20187..abcf602e31 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c72a00088338657055c29bfd64e8ea11b47d4875ebaf7ac8ba45b02b31d16109 -size 6617 +oid sha256:a57866d169c69ba68365ef8cfd4739ec95f8a8aecf4805ec68b2f247f3f698dd +size 6627 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png index 6856a2501c..fe5123f403 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af5e1cbfd118b6eef4ab55eff57e2f735d0d8280846e57e1106228dbff575e6b -size 5594 +oid sha256:db8eda0daf8e2038c2c69ff945e686a9e5ff271d8dc4f30987f14f7acb22ae85 +size 5625 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en.png index 415cd8ef36..23858ce575 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a8dd6bc040641b68274f838a02bb0bc7750d35814bd8717c332ce6c4b4bbab47 -size 47001 +oid sha256:c7544e2566517e8692a1cccd4607bc2ab0f2767bbe9e5b39eb439d7695ad2ce5 +size 46905 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en.png index fe703a5bb2..9b505f3cf9 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8213893828ba44ae9ea6777204e922c11e584cf428ff29fe98e809292a34b3c3 -size 44816 +oid sha256:b5dbf45467305e83f302fd626a2c0adcd27eac6aeea8b7a83efdb6e728d974da +size 44703 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en.png index cceff9bd6e..815986cbc3 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75f10457c010805b854c02d3cf7744e1b8c2081d6d33cc9315123ce51cc9c3cb -size 45934 +oid sha256:41907de78c86fca804af2af7dd351db6a1ab87515e71bb906ffa2219ad4f5879 +size 45880 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en.png index 21020974de..f08662715a 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.changeaccountprovider_ChangeAccountProviderView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f224eab6216782450b3075d6d63f8bda4764683d86ab683696bfae71d062e41 -size 43678 +oid sha256:62581b532695d10a42432dfcb37249c28c2bd617ecb49d7f3a8224855b78ae55 +size 43600 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png index 0bd68821e3..7869ed3dc5 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12ec8a85ff40410c93a3f5dc974b95d1d138712f2cc6f81fc18b9bb7a7e1af3b -size 22486 +oid sha256:8098b9ff6c4d08d8cc61bc51e391a5a17e9791d7236d2d7cf652a6b855c87b97 +size 22501 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png index 5801447ff5..c1f55034ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:929b3c6c51c3ca37e6d00dbf9e1f3024c009cd0123e845293fde23b1cfe4f9ba -size 23459 +oid sha256:94878580a4ffff7c4d437eba1c62184aa61435420d6c85488fefc53e33e1e150 +size 23497 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png index 96ca1664f8..a960bff528 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a7dfafac3676b9cb89886b4c1c3b2384dd7f75652a1c013889dacf7d5ecb8773 -size 23974 +oid sha256:31cee1e647c74c67740320180af54509e466ad162ed56894695b038ccbe35103 +size 24017 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png index aad9addcfa..fc8aeb2409 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b8b39f7e59e23e9be33e5b25375403e622935e709bae3c7669c80a350d19d25 -size 21998 +oid sha256:8bdca1cc8a99976a8c4a297192650a496a4347dc27c73d1950f693be1cf2cabf +size 22005 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png index c78ea7e982..aa2b293c3b 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cbd62f37c69fa71c52442494efa24ab2d9b56c96dd9ba0d9e35a04917dcfb8e1 -size 22895 +oid sha256:604243eb5409e170a760cda08fca1662b7694c6920f7b18da8d4c4f9d60ffe9a +size 22915 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png index d62536a9c0..1f6dce1201 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:906f38a6ea86f1794e86ff4a4f20bf620f280114e234ab35db7165644b8665fc -size 23403 +oid sha256:5d3bb32677abc81ffcb892839c5609f27637a9ea8081460d3f95751a03f125aa +size 23426 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_0_en.png index 3436cbf43f..7471641cf7 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:81507775dafb6d842b65a66f2982ae7816ffca1f9e96b912af85bb0c50002e28 -size 310974 +oid sha256:d774f17a24d0270c5cb8419dddef5c9e77ba0fa26c8b87e8131387b262a844c7 +size 312065 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_1_en.png index 4a367a49cf..bbe1617319 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0cab598df1a80c51051338f60a2c7a5cfccd9b8288225f54271586aba15d22cb -size 305113 +oid sha256:73d531b662c5ee7371306d2da90cb349b742b3e9e955696d0e7ba4dda435aba4 +size 306772 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_2_en.png index 99a5a54fae..20e76088ef 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9ab8bdb21369e9342fb173ba2656d54e3617bffab16113635b35bc99d47e2c7 -size 308609 +oid sha256:12eb9a70791bfca39057aedf11abdf10da3970fd7405ca3ece1a0fa3d67529df +size 310310 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_3_en.png index 2448f1f0dc..4cb810de6d 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:238fdee61834dda91ffd837f5e4a347387635e107897a444331df5ab2939027e -size 303967 +oid sha256:47a450cc178bd56240ee5eabf1259cfb43986f9bcd2fbf5e4e54c54b845a401f +size 305482 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_4_en.png index 8c7866c018..2268ec40ac 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9238fe3e6c1cfd42171274979243bdf2cb6faccd7e871a479f635c90b180f51 -size 304533 +oid sha256:c05e6d1bcc7c807895bb77a361ca399ce9db24457d5b0802697bebdcee71f53f +size 306019 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_5_en.png index 46919a4d13..415d0cc542 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ebae03319afc453b93df8b2d93f386fd9113dc3cbd20c63778f5b508895ecda5 -size 313101 +oid sha256:4bcae33b6171c0deb02af46618a5b00b30d3dac4495657e0e1bf2f0b1c03d7e1 +size 314201 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_8_en.png index 133535c6d5..f976341370 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01fa1c9b917b65afc2d1464fad177f7420dea1625eeb7c8335d8105664134e67 -size 312145 +oid sha256:ac09917f10fdcab0f54dc23bcf6189c8db3a0ed47bcf6f8db549cfa19409b2cf +size 313453 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_0_en.png index 73f9752ecf..0a0b4afeaf 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c14a3ae87a82f7dbed4af6bd355abe604b335abf1004ad3bcb787088512ba697 -size 391109 +oid sha256:4c9cccb5ed04a6de52ae035fb9b83747919509ebbc7c4460a37d39751c9ca389 +size 392252 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_1_en.png index 71f05d8fe5..6f499209b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec2d91d4731bd62a711a565a6882d77ba6ecb1261e0cabe3ef436d57655a267d -size 377944 +oid sha256:c1d280175bb5ec48d9400a42664fe00e15c0f4486802c2d9e48e8cb2b2ecb345 +size 379460 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_2_en.png index 9b5650a22c..44928a9a74 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4aace29676743e516388ff9dd32ff2a953b07275edf72f76f0ad7aaf8d60e45 -size 381186 +oid sha256:3f6e1ae050b534c4b9bc8c8848dde8bab3ef49ea81132d19329e243050175439 +size 382668 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_3_en.png index 8b5843bb89..31ad76d4ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5400be8c794a8a538683f1e0c1161cd516c4834edd8f139d0fe7f64279295c8 -size 361782 +oid sha256:2eb90fb042e21f10d37f8b3b19782572ccb91b2c3a551637627d919286d8bf66 +size 363642 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_4_en.png index 24e8c84884..c94eaa8c71 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71654cce259c93af99e655285a481f8cb1648841a908553779fcc9b5fa0c53b2 -size 362262 +oid sha256:4a44c03264570519c99172075992e9c3bedd3a6be211b56f05837c6e0ddd8e94 +size 364135 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_5_en.png index 3964454684..b42a999e84 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb971b62230078e00c1ba9c04d8b18d1419c1665c4f8f092daf111a739e1d269 -size 393095 +oid sha256:aea3574fcb361509f2c8c035fb5e5f7ebd7cafcf5e91197347f2ed24f3e45a84 +size 394253 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_8_en.png index 30d5478a90..e8013b18ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.onboarding_OnBoardingView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e622d9b43664c5a31b83b41801ed07769384ab9ab84aad57605cdb67b16c58d -size 392254 +oid sha256:13f5758d4b51dfb31dc028f17b3f847d6779339aaae5fdee3a1856daff1c7328 +size 393429 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en.png index b7c62995ee..583a7beb59 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e3385b54a474c6d722106abe9c20eae3895eb6bddbadccf7a1112ce88f87b39 -size 50304 +oid sha256:bd5189b1079f9011162ff7ba2c9211fbfff543db892b86ea3b57ec78495d2019 +size 50344 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en.png index b450aea25a..1be9bd5d99 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.searchaccountprovider_SearchAccountProviderView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1ef764e86a5133cdfcd2595fef41da81b1eb8bca427c7cda9a5145d3d6e30ee -size 49302 +oid sha256:96742102f57f2e58027e3402ea01c91ee1eab6010dc46ef8ff8ee3175264a628 +size 49259 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png index 3783974c39..068a5d0023 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9912a8d83fd78d27fa6b01fd9034a03e50bc598f10330681c51fc776d5541bce -size 29420 +oid sha256:1c792aaf65bc7b87d3a2e7cf034ab7a16e11cef50d1c8d7bc55e319dba8f656f +size 29584 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png index f594f885e0..3a1db412e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab09bad33db524c5bf21815b0573cce94a5a04a3cb1a7c5eac08788a6fd43bc6 -size 48565 +oid sha256:174878f27d737484cf3121ea7f6019f90098f02007c85c27f4b4cb58c1f9a38e +size 49028 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png index 336b672698..03f9cd39b9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:028dc1af0a32614235945f29b86fc75f7e4101115ca6bb24a8519d9b540e3446 -size 50076 +oid sha256:83d2c2bde2cee9c9bd385f94131d5f3d13a24b3e8705b4ae8f47ebc0fc551550 +size 50465 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png index 5a7092ba16..18971cfdb7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:050194b3070ce4e062b419467c0429b4ec025bda070dbf9499ebf22094d930e1 -size 43582 +oid sha256:bc6ddbbfa3864a4456e564ba76ac303fc2f4f1362fc710f064f6c72e4b99da2f +size 43755 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png index 8888dbdfcb..b6f510f5f1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:979969357697032a7b7e5e715f42434cee98e6ad6eed439baf79ca0b972cef42 -size 46476 +oid sha256:6e42d39ee8965360d92cb66485670b48c265c0728240529c3d35d14a27f325d1 +size 46965 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png index f1b598d66b..e3b257c5b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6ca9ef59f9e436190c1342dcc0376c88bf46c8b6b2f84b6a487d3bf998e94bc -size 44877 +oid sha256:35262a34abfe83de81ba1000168773fc867ec14a73daa01ff1c40396fbefbb36 +size 45255 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png index d70c672fda..8b0d0ae6cb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb661596edcdda0d2a5f57c72a396624ab6f4291d07c0224cdcdeba67fa48071 -size 41955 +oid sha256:2cc504e426c4e96b635736c43f0495d226c9fd8dcdb822f38fe3439bc1478326 +size 42260 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png index cb1af3bb6e..002d56ab44 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:834245a21eb2bb644b5d9afda81346c37a3a6121d20d5c14c562b100cc5b913c -size 45046 +oid sha256:5c365cbee07a0c25ddb41085eb02dddea84560a5bc0bdccf439e80f46f889005 +size 45557 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png index 8b6616fc18..ca3cb0a3e8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1bb9f6d15e6556e692a6d879202bf6036d9cf1b353f317b911cc7ca379c2a90e -size 43190 +oid sha256:61f557888cff9958c99d1e973e4819dab7d23f0eb261d47a69e14ca9e6beb0e2 +size 43498 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png index 02318d8ce5..80eaada8e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e01aa32704fb8d1f2b7f4325f94635b345ce3117e384923e8132a68b566d8968 -size 44964 +oid sha256:c478071682838cd4cc7de83ade5de09a522eac5b1bc0261adfd6b4c4caa6899e +size 45379 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png index 9b0b7bfe4f..2b3e376564 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45eb96b553465eaccc2e5081bb8b867a8cd2d4e5ed1ce66767828bfb3b7fc0fc -size 34176 +oid sha256:d2ec2f9105e3aae1f33e98d2bca2743e14d5f9239ba7e78f4f91004fcded11e3 +size 34412 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png index 6170e24768..402a0cfd20 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9a6d982e6a414650a917da3e66b2155f8b6ce3285ca4fefd4afcd0df7f6184c -size 28432 +oid sha256:96ad3fabe9a1753ce36f118c4eaf7cbff8293c5c05b25280f1601d6c006bd055 +size 29010 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png index cb440db48d..043546e64a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06180ecb1a875d6d007a528730d53d4913c733d8b1218ee69daa3df557130806 -size 47781 +oid sha256:0ade5a0171e07299ee3434ce36ccdbe66a4bc5da81409774cfc35d3b99459b20 +size 48268 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png index dba9e6d4c8..a04f0c4bb1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:670bbfdc5ae48ba97911716db461ab391a57e94764508eae88c594b68e96e826 -size 49278 +oid sha256:d5507781d7fbd2cd083f6a9c75118572f269b764da21c91ad82760139ee61460 +size 49765 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png index dfccd98a28..dec09e3069 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0d0257a4d2eed51e9c18f3afbe0e39fffb7440e0ce749eec8959c9b4e5e063a -size 42723 +oid sha256:6b5a66bbb9741274a14afc0e9c117079b4d184623620523fd11af73f592ac465 +size 43214 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png index 4022cb1368..a3529b5d97 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05e6093a0a7e2387c2c06270416e53c0654353cd1e348829c31f1377c618374f -size 45875 +oid sha256:bf69710dd5e9926970b9c13ebbe5dbaa9d2e87773ba7c439fe18f3474459fc40 +size 46325 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png index 7f7642064e..a4c1b92d16 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b021dfc67025bf99ca1b6ad8b28afcb29611716635a57f4c3e2b250515f63da6 -size 44357 +oid sha256:ddde9132a3640c4e41927cc53506d0628effd958ab2f38cc93a965469311c3dd +size 44783 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png index dc562de97b..df9e68d874 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:199ae1aa490d6b7c3e4e0a2c4efedc5fd8f9140d18be74baf9b67023f9bc2165 -size 40888 +oid sha256:a228c7efae3558529141ce22a0392944c2475902b217ce11c2217afa136163ac +size 41453 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png index e79cd5a5d5..f5481bbf61 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b5a85043479aff4f13fe1b2e86ad4700410dd9c57219659c0b2cf93acfdc6a2 -size 44679 +oid sha256:e67888597de49ad6c67fcc4bb0e31393bc0c61dcbfecd8efe01ea51b2a067aac +size 45073 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png index 4825735975..7b830f1377 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bcf537c2f4d01fef81785ddc0b8f5133e2bc1966e6837e239ccfc0a06f14d18 -size 42111 +oid sha256:3b9d919df0d86bd8e3b177bda45084b40b89803a4310e3782e50ce19ce00fa24 +size 42624 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png index 225a8b94d7..7fd5f1293b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f27444a111e07658820b19dcc780219ea80b2ea5d01495ecee1255c0e84650e -size 44507 +oid sha256:76203bf3973c8a5234676309fdfff32cb312e2f57e8e63a99061291e9fdd5219 +size 44887 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png index 46c4f1942e..41ab0f2483 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.actionlist_ActionListViewContent_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbe4516b52f897a4f91d229f3a0f1bcd3a867d9494ac894d11452bcdf9407f2c -size 33013 +oid sha256:3b653b0dadf9e69b138bbb0d51e4e2176e0ae6db953056daa0af1559bc747fac +size 33495 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_en.png index 3bd0c2ba54..148289d4dd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51f0b3f7e4bb16728f21055de37b7b2780fd2a1fc65b6bd4564334daeab20763 -size 329042 +oid sha256:b64ae2fd2462ec3b62750084f47ec29c984ef4279a465b926c9d36e23834092e +size 328321 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_en.png index bf0a11f093..21d03570b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5febc6580e4f0bda75a27445157ace7f1acb620c17cba55ca5d2a9330743c1de -size 283397 +oid sha256:864883e9220a4d653d2d6b555ace89c77891a1ade04cd2f49d89c8bb765c6774 +size 282733 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png index 2ae328d7eb..8edee63bc1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:34b6dfe4e65612615c3dc87e5f65bd0b160d97527c4a4749b496bf8d48819d96 -size 256641 +oid sha256:de82970da241172b94f822f8792e6fc721dcfc7f0f67e3523962e253e9750884 +size 255933 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_en.png index 553c54a63d..1857dc249d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d99c470fd5134e0a84b284ed32f4c93de01561e630ef32d7c22a4b476bb871b1 -size 277852 +oid sha256:e95d7091485a2e5bb3ca8966c8fa93f21e2e5fd2d939e7582224ebf32c05b619 +size 277160 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_en.png index 6c3a6f4bf6..25a72fa80f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b15a04a861812e3e4dee0a6a30c6afef4ab171c5261d1e5bd5a234bb7296d97 -size 251908 +oid sha256:1ce3085cf45a94e014c9ea79a46d47741fb098853ac81e7531fdbfe32e8d6f5a +size 251213 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png index 530c5e5bb6..ccfdd7d9ed 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c32b4744750b9f18612bded2e292dde151e2bfdd8a69a36c88044f5ca3a76f8e -size 311315 +oid sha256:fe6cb72de5079be2ac02ec39f74bac0d20492cd6f5509b71ad9cfc4cc52955d3 +size 326468 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_6_en.png new file mode 100644 index 0000000000..374a59ce84 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:846467c023fb2f6a091c6d350927c2891ddcd164dace189d157a8570339e2d92 +size 282932 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_7_en.png new file mode 100644 index 0000000000..b7cd1d9387 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91472488cf265e9ba62a8b6690fa34ced41ebbf7a4668424c02464086aaf9f9c +size 283181 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewGalleryView_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewGalleryView_en.png new file mode 100644 index 0000000000..bce4dd0969 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewGalleryView_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed2c757e43dd8b25eb10acf32223168d10231ab2c9a9019ffe6b4eec6d656087 +size 343464 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en.png index ccca24ef6a..91c617002c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a14113653096095323ecb94cb3dd694985717b8585c8cfc6b7a45cf7a2483a79 -size 402427 +oid sha256:14ad2df78cdd8422279c413e9ed2f709636d09cf04b3ee4ada5b6b53e8e42c8f +size 402328 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en.png index c511e0e162..74b24f7194 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95c64e1e7055dd048b88f0e19a57fe696ee93505d74f96bc4f1915fcce769d7d -size 402072 +oid sha256:45ade3f4baaf0b91300a6829fbe42818d754ccca64b1b090195ee40eee744ee9 +size 401973 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en.png index ccca24ef6a..91c617002c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a14113653096095323ecb94cb3dd694985717b8585c8cfc6b7a45cf7a2483a79 -size 402427 +oid sha256:14ad2df78cdd8422279c413e9ed2f709636d09cf04b3ee4ada5b6b53e8e42c8f +size 402328 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en.png index f8fbf8c1a1..171ada1369 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccedfe061af8a77da7ddf6b20d23899bfff986fd6c74b87480b588e148ddd8de -size 89013 +oid sha256:c6e4dd5eae99a0454d6918b65baa3ca36c2266abfd9fb37dda961268e55827a9 +size 88994 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en.png index fbff934ed8..ea4995ba89 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f52a267ee2aa300185191aa3e610787c58d7222bc8e4a7570879d4c5fd37133d -size 328936 +oid sha256:0c6a5c845db0d9ffef0074062cea67134bdabbe91fd1826b2236a0f92e4a6dff +size 328222 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en.png index 5f90adbd8a..c21cab9cb2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1feeb32f9dce486c54db41727d9d9801f606353008945988331c2ce391dec451 -size 75364 +oid sha256:58ba9fd5edd2aa366b62a0a8880b6a3f6f7142861180c4109ba4904c43101433 +size 75343 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en.png index d7cdc540f7..42cf04b201 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bfda29fcaade9508e0d742b0de7ac230d41a358e98755e4b08f1ed7d5affe30 -size 408106 +oid sha256:43a670de0512321ca3e1b5bf0c967c6bd8504df542781c4973c8806b8b95abe9 +size 408029 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_9_en.png index f06abb6c7b..84cc698a63 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview_AttachmentsPreviewView_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1fdc4e2d82297927d2062586398fda3f3b7f6febfde8888a062229caf713ff54 -size 85154 +oid sha256:6c0ef41360eb82092680b5b262bf1ef8449636387124c5aef940a727b3bc6aee +size 85137 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png index 4185f46b51..5289eaca63 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:085963fcb425147d35a9ad947a7a3e4ba4712bd3d2f32e93099ff15cffe83b88 -size 64761 +oid sha256:65f9ee083a73669a0d3f9d88141a610ea53f3c39e89d8f706d414b04555b4764 +size 59321 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png index 2e70435fa5..d3f7da6320 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a3667390d9d88894bbdd5d72b0b714b29c9ff160653e310e97b0da87b6ba8b0 -size 54724 +oid sha256:8a94a4cc176b5d52ef9b21339749324adeef9857b6cdaa2ae973903e2408662a +size 55904 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png index 02d0fc8eeb..bd73e322ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f77d8243c23d3f37dff86dec53671cbde9fafe1314f6e6b445abdfe47d751ad6 -size 56187 +oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 +size 3657 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png index 0cf6c10c4e..bd73e322ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49f0bb16d3d57b59242e704e3dd4e8885c59721a42129837ff6a4f0d7d02de11 -size 54433 +oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 +size 3657 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png index adec213a8c..bd73e322ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ebee4aec3dbab6e1bb05fda7c5e423f0e931560743d0f0ccbac6b70fa9ad808 -size 52921 +oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 +size 3657 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png index 986547c8c5..ed3c8abf17 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2acf7cae297e8be76765b392dc07a36692a9e597b8f205de31a04dcf8b6bdca -size 37918 +oid sha256:a1a4672f87cf79f8052e29650be198bee1ee6c00a24ded5fb243b6a32b51c372 +size 38017 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png index d333d2439d..6798590348 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer.suggestions_SuggestionsPickerView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:47b4d158df0f83631d099c072b8b3d95a57d539fb9e8d7e6802f6a90a3b78284 -size 37904 +oid sha256:f8c69700f738d00379102fac8d2d1f33891983558d4a650edce317282e16b6c7 +size 37737 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en.png deleted file mode 100644 index 303a32a04d..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Day_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:36926eca7b934f7794ddd73e7929861d8837e9ac51341520c883043dc53d1927 -size 25026 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en.png deleted file mode 100644 index 32c4015a76..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentSourcePickerMenu_Night_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:493ed64dc981851887506ce33cdd063a107c8d5e6376027e7949a248b88e2a42 -size 24167 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentsBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentsBottomSheet_Day_0_en.png new file mode 100644 index 0000000000..a0304d60fb --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentsBottomSheet_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecda20f80c78991c5835e3e32fb18db8e08ba0ff8d8308c8a3c06ab46687006f +size 27083 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentsBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentsBottomSheet_Night_0_en.png new file mode 100644 index 0000000000..51af377a1f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.messagecomposer_AttachmentsBottomSheet_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ac6266d2081724960015f80dd7a489a6746bd4bd705755b92d91500e1f7bb2f +size 25443 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en.png index ac1b698ddd..8a295a919c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70b06a4411aaf9fccb7dbb68878ee4a01b0987fe592a1aef6fe474dd555dbd0b -size 42536 +oid sha256:e28b5fb8181f780a372aa944291ef23349f4acc3460786ee152d8e281e85b866 +size 41993 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en.png index fc55c74f1c..14e06bbe27 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.pinned.list_PinnedMessagesListView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ed9d6c254ac362f84b9be0761f0bbd7aecb14343a131d54da4b2be0ad033f87 -size 41165 +oid sha256:d20f6311164e291ae60542c2316cb4d438058322fca1b0db0980f0579874f9c6 +size 40650 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Day_0_en.png index adeb4f7c4d..2810ad22fd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c02999b2d0eba92f1e9b1f5fac52bcff303401f177459d1a439b7db906e5c2a -size 64622 +oid sha256:3bd5c5c53110eec56892fa6f93ae8727104d7eafef03e669181e0465096bad94 +size 64980 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Night_0_en.png index d89f062c11..ccb7dee9ed 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.threads.list_ThreadsListView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a7f6b64bfe0b47546a009efe23060ba091adbad32288ce546cb3b030d7a9ec88 -size 66177 +oid sha256:e3354fc31ed4408c4b53b63f04b6faf3c590308b9c45e5a18538b0a9cdf7961b +size 66453 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png index 06dd93b269..3f12875a5b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:578a3707102c7754f607c3a14f94f32cafa30ee570db174386533c484cb4773c -size 295031 +oid sha256:7076c9a44a433cd9eeca536365ae262d39b4ad99a8f854faadec272cb1b82031 +size 294992 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png index fc985de87d..29e7582971 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineImageWithCaptionRow_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f358da2b9b0521c14e525bcb2bd41c29c96aacaf5f007546e6d362bde2ee3fb -size 612526 +oid sha256:d6441c572f64d99bc119d649e5e6422fe516b9d097f310ccbd99a9ddded9609f +size 612494 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Day_0_en.png new file mode 100644 index 0000000000..59219a4d99 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb3b4e2147056056ad80681a4738aaf8e16407c14af12a1fd556431ff732f54e +size 15377 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Day_1_en.png new file mode 100644 index 0000000000..aa00f45355 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa4034a06aa6e8d24806b640d9c6604bf4cffc5ec5664d2b9b189e6c39850ce0 +size 42543 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Night_0_en.png new file mode 100644 index 0000000000..6c7d35be62 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75fce2e957c6ba2da818557c4d02c4f96cca05541a02d51b36b72017a88f81fe +size 14743 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Night_1_en.png new file mode 100644 index 0000000000..29714c40b3 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAttachmentsListView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b777363de123a6de81360e4ee9c5066c8953ac103c52349979e4c3fdca1e20c +size 41699 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_0_en.png index c056ddecb1..e76e0db72d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcd8208f3737b5b5949af591d2417d16f2da18609f3770201f2e87577b250b2e -size 8947 +oid sha256:45b2370c78dd907e5bf7c5df18b98df636e1099cd1de5b54923f7beb9bd17ccc +size 8680 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_1_en.png index 775c2483f8..429d9d0355 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d114f04976fbce895cc53c2c57df8af1e968067d4ed451c4a11b00ea008e14e -size 11127 +oid sha256:cbbbc103c2a7b5e8d942e0af113568c28dd62863ba0cd1dfb7a5dc9de56b3760 +size 10863 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en.png index 4854996fc2..c45bb0c16b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36487e20168db4594c519e4a6901b18d0e10604aaf10f07f9aa95d44647bdbd6 -size 20287 +oid sha256:f758005da7c969bef056ccf52d27a099e3bc5e900643e50990be430d640edfce +size 20031 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_3_en.png index a27104d999..faf7f18e65 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3576dad3e0443c638112c329854fc4d8818f2045dd2e17fe3a0ccbe9a9b1394d -size 11048 +oid sha256:c43d85e4658b9fb930ef76258479a876d5cde3b545bc4f4a76d86e4ef2d7a82f +size 10773 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_4_en.png index c2273c12ee..f8f7b243b3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b4dde4370b8bd6d2bcd8d3c9a877595661ee1b1296dec0f73b041fb556a3921 -size 21282 +oid sha256:c836c0a00fb5697138349028540d5e1cb4f1fddd2fd50d388cb5a1b55ccaa8f4 +size 21023 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_0_en.png index 7fed1167fe..ee33147a2f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc2da3562566b433c6fc5dba185c13127f86890b26644e41d9b5c88f1d130fb3 -size 8671 +oid sha256:3c5351b6f9f14198aec7bb4bd6353b43bbf9f487e192a5c927791756dc354ad9 +size 8431 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_1_en.png index c74490bfdf..802d8b0445 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0870cf3f791d9a1f5203e4d81c01fa986a03a5fa44589befa9f8163c834637e3 -size 10799 +oid sha256:92feff534e8ae02d574f5bddc927bf642e3199dc4f2d89a584d087058d18fc01 +size 10565 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en.png index e3f7918645..013938783e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2031bd6ed35ec1de5a17d1f85aa52c4cb62278e56f1ec5df48c0afe2ddcade38 -size 19216 +oid sha256:2dee0c45a8848f8771bcb0b60f368ccfef29beb7528c227a1a9f07c71a0457dc +size 18940 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_3_en.png index 6ddee33e8c..f5db366e09 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9cac5229b5129b2bc21cae8ead0e7d19b58922056064f28bf0f59074b4e21e6 -size 10742 +oid sha256:9fa672f2cb7dbf0fff171d507e66d1ed8494cbcd93b48bef1ee1b9b75d6717e7 +size 10499 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_4_en.png index 826b4193f0..2ed11e26e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemAudioView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b693ccea2549b9140beacbf2ffaa8ce409ae7c7f2f9cea0050e56527c2c03fe -size 20380 +oid sha256:5735813e0f9c40e5d861ba0c35ba73689ff7ee41224829289ce017746323922c +size 20150 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en.png index 357520ad31..6e88f8cb19 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:043671b3e2176b35ab9519be38ed5711f3eee99a8583583c6fde11f58250aa48 -size 8251 +oid sha256:e155260fd46cf1550c823e2b0a51f3f6529acfd131fc73a7e66dcaca24f3449e +size 7934 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en.png index 36d8c49114..65beb3b8f8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cd96a7daf5c19176ef997fbc80a75c3eeb19d470519ae1d57027b5f388736b1c -size 10526 +oid sha256:49a670d25e379b2385ae14a814cd4aca9a0bdff00c3d62d31b146139c2d0edbe +size 10210 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en.png index 317cdaa271..33772989e8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bba55beec2451cdd8eb5237e85ccaf37d98ff86435015ce019f8ef2f131fe31c -size 20520 +oid sha256:d633e28eea9674914bb018b113313c2e3aed6463e2de5901243f5432087a3c1f +size 20237 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_3_en.png index adf5f2263f..c65619f05d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:207dd1bfa213f3153cf2096d6e961d4c1048664fb2bbaea546af843bb96769a4 -size 10349 +oid sha256:10b79226a4eb5c67afc1fc8ace8c6fb49429a69b1e1518b622dcfd20bc2820ea +size 10032 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_4_en.png index a2ec73f85d..d68ac1725c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:15a00a56cdb8156a78905fffd95dc5196f4267768a60a08416417322ec6c9801 -size 20640 +oid sha256:085310083c4150fb70e48087881e529f17005df69cc01dd53807a06266f4f4bb +size 20317 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en.png index c7503a4391..4441c3db6b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e1b8818e2f1e5f822b9560ec30297460bab89f05d94e36a989aaee4277ae1216 -size 8071 +oid sha256:555333bf67a1f4460c0f0d71393c03914fc67cfe6f4e5161468aec1d95e587e2 +size 7803 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en.png index 6a70eee4fa..2755d2b93d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f3bbd229376c0f2731f93cda00e4580c45971e4ac07bac7b2578d45b48ba079 -size 10220 +oid sha256:36009b81c172786ab1d87834b05550af706b355f8d044d364b1f15e58097c8c7 +size 9945 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en.png index febf7e36c2..5c5063083a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2e3ff1bf09d9e616862c74ef29f07c280bf07af8355eb282e51745e0f6927bb -size 19380 +oid sha256:d40a8265e7bffd24954d6fa3194c8c8c65b600518c23d6089b540adabcb751e5 +size 19141 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_3_en.png index 5e1065d2b2..48242a7b75 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0aadd6c4d503ebf0224a941c798363e3302018fcc9e726bc31808ab7c5381504 -size 10130 +oid sha256:4ef1884c4cac3debea52affbab071110a49b40cebfd38b316693085464fcc440 +size 9859 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_4_en.png index a9fcd11f7e..3146070439 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemFileView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f44732ffe4caa44b3fb62bac8a6da3e15a7917f0918314d0f1407b08c8b72da -size 19820 +oid sha256:983620627af06dc1937b040fe21b3e12920e84116cc584fe76a7ef799473540c +size 19547 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_0_en.png new file mode 100644 index 0000000000..b06744a137 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a649c1213f7577e41c8fb847694a433fb8296008b020ce9c11b9f19e4daf2362 +size 366552 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_1_en.png new file mode 100644 index 0000000000..27e0ff2c99 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85f7b816d7dcc1a825b0cdeadfb210809beea7142fe26a9e87ea4ef86015e2e3 +size 191317 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_2_en.png new file mode 100644 index 0000000000..1b523f9e94 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c675d5b6ea5bd2b5d1bc780cce41ecc179e4e2a2c1f0518069295d4d7b6d1d2 +size 380356 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_3_en.png new file mode 100644 index 0000000000..1b523f9e94 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c675d5b6ea5bd2b5d1bc780cce41ecc179e4e2a2c1f0518069295d4d7b6d1d2 +size 380356 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_4_en.png new file mode 100644 index 0000000000..1b523f9e94 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c675d5b6ea5bd2b5d1bc780cce41ecc179e4e2a2c1f0518069295d4d7b6d1d2 +size 380356 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_5_en.png new file mode 100644 index 0000000000..e169c383a0 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f1d54f890b8e463ffb2a7b7a0b39f1ff9525fee74ef5884171e3d29bd47540f +size 349978 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_6_en.png new file mode 100644 index 0000000000..4d6c2f9914 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a45bc7d128c477a017d3f64a1e7ae14b4de888873fce20e5b8f146871f52d08c +size 372020 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_7_en.png new file mode 100644 index 0000000000..5bf7ad4ca9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f46ed316ce20fdec7c2a8ab834cc68c0db8f1cf5dab05a3835133274bdf74968 +size 372000 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_8_en.png new file mode 100644 index 0000000000..0a7fb286f1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c27d90e1fda73f23de789341fb7023501e7a9f1080a2b8f684f3f0e923a1e618 +size 314293 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_9_en.png new file mode 100644 index 0000000000..14393b4454 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Day_9_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1cb42c166ced625581718e7f0f11fe9a6a04a0fc9ccd907addd368c44884069 +size 309093 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_0_en.png new file mode 100644 index 0000000000..36cd635ba6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4a12a0fc4ad8f9d5b64a30e3d7ba8c678dfd8582c98b668d292594dba7b2742 +size 361947 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_1_en.png new file mode 100644 index 0000000000..f94ac769f4 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2aafd40abe6880abadb610293cc06a38a1c7e995302019336e4ff33192d9cb4c +size 191195 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_2_en.png new file mode 100644 index 0000000000..01dad74894 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0d656a13c24c54c13e119da73f14e0523dce0ee76a9197783043ad5bca07b57 +size 380109 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_3_en.png new file mode 100644 index 0000000000..01dad74894 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0d656a13c24c54c13e119da73f14e0523dce0ee76a9197783043ad5bca07b57 +size 380109 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_4_en.png new file mode 100644 index 0000000000..01dad74894 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0d656a13c24c54c13e119da73f14e0523dce0ee76a9197783043ad5bca07b57 +size 380109 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_5_en.png new file mode 100644 index 0000000000..71d008600c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:595438b4666929726f244b5f53fce3507bd6aa0fc87b10ea9706ae893a849a7f +size 348050 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_6_en.png new file mode 100644 index 0000000000..d2eafbba35 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e813d8530f1083a960a30cda348e7b68ec54b02f62773fd83788054d9b78a8c +size 371473 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_7_en.png new file mode 100644 index 0000000000..c4f9b5ac91 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f8c6615f0b06c1e1a358622e0598aa89bc7c7e2b5bdf7daad269c92434e124d +size 371473 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_8_en.png new file mode 100644 index 0000000000..c272bf13da --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8e5cba748f3505bd3d34c74189c9bf1605a2cbb5fe534a3e2ce7d6df64065d2 +size 311163 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_9_en.png new file mode 100644 index 0000000000..146e3a9211 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemGalleryView_Night_9_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c144e259fa322bd899a047ade06c7105a6d5f41732193baa9e1437067d7b47f +size 302873 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_0_en.png index c11e6b978e..90adfc34e0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3daba890afd2533e1746f1ffd0c535674a4a238e4591da2a6bcbe31716d26858 -size 143676 +oid sha256:2ae9812763faa89524be29c0b796479c51092e570d31667bfbb7209e901dca83 +size 225821 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en.png index def7635efc..eb605cdf3c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9f2f0e8ba6829cb3d83dcc0c6d3ed5a91a0346771f84adb6731ba5fdac01f4d -size 122009 +oid sha256:ab6262a03bbe7e4ff33ad1c0655652b58a78cbf6aa0a2e4a8f794f7b347cfff7 +size 197616 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_en.png index 07613eb447..7a2c4252a6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f85b9e88dca466b567769291fb69afac535135c3a07f412d6b8203968460519 -size 120940 +oid sha256:1a8c03a738592d5ad555e1cbd07b5169edc45de18044dee9139dd15763d58468 +size 197204 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_0_en.png index b9280ec225..179d838b9b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:463a2e544b2806f4082c813ec3ba8c6ce0ad0ebcd8ee32666806757a90c248f5 -size 57131 +oid sha256:d761883dee687ae4917949d64b5f6fe13daf1d54ce8ee05785967c4906078560 +size 80994 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en.png index f06f86068a..12c1e7fdd5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00da192b3b46897c9d50986ecd84e07332cd2b490ebc8f3893a9497e72f18af8 -size 41478 +oid sha256:848201daee4c16c24dd6d29f6244ac24d197832c43168bb5d76245ebdaf0d643 +size 73421 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_3_en.png index 4cb5fc6e48..78bc8c65d4 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemLocationView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c015bae5b3ce8c4447c62a13fb74d855c23b0e41bf0b128a1834d30781c0d1f8 -size 41110 +oid sha256:aa9d77577784fe54259902d90d447ca253de22c2a9f8e62d767456a5d52179f5 +size 73006 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png index 804455160e..276c82c9ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ebc7039d4c3db7d0a7cf36b7cb317576b9eebac16bd29fc542193ddc78a3467 -size 46843 +oid sha256:35741e180e6c07b452c485099c11473e80ac308ae81d3620fcd8e3bd1385f977 +size 46801 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png index e913391bce..1b0aa01151 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:beac2c2c811c1fe6e8a1ec28fe7b17e9ea4dd6641d9c79d0b7c18ad3ec36a508 -size 48920 +oid sha256:9172fb348403a2f590f2a3fd522a9113e5a9e1fd06fae07a82a453067c5c87f7 +size 48876 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png index a73ab70bbe..7072bbc0fa 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:737a2a37bd4b753981d719e70c366688a92ebfca62e53a1e60ae81a073c40f14 -size 48858 +oid sha256:b3e60938f89fe4e56acec088683232dcce2b13deaf55111ef3e049857dfe2585 +size 48824 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png index 05d46d854c..1ed803b334 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:087de5e8ccb4d69ec2c1f12aa7c64876228c3d54256852c7b01a4944a7f34e83 -size 48929 +oid sha256:997f60386b4fcbd305aa76c71c95d50860ebb276e6977c8e9ad8d3b49ffd5d24 +size 48896 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png index cdf797ba54..85edbd5662 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:effa17c9dc842c49c1b67be244f0c8c53e859fe80dab54a373d7536ce3898e7e -size 45498 +oid sha256:9b64a00c01448b8935985343ae33912c80dd84ea2329717b8addfc07dd6ef012 +size 45403 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png index 8e1812e454..6fc78b1598 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2b5f85b44464923de745354cd0aa028d94e235b8797207e82d8651a4281db87 -size 47662 +oid sha256:e4bb7cd6b419bf262fb959ef7062d842a9f58f84d85e4a928f11187ba692f739 +size 47590 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png index 1f3b56bcd9..1909c9455b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffda5057a816628a946e6441a90c47a469233a61d3c8da11d39797b8f44adfff -size 47649 +oid sha256:2aef02a3fbb01e4dc03179914298aa169800e2f866d678ea8fa53a492e5e451d +size 47577 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png index b733eaa9e9..69a497b6f6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemPollView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbd2c72e13e300bf3f223518f82f3573d70916ad0a274a94cf62eb4220770c75 -size 47741 +oid sha256:be08acaff0ebacc3a4158489c7bb7ce944c8f0b9246ef6d37bd58f5ce7519a94 +size 47670 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png index 80857358e7..f792a1663a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineVideoWithCaptionRow_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54e71f45db31e8664c42f8c05feb91ae839589e00cb89d12088c15c85fb9f25f -size 607824 +oid sha256:e3bb005a88e9a4d2bb850478ee8ac2c4f31d32625bd6d2abf455fade461cd399 +size 607806 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en.png index c4f6062ddb..c3e5011041 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0cab01f0ee35ce1c02d2cca172b90c34c27f088bfcd63075c27afe514c335b2b -size 5830 +oid sha256:5cd23b8ab206543d9632589c9c6e3ae157846cbbeef683d187f0fb8a7475b27d +size 6698 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en.png index a3923a042d..4dcdb1b9ae 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d3decc8bb6e090f11f074cd681d710fe3dbdb1670a257757d40b7d1f1bb5f03 -size 11305 +oid sha256:b161e07f504adbb140c80945cf9cd5b31dad4edeeb86d1b683fef4f02148a110 +size 12178 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en.png index 18a104b1cf..63b599fe61 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c57aa1289587a7646f1b594a44cb738425f3dc6fa057f4e48b34960ce7162af1 -size 16754 +oid sha256:df393203d4535dd63962cae667253c00c19dc4b6e25c887619ff5e833066f4ba +size 17596 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en.png index 0399d3d3cd..584992b643 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f0fa280febb13f2df22a930ee56f1a9f92bbb2782a83ec2f5768160176445fc5 -size 21849 +oid sha256:6f4886f895d90cbd175fab866329841b45a13890b923ee7928673698d320b60f +size 22940 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en.png index 33160b2925..659db847cc 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5e6b78ae1507cba5face18a6209f535b3e8643bcbcaa5913e368d8516845e43 -size 26063 +oid sha256:541e50bba5a4dd70015bbc5410d8d8c9b0cd194ab119918f64baf73cefdd618d +size 27956 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en.png index 82624c2964..3fe4168506 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38c4292a4bfd69b485f4d072fb627d457c50e675c2b13534ac3f75d62a3fc38e -size 31445 +oid sha256:2023632334cfbd15b399fce33cb5ac04135f371d6cb09669fd66f97bc86e8fae +size 32655 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en.png index 3ada2b31f2..15ae66d08f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d49f4b65797a915e6e2858d12d044f9745442ea9d68cd502db10589e7ffe99b -size 5623 +oid sha256:d7580ba96fcc879011f591ac4bacd16d3c7cdc7db51f39cc7989c7c4dffdaa69 +size 5937 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en.png index dc71af5d74..584bac4e93 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:988621910e3cf4792d9f23a69f2ec42ee46ef4fdaf6248a6ffd18f919ff433dc -size 10936 +oid sha256:eaf905401acff2b0000abc9c7a13b8034c55d12e355908dded5b1a24fe573fb8 +size 11366 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en.png index 90eebf14a2..43aaf422f2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b87ff2c70860a5d2c5f8a987440ff97ebbb97b03c5726948e00e7adcd3e38111 -size 16087 +oid sha256:e6dc3ec6b43eda48a6d96af60aa983c2a8c42d4da81ef48dc2bd783309de8316 +size 16469 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en.png index ed84f96464..6382583d2d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:909bbf2ef3308f5b92a2598b32480175a2e179d6c6ec99f749594d85e9762e2e -size 21317 +oid sha256:fa666b0e8ec6d77820c31ebeed2ba9fc9868d07e56eb77ff079b5cd2b2840224 +size 21836 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en.png index ebc463a73c..e9321c5510 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cefa811e8c4df8643fa53a715a2509e1af9090928947538c7dd212e6fa7a791d -size 26152 +oid sha256:e260c421c187424b8d139e75351aa3e654fcf28975aebc4bbcefd8f77c2d21d6 +size 27082 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en.png index 7e05f9660d..db2b180cfd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c126c9ee9b6039dc05b6c8133fd5879062aee404b1a9ab2104765ba676d909f6 -size 31526 +oid sha256:48537a0e326d7cf1fc36060fd2831bfa3b237806a79b492368471de25f331a58 +size 32174 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en.png index ab421633db..284d163b99 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35e02daa2a1f36463d5d0acdabd2b8ebbd972ea93d171daf628b643fdc995f3d -size 4653 +oid sha256:bb2ac7a95a8c022d73bc542e379762e82f3bf29ec92ba28c9c6db5ef75892862 +size 4650 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en.png index 33472fbe19..4b55a4723c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f5e23c5ccacb8edab5d86a1bafc482af9adfd734ea845585ef4f7c4ba52297b -size 4365 +oid sha256:ded635195c57d4b20a2aa8925adc2df072ee0da7c4faae0f360f16c2a6eb0600 +size 4361 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowRtlContent_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowRtlContent_en.png new file mode 100644 index 0000000000..4762972963 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowRtlContent_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9e6d26823bf16cb281760fa157685edcfef3937dc7b13a7bd22387d77fc6b9b +size 54561 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_0_en.png new file mode 100644 index 0000000000..2deb3aeb0d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19708f245fe36dc51fffc9f628ba973d34dfa17ffb001ba763f21795b869c384 +size 723818 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_1_en.png new file mode 100644 index 0000000000..b42850242b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36b99a288e36e90703a09459fbbf626c4bd08e25a98857cfb5cd75f2dbc4afa7 +size 764986 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_2_en.png new file mode 100644 index 0000000000..ea80da0650 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50b831358465da4fd2a49de0e6029a33561bbf28530b281171690f8d25f98774 +size 744903 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_3_en.png new file mode 100644 index 0000000000..fa21d48f59 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1fe348faa8c8adae205de19041a2e4fc3c1a82bc741c0fabf90df5da0aed206 +size 624607 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_4_en.png new file mode 100644 index 0000000000..3adce58276 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8d89b94128b47958bafdef99b338fc5bfd3586f73fdc2b665308fe0a9be8fd0 +size 719641 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_5_en.png new file mode 100644 index 0000000000..23ce668685 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:620849b893491d33f5b0a2a0f2d0814c40d111026aee52e299b893909b08afb8 +size 48309 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_6_en.png new file mode 100644 index 0000000000..7521205f85 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50ee16d8894cb50860bbe0dafb7f1e6002ba18336070875699409c1ffd1b7de0 +size 103322 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_7_en.png new file mode 100644 index 0000000000..829dabebd5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7381b146b64c1281d8e3032539c38270b086d2173d635d969dce3e1f24e07081 +size 76539 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_8_en.png new file mode 100644 index 0000000000..dee2a3b025 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Day_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d737d3c634a812cd2338be8c372de94a5f0a959e56be9b5acd6a4a2d83b57879 +size 39262 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_0_en.png new file mode 100644 index 0000000000..4f52d626f9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b26b7c4b25da7fed6311db1c79fc885ed7c237d48b305691afed0e4dc8c22cb +size 721899 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_1_en.png new file mode 100644 index 0000000000..65441d23c3 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7d74b2eee87465a649e0459c42cd2db2038da51e18e8782b74db542926284fe +size 763800 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_2_en.png new file mode 100644 index 0000000000..4a107c909b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6c375796b1058179fd449279249217538b51688ac7bdf517ff431fe92f772b1 +size 743275 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_3_en.png new file mode 100644 index 0000000000..cc52531a72 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec0b2e34ba1d5c05ee11aaabfddf3e4627eeb671242a44aa1a9368c1c378bba1 +size 618352 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_4_en.png new file mode 100644 index 0000000000..349a26729e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed41ea8189fb20c22a011694372d3acb6df8f4c81e01b1a03ec0eb56120934fe +size 706216 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_5_en.png new file mode 100644 index 0000000000..8857763fe8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a89c2d2ece84f2bd9a4613c84ee7a4090cd00e79de88bbdb0dc3b82f6f867b1e +size 47837 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_6_en.png new file mode 100644 index 0000000000..ac841eead4 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e2cccbfba9adf2c1aa799e98410f32fc3895a28552577ae5a49860cd04e9d9e +size 102247 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_7_en.png new file mode 100644 index 0000000000..b6c5b1a006 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b98b6d69d157f84bae3dcd9f8cfba2f98d1f8dbd923b9d8ec803dffa18f7d92a +size 75860 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_8_en.png new file mode 100644 index 0000000000..14597ddb08 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithGallery_Night_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9da51e0ce86a07b09548161e60b0bf76cae5dc7fa53929ea23f81f416347de6d +size 38627 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png index 3ac59caeea..1f0fdabe6d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a94d5198e27338675c0e15df5874ba3272ee315b8d77291dc7ccc7c754ed1f4 -size 365082 +oid sha256:b8bb5a6de6601da8d7fe59f110a054577e2e25dae4bb449f60c04e7d7a1b9551 +size 365073 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png index 86018764ac..195aa04fe2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8344427a0fe87cbf0883ff53a9ee4dcf90976a7011f6618d85961df48b2c53a9 -size 370228 +oid sha256:76e5ae44362792d570cd82f3910c8bd0acde509b8418c5892e0385e7d636f042 +size 370223 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png index 94428abb56..84d9d4e5c3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36d7cf2510d546d2b330b1d1b1674ce58df0558c547e443794a1e7b2222add87 -size 347897 +oid sha256:7c609a633ab23eae5729ecb57a17a385bac65e81cbf0180c01e0847f1028039e +size 347890 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png index 7ddac02717..73b7e674e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4ac79f3b8fb4e231244bd96b244a4f2526d6ed28d558f9d50734d83bbb74992 -size 363909 +oid sha256:991deacdfb7bc371a2df960a2364ae3b2187e588aa5afe7f39409e367040dd9c +size 363893 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png index 67490ba700..01d4dca84b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4431e2d9f30123949ea5676ce60f642234adcf9b5a33f2acc3f80ebf6609a66 -size 369730 +oid sha256:ef2bf449671b652cb152b3baab92ab100eab77a54229ab49daeab156f2f484d0 +size 369724 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png index 68f8148879..b5dac8434c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ca8cf82aa8ab1bdad56a27584b27789402aeb7ad8fadd038280a376fb75a72c -size 345094 +oid sha256:1a92f8af94682facac66d4aacb6e49f345561c15be2f8b689041b78aeaaae831 +size 345062 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png index 14a40a5676..a332744358 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a11044fe90227f1f316a1ade8587e545bb620e11cca76865fc2eb83cdb817fc5 -size 364655 +oid sha256:588967869cbd25ed8b82aff5618175660a8a9e45a5a861b1c7867cf1913f575b +size 364646 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png index 133fd3903f..d7b969fd5b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:426d1c844a8c88281c5fa4c61916d93278fdfd38f8cdf2dc54bf1a821f2de3eb -size 397167 +oid sha256:2528df873713755f542f61cd794080929586c1bd5f316c0378ce9e837c21d50b +size 397145 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png index d235670def..6e83d6491d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a00bd766a00b7e7c6615fc53bf469b3ca5056a6c514c096431ae38d99d604306 -size 364845 +oid sha256:34152c742abc486a48234e22101833bc163cf11979890d06aac41e68e3c404d0 +size 364846 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png index b10f9741b9..0021619c44 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ec1b0244dab22414c6719b3309426e13128d0c70fb67dc66cd8a60d42521fd0 -size 355411 +oid sha256:7b23d3a37774283067a8919b8c332b1bb5a79e90dceb7216b484b985491282e5 +size 355389 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png index 422c324695..77abe20982 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1df8d22766981fc76d6d767dc3f40d98cadc7c51be20417b067b91af604232b -size 367884 +oid sha256:5c3d87862c6d7fc88d0f23cd54c5b9f77028992fdd7c282a195b964dd17e85ac +size 367855 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png index b6d1f07279..47a9a6b630 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bee12a6bdb18fea5ac6997671bfcb903296da7278cf69b2456330066ca31dfb -size 342870 +oid sha256:54372845e922d047408dd960d048b9b5eae2263d589117d8e7d197741aa34f32 +size 342827 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png index e9d85990e8..a431a9429a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66d4b6ea4a697735bbb0fac936b89cde99c5077973ba828894bf50b5dae233b3 -size 362848 +oid sha256:93c2df04d65f6078ce3f7067fbae8a7317ec42ed0fc013dee962a3953269f3b7 +size 362813 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png index 0eb106f4a9..b51a89586b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:217ac95bf476c53d2dc6d3d0143b21312bf38b8ab86c8dfd4f9360582b584f9d -size 395476 +oid sha256:e642229c58169775fe702769a306bbef22698516ae6f7ac75a761213c3f195fa +size 395446 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png index 0cfd1dc985..1a8ea3e4e9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:545c9e8933e420cc3f8fbba0fbd5162c946c65a20721faeb77c568596ca720cd -size 363045 +oid sha256:66aba7b4271a990fac85b0bbc7cbdc371fa1e38a4da5bb4e2f62a80b21cb3a8f +size 363012 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png index c8306263a0..c9227ebf94 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:756f0cff90ddd61adce2f467c0384d74d430f6d51c091e4980e45bcc9ee6f0fd -size 353705 +oid sha256:e614f4a8657637c584a283d69124236d00fe1251c2b8d739c5688a57a6fd152e +size 353693 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png index 22654db502..c715905d3d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventTimestampBelow_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:341788fac989135f221178271ebdec2f18056780388f9413a3d3ed12904f28ea -size 54429 +oid sha256:f7ca58c03dddd32c419bdb5419767f6d8f784256fa957c2599af8311265fa959 +size 54305 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en.png index 85e89d81ba..d8224a523d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1730ce48c314caff6efe29287609dcea9f8cc6eda235a4e1f0a0d210e36e4fe7 -size 37453 +oid sha256:1d3fd3cbe32073e9e58032baacec15591dcd1219d87e17048c7cad709402543d +size 37455 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en.png index 27da587a71..0ba4ceef7e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewMessageShield_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78bcce34ea3a2a76333aa8f4e3bfb832507b49038c8e73a34c6ca70735db28bf -size 35828 +oid sha256:8201b2412df88f9850a28129d354bc13f77397dc9156c598b0ae64e962e00653 +size 36134 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerBothIndicators_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerBothIndicators_Day_0_en.png new file mode 100644 index 0000000000..4a73754a8e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerBothIndicators_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ff35c533fef9ca6ddd0e0f31ae4f4d5673e7e90f6d52d9636bfa62a045d8ebf +size 47952 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerBothIndicators_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerBothIndicators_Night_0_en.png new file mode 100644 index 0000000000..6df8acbfd3 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerBothIndicators_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbcfc8e7f8fa55d007014f39be61a2d8a5a895ecb51f06d83b4f65c13302ebdd +size 51087 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerJumpToUnreadIndicatorOnly_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerJumpToUnreadIndicatorOnly_Day_0_en.png new file mode 100644 index 0000000000..e5528b303c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerJumpToUnreadIndicatorOnly_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:990da337f293792e43768e9aa507581df18fac8b2b9dd01d7ad980e4239bec53 +size 47571 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerJumpToUnreadIndicatorOnly_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerJumpToUnreadIndicatorOnly_Night_0_en.png new file mode 100644 index 0000000000..d6b7840b7b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineViewWithReadMarkerJumpToUnreadIndicatorOnly_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:092e8d3ae1d219d48e3f696244cc83a53aa6402096ec6b7d817d3a115c6a28ac +size 50750 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_0_en.png index 77f5eb3cf5..5bc0436e67 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6852e8f7ab35f830864a94360450b7d4b78b16ce7cb75f2152757dabddf8868 -size 49599 +oid sha256:4f5ce420b36245b164131386d761cbcd003450a2f8d4789a5d5aa681e69f3a74 +size 48582 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_10_en.png index ce251301d9..4febce3994 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:877e252ee1e0c35efef1854bf6c94783add9138148a9e910bc7908ee7228209b -size 88375 +oid sha256:21c58efd51180d851fdba6c7ab8efa4c1777ef7339c0b8b249153b08cf6cc8f9 +size 87548 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png index 3907bdf959..5b74b9e857 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e157c0f0f115133f36dee9c1f1647fb8f00813a12783b18fa83c6972e92e037 -size 51116 +oid sha256:a97aa2dda9f95577c260015cc619c520d7cb363ce1f2daa1c790d4976cce43de +size 50098 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_12_en.png index 3ea50dcbe1..64f46855e9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00be45a05243c429344206d132d0fdbc6322c25c3c71dcab61f939070dd015d3 -size 63156 +oid sha256:fccf8ce1c5bb494b8a009390ea6dcaa0c6a17051d5f311f939006141f73a3251 +size 62124 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_13_en.png index b9da99e5c2..4f01516eba 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a19d67b394c682e329bc232b0a36c5015dd73d09931b7e401c5d306f922f026 -size 47404 +oid sha256:7e269908cdd45a3996a1b04b8e477a75703bbf01cede83d773460f64f6f49871 +size 46378 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_14_en.png index bd22123444..8d904ee1f6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:205d1785959ccc932b6f307bbe8fc86466eeab2be83ce80b265cb54bf75cdfe3 -size 64392 +oid sha256:41adea47d3fdd76cc8dd49c1084b17544078ce3881e6b4e91cccf673efa3bef9 +size 63367 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_15_en.png index cdd4607e18..4afbf06784 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4384708192ccd7ef69601ba4a37b491d1959f8ec84c3e70ceba148d716347952 -size 54368 +oid sha256:2a22c1ca92e494a08a5641bd8f34c9edd45129b8187af26764c4020c91df400f +size 53373 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_16_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_16_en.png index 32a9dd93d2..7571e9f52b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c3ebe62e38381e25e85c0be666ab6380811d2fbbea58461b917a0af4c6cb4d8 -size 64322 +oid sha256:788d2f17f3dfa8f4f63dc5a6454a4097a23ff984ec0985cf34ed3df146ba60ac +size 63442 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_17_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_17_en.png index 39bbd406ed..70999d766c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f7e3f1cdaf18d7d529be07cde3bdc9100243780101e73dd53c3d78639775974 -size 66862 +oid sha256:6870f4b12402d309b61277bb6c1c79cf4f7184d364c9275f10679e2f656a9e06 +size 66225 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_1_en.png index 2098c7e796..77e10c4bce 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3d8648d88afa54cc57ae97853e10d3c09e5f7a9e5eb34a1634cdd4fca11b6dd -size 70959 +oid sha256:bd36b89a823c06f75546ecfc55474650931fa9b70700244a1c333a4cad221c4f +size 69970 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_2_en.png index 414db592da..209a92fcb9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:467e5aee42e9041db2672dc0d37e98fc1090c19207604a31247f3142d845f792 -size 493534 +oid sha256:fc2fa4ca81add0b97d595a3ab69b4b9dd7296a0a92afec5c230d863df34db72d +size 492920 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_3_en.png index b9723dd5c4..2e4d309b9d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:723238ad84c9925eb0edbbf225b50a03bf29e5671777d9f03eba6b910ee00fcf -size 488705 +oid sha256:28afc0e4146fbb75e7109b0cc3f0beac4dabf2f69c4a9928d2389a6908be312f +size 488121 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_4_en.png index 482736f6a3..3472c572ef 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:31b6fd539808d47a692e33948145732b530e465eed7356e3a47bf7da157dcb18 -size 66920 +oid sha256:4b7082e677feb1a1b9ddfdbf2f02a6ee214805ce21a17b88de7369f7b41f0ed1 +size 64370 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_5_en.png index 44091f5537..828857e66c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea2bb433c696a382c2006381c987eae227b72a159d03d3e654397b00c909f203 -size 82141 +oid sha256:9c8148f10a526303a10cb7cb79487c94d53d4ef93fde817d8696fa6cd564ea83 +size 79960 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_6_en.png index d56d0cb66a..6f934e18ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:50307dd635bc606def8fe4b80068b7c209e17828718c7a5992127953226cd4e2 -size 71172 +oid sha256:c565dd13a3d3a40aeabf92c169f1d4afe0b324eb630890287237c5ea16f38071 +size 68671 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_7_en.png index 72315f46c2..884b902c0c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f0a63b3877b4ce2e7613164e9103a9ba935d64886ccb18646f51e0fd9750885 -size 100976 +oid sha256:faafdb864f31d90df887cb689e8166b6a8f09941391af8df6d47ffcf62d2ebbb +size 98965 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_8_en.png index b5a3d74b5c..63a4f0f7e1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6bc3aff28b9187e987f4bf41bb81460234e4fbf1f5976de84c5f0126dfd28455 -size 54529 +oid sha256:886b3b82ebfa02b88dfbaf8a4627167ee4c6670fec6b223cf605a253d3fc5e97 +size 53683 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_9_en.png index 6ff4840c57..c6563edb33 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbd5652457d495c3c6692c151be27c985cf47e95c8b89af9b6edc8c1b734acc8 -size 371265 +oid sha256:314e3df36d05e4faa6750214c7b44d685502700617d7a7c87c688beac9a91d95 +size 533638 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_0_en.png index a93be896ec..57e72064fd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c62d43a36212da9b518269767f647493556a5082ccbd1cb3919b608687112405 -size 49392 +oid sha256:358d8aca9d2e08fc55b7afd10f9577462ac5ab1f9abe95523c2f21df12d12240 +size 49449 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_10_en.png index 80dcc6a601..fce1f37b88 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e5dddb25a8a201e5334566c90a252111e0d8a65c9949e4f0b7d3d66b3a4103c -size 83890 +oid sha256:acc9ef48e0d5c2bc08ca02f5415e7751357c2b3a6136440c3c7c323ab73b667c +size 83771 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png index 7f114a43f2..fccd5d210e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f225e76a780b6a3eccc66c720f710564b82774250a3f229367b12cdb390928a4 -size 50876 +oid sha256:fa3a5b26a6d98948f69598cab12346ecc54edf72d131cafda69f68854e7d2741 +size 50937 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_12_en.png index 161bc26f01..62b3892cd8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed0df44ce25f2a9f7e75d49c48a805f62bbf61f1f63ecee7f29e34f9bcae0e70 -size 61888 +oid sha256:42955e8bed36514ef57a3e53b579041d92c5f37edcd587431a8086fdf99dfca5 +size 61975 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_13_en.png index d74c89c6aa..d0bd1ecf26 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4eeddbe4e53cdf4453db6a7bd0257a52d46cfcac762da73319cf8735aedce481 -size 47422 +oid sha256:83ad6aad137696d06e00aa575d5cb35f96f0d90a61c1eab2a203958da2a73008 +size 47474 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_14_en.png index 6ddd6f5648..8a8920e572 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:143ae0c737a60e42370c10cdb39c577b91a151fa69079843e740b9edc7c5fc67 -size 63288 +oid sha256:513cb5cca0f8bea0af4c6272faa93c9cc6bb39470a90af807f1f8ca7edd1fd37 +size 63374 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_15_en.png index 1cff467cbe..ec6ef92b50 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4474b2c524768d2493b7ffd6c05b43f486c595c23f1ea641ba7704fad7181d0f -size 53792 +oid sha256:104638ce62de3f283f4bbc1ee3967816b88d84a6969cfc0cdd3a50f716ad8096 +size 53876 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_16_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_16_en.png index ba24c369e1..9f92d1622e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7e7905c6765db72a06c0dba835e34556377fb014476f0ebb2a68a6b93d05314 -size 64889 +oid sha256:ee37c77bae1dbf13fe3d22650828bcd4b636b9be847ae0bb23ecfed0ce037313 +size 64974 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_17_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_17_en.png index e5795401ce..6a1ef10cfe 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06e2c25d3cbd111b22bd0188e2b1880729e023170c7bed972cdb3c34544ba55e -size 55547 +oid sha256:204bd19f811ab2da4068165b67e2260d0855332877140fd67631a6f9e89c0455 +size 55640 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_1_en.png index 6c57315d3a..0fb34507a8 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1ebb6edcfa045967fd9d9a2b554b1e2bc1ef0e20680661c0af2d8530348ab72 -size 69388 +oid sha256:3ac772343aad8977a8618d69a50d97ff4d9818eb5869c3fc03e58e43f4b4abc1 +size 69473 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_2_en.png index c418921834..461d9f4310 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3bf788838a204acb53bceba268327e3c2a772447490a597ed4929487716bc6fb -size 486425 +oid sha256:2fb3a106c42c8176321be45a2334b185c59ad7c12e3fa099b4c9ef0b4fc98c3f +size 486526 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_3_en.png index 6ab414ab0b..ba28533f36 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80e198bd8cf523c785de4a66c4c22cecb22d1040377bdfd66eeed821a4281592 -size 481590 +oid sha256:17a7b359ec376b3fcd4bf4bd60d26a9b0ea5f6319d1da291006c1bf36d3f1b39 +size 481665 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_4_en.png index 41d2ac5ad9..08368478be 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1bfcf8909d3414e517357d82c203c5464071b3f673d7623d4f75b6c18f25e22e -size 65742 +oid sha256:e49aa7b7b5245cc48851ceb9d43e2cfbf4df07e427baf071f81717e0ce454c62 +size 64186 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_5_en.png index ecf72ec264..6190a8ede0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d3d27b7a366ac20b287f7587866dba06dc5667ba8cd3b6dc040d8ee7e3adb94 -size 80499 +oid sha256:434369f889778088c1612a304a4d7a50de90048eeb0506cd13345567cf0dd0b1 +size 79196 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_6_en.png index 17f8b1974c..1ab4e96ddb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cdf2031afb6d849812555f8b38f6b0f1f65aa959f3cc9e468fdeece65c150858 -size 69980 +oid sha256:91ab3270af1a376d76ea3457b9e083036ba009a95794fcbddcde62f5a6dbf2b1 +size 68637 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_7_en.png index 780f2f9094..02d19f3878 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0034ff36f0d58e30ac75b36f0869dc27f617d9f1dfb1cf00b88c9bf32d23986 -size 98632 +oid sha256:9ea0d765a77d9682e376021a2c1c65b9a6bf00dbe69a0762b8c0abf9d0634880 +size 97456 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_8_en.png index 67777f33f7..e7d088463b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24c430f5d40a0215e5c11348d40d2b9a50cf5bbc6639e5ebdb408004b0f3024c -size 54499 +oid sha256:d02a19a7067b5ab4a6eddfdc50179e0457ff4e40f99746cd384bf5ef528f019b +size 54581 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_9_en.png index 825618ae17..016a480809 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline_TimelineView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75ace43e27a0c8f9786b0494931c3ef5e12d903e7417dddecfb34c9526e74f3c -size 149314 +oid sha256:e6211f8de0d2ac250ea4318532c52bc5ba13e5f964a75424df0fc1c584f66f2a +size 216195 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png index 68e8a2127e..3ea918900d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc098d35a0af82ec65dee8ccadf6df83246fbbc7933239fd940de938a4dd4476 -size 55995 +oid sha256:e088da462be419f059caa750afe0ce5d806ce25e682cb5aaaf37f88e5c236ee3 +size 55745 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png index 13207941ab..695f6809c7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_MessagesViewTopBar_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb5305c7ccf69c49fde95cd3601bf2ee103988775b366cb2ee3fcd04e8673729 -size 55131 +oid sha256:f5658c53966bfab8a24a1e123d10a1b3c98b7d43361469ba8d6519c2d2f1cc22 +size 55067 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png index d4bf4bc165..92a01e3e98 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:397966acb792f1a20a79cb865dbf38687244baa9dfa3bc6ceea74919446ca3e5 -size 32476 +oid sha256:8ff566d11223b1a330174a0200848442b510aa378603a79ec5017144f5b8979a +size 32743 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png index 58e0a3469c..744713a8c0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.topbars_ThreadTopBar_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:434edcb217dd174b57435f1ff2f86cef8ae025ed7a058da229e1335fc0e00801 -size 31748 +oid sha256:1b866f67d78b4add03de052d0eb993e596bd8afd6a77f4cf27ff7dc7c17d8c51 +size 32263 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png index 631559cabc..b2b3f0b813 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee269e52306e048bbd0a06ea7c56f9080f37f37b00909c3d48a02a3a37bd57bc -size 131800 +oid sha256:02c4892eaa7d27c867266c428374b64e5915ec50ddcdf8b1d532e1cbc6f56462 +size 130436 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png index 9c5932834e..7a5e5e1512 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dd30568e628750f922a87c2df1fd7751e9d899b9163253c9f2a0c7b03e4a869 -size 56247 +oid sha256:0e3467a7606a5a7beaafb510faf008ed567b1e3a9915ede6e2ec09c491af0bb9 +size 56552 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png index 157e74f7f0..843adcdff0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc02a7c7b38753d9509b3cb0fb2eb0e29b6d6c79b8471ba4dc7dd5b81b13d15b -size 50892 +oid sha256:446ae29cbb211665f6d91129a7dee0f718b407fcb2a64d3f2c0e962e1cb47af7 +size 50168 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png index a63b53d2c1..ee23a7111d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7fdd2e68114457368c5d19fe117b2d5a86a02ca475925c9fae0269ff92f5144 -size 66312 +oid sha256:38ae233a128e887efc48da73be3d6ce50a7095601315ed49a3c9cb209ffdda26 +size 58352 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png index ef8699b324..9685e6cbc9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f21b1799dec6cb466378a748adb5227f76bd6cf611be694922ef63a951fdf692 -size 39910 +oid sha256:d1a28720d554bc4698eb52e27e7c6228ac9c14b3703a8c139c3113f8b8fa284e +size 40355 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png index f00e72d033..7ce91f4684 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d1a8746f4dc362d7d1caa424b18c09c3d2e14753e8d6599267d472a61e197df -size 59137 +oid sha256:7b749e1260d6ba2b7fef5ae9efd58612f6d67d1788f6c1e5cebc22d58d0fd7b7 +size 58563 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png index c19f70ee0a..f6456f0ec1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc8b338c1a56b1b663171e16815b3c8122dab3ec948f3db4b9e790833b3f89a6 -size 55378 +oid sha256:22153168f6f3e84ab789faea29c94fffbc1a5e4c1b9a98deccb0460192fdde23 +size 57213 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png index 3cd7dd274c..6a3ffb84b6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2a89e79995050e8b24b459172a7c123cc08c64097d5d735cef8c47f913a3bf4 -size 54080 +oid sha256:48b91e52306daa750b4b5792535e1f1865ae3b74a36215376a51dafdd0dcd506 +size 54837 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png index ae8c29241d..abf8eb7086 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:616deb9421b09e2fa25d6953263fd70a9f687fdfbdf9503bbc35e7a0660ec440 -size 58459 +oid sha256:1e79e1cc59ba62ca8eb99300eb520b05d7ac6d52c077e3010c03b474865b15f4 +size 58374 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png index 4c3689dedd..5d4f5bdaeb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b14de263a1f2356b3e84b2a633b0ed837bd160d04c1ec8eeb8c55176856e59ce -size 48755 +oid sha256:08fb14008b08d86755c3473e7194ef0a39bb73c3f0d48122ca80c6a019ec98eb +size 48676 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png index 767be1a188..b3af9d831a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:970396f75edf55841822286155e73e5f4981c347c7c2ff34e69ff9e4bf0aac9f -size 59343 +oid sha256:ce795c4e32a1be3d57f6b1c87588d8c7ed0442996ab9d8a96f1ec5a07627e598 +size 59663 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png index e4a14ae551..2c88d322d4 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:39430896a687266d7a60890fdac5dbca6d36c87fe30d07619c9c50e23c3f77be -size 56972 +oid sha256:963fcec9647d0e5e57bd3fbe3edd389c17be7558c1da7e93fa44f34db34307ee +size 57726 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png index b8d8a2cf4c..281aad62a7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cb21bd5e7d348d1d07ca4b6a360f26a4735cc9760fdd7e3b4b1bcde32da6f08 -size 62655 +oid sha256:85f6f4c64f67faa99b9af65307a0cd3b46a68db52503c9c929375408597995d9 +size 62094 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png index b3c490ad32..cfa6e4dbc3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30e13e1b91d681088ceba71f21f668a5d8b8f376cb10832f0289b1b14c1103e4 -size 55569 +oid sha256:7a3281f35461edb900ea434c68543dc684a5fad7dab7c9aabac510bc59d442b3 +size 56479 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png index 74826e1e9e..5f3a619097 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:805245ffe7f4e99a0f5927b89bcaa6ab8eaf7cc603d352b14b8109e76eecbdf2 -size 51742 +oid sha256:19d14e3d779b163053c28e66d3381f0cabe3b540744606e955cd733f9e044089 +size 51713 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png index d2b5044048..6e8468054f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52441a5e250b027ddd40ee32754a63c6206762084f47ecfa7e057e2ac77e78a8 -size 69120 +oid sha256:262e8d4b8daa2d25593834fd0ab5d7019b0a3dd13707aa96e0701bf9240c6525 +size 59809 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png index 51a300b462..d7eb027558 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84a6b1ef879f1a9be16526efdd546aa554e03ea74b0e8ec03178b2a860b752e5 -size 38089 +oid sha256:5789d10db607ad77acd5d9391b970b2e0a0f962c205b3bf40db5c78d0dcea48b +size 38821 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png index eb13905340..f4ab74029b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f988610da5b4feaa47eb9e5224f9b0d2d47633d9aa8fd45117fff75f5040680 -size 58673 +oid sha256:51a5b682243b969bc2d7d609decb823b0509d240f3ff14ee78319260af76a47f +size 58740 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png index 250279e2f8..3974618f39 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f9e76f5d50ce3e0fa259f0692184564a8a988c2e0ba047595c34a99c04fb8e2 -size 50510 +oid sha256:718d5c9f24c114f3bf88e000b637ea19598d7bb9b97001ba137fc12a6a1285e4 +size 52608 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png index 6b4cb7360c..0ad1e67deb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:abf3863e6d5ddc747dfea06a006983345937cd85d0e89b60bc625f4ad16b2691 -size 52906 +oid sha256:82e6e38576a507b19e58fce9dda0734ec00bcedcb0baf8f4c7919dbaaf7d2b85 +size 55046 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png index 4f903b55b7..a009d0f584 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2e99ae9731e9c75fd025db8f24649d6219941ff3aaf0bd4a67bc2c8d1f204cb3 -size 53516 +oid sha256:478851e9e2e8c80095aa552b98a5d574749200ff49899c9472c913b07459c4b5 +size 53758 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png index ffae0459fc..f82a7a8219 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:539799354ad5b383c308779b1278e879db4542d9d1c870c13a54a0ae927767fb -size 44098 +oid sha256:22ea7fe121a63b35a2c2bb47609e692f8bf2b913871a6baf3d420c04334c6c4a +size 44344 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png index 5e28ba8938..7261c9b671 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5c6ac53f33fb4338a11358a487c2042304691ecf50f61ca0e7cbb75bc227efc -size 58294 +oid sha256:7cf3d727da78b39ecf24d4df7db0884af9008db67cc92274849c1b0978f87726 +size 59252 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png index 1ad21c4d64..cfa62a6626 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:289819914863942caad5202131efddd9b880b4af64a36d4b45fb547b5b1ec47f -size 55916 +oid sha256:bfe848e4c365cf4b4d663145f74e5f8b3f47a4c8994961c530603f0248400316 +size 57117 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png index 6e371532de..89065e6bf0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:86273e812cbc6245527c3d1f138111ece99375aec0d68728882b656b01687bff -size 64392 +oid sha256:a966c9a1fa4fdd933f4ef9239592e90458a2819ff4a45c857714d2e38c0df5b2 +size 64405 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png index 175a0f2bd1..cf8d2098fc 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c864988e49824c3618904cf42363c1fe538800b1f84aad2c66ac654f62f434a6 -size 21829 +oid sha256:d9ca948d2f322152fb3d744352c516da3969464c58d200a9a86ca4e94a421782 +size 21779 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png index 214d636e46..46eebf12ea 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedNotSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:452d8bb3e6e0310e4c73144aad5a576786dc48e4070aaf63bb0c3e9da0159595 -size 21040 +oid sha256:c3659fdb2296ba5209f1dfb9715f5aa15b53e40950ae2ee874668382d48721bf +size 20998 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png index ab26a4d6e3..30bab8d633 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5fdf37958fbaa5eb87b1ac06664e28d3aad4dcf49b2f778216caf469e00a6208 -size 21558 +oid sha256:c840fd342d8e0d20b467459ce55dd6efe5e8af7be63b5f04381f8b207bf0ea20 +size 21506 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png index 7f82d27887..dc32bb8c39 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewDisclosedSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:449174be2973e6ead2b3ead2e0e17602c81d1e033d4748ca73c9d23fb85f786e -size 20691 +oid sha256:cc466128c5ddf240505abbacbca4b64c4b5386c1f11c4b2490d7489173aaeade +size 20652 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png index c9f8004adf..a6c63537ca 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b905fa0c4db60d00f0b6ace10475938e7475f9a42485a196106ad775b0dce94 -size 21637 +oid sha256:b1280c50f1cef592973121e772c05767b3ad7dd73a69fdef767be3ff7ec0ca32 +size 21581 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png index ae6a95dc6a..51329440f8 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75e459f015375792833cba105472ef353246726cbfe9558897b439a8f113d51f -size 20793 +oid sha256:3a04a75d043d911aeb5378ee65ae711edd6d02366ea0965e3a6db4cad30b1327 +size 20747 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png index 8830de49c7..c0026065b8 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12c33a0e0e3c2adc8c84d2abc6c454481ec5525bfe4335edb76f29b8e0c47530 -size 21886 +oid sha256:1e7d403a1598ffb8f4741e8c1d22ef5ecad8a00d341804a13408bbba15f20102 +size 21852 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png index ea0c67b60e..0ae568111b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerNotSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f0195e6a8ac94d80fc8fedabec7890c1759a9c8f0869c04f4091d04d6d458f0 -size 20909 +oid sha256:7cde74ada77b24ba095076aa7bb64a3c2f176a5d918366e047869fe8a014ec06 +size 20889 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png index 30fac7b3f4..c12ce989e4 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:feb7baa6462360a9867bf933ecd58e8a93903319d8c481f08d5f5eff68327809 -size 21767 +oid sha256:224efbc64460928f67f36aafc136ed39c08af1821681f174575b439cf3f838fc +size 21732 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png index c04d74a07a..ab4515dc83 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewEndedWinnerSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:794736fcffb4b5b5738ec8572b7e05aa74fe02571a187d85a3cec8ded3385944 -size 20804 +oid sha256:327382d2c29eae52cabfd23c8cbaf918b476bbb4599b34c895ae2d8cedc97ae8 +size 20779 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png index f44e0b112b..c8d2b45932 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ed073c0daa096dd650b271bc5956937147b03ed368c3ebe2bd6bef65a8ceb55 -size 19940 +oid sha256:8b006278f82e5532708959622bf2ea02a36a0958fd88fb17cf01e578ce6d041c +size 19886 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png index 74018e58c7..53cae5715b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedNotSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e5ed9ed51f96eaf89818c5bc8eda71ad922b302b66167e325e75167fbf7830c -size 19250 +oid sha256:a24f72385732af0d963bd4d4ba43f4b19e4cf884622ce492adc8773724698564 +size 19203 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png index ac3c021439..1db5159272 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf3dd646cdb9edbb57f67004b27293be4c207468c951d21dcd38736d472c4572 -size 19671 +oid sha256:7871b48398cf6fb5b7879bd7fc6abdbc77610175bc1f65694263882074825b26 +size 19607 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png index ffaa88b0c1..51821ae3bb 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollAnswerViewUndisclosedSelected_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6fba79bbabd808008241427a7fb9b679e14cf421aba27cf07f858a22e8cde986 -size 18907 +oid sha256:3a454b9e5738339b8f41b777097a3a97cfdfddfde82abfe2f684baab7637fcb9 +size 18863 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png index d0bf4cbe70..08887dc916 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:535f0ebc9954c43d6bbf5aef6b0a7e3f601f6b144ced1ab8849026fcd9b1d24e -size 49054 +oid sha256:06bcc1250d5bd298072c9433f9bce37cd732fb978c3ff8cdcf5a19533a2af75a +size 49012 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png index 3ed6965647..16468c9693 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEditable_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d7d8b78fa215494248859996d72763077d915be680ed07068195d9cf46aaab9 -size 47785 +oid sha256:029032fb1ab1f7b4a6f18d91093fbdb2c1c84b8ed60c1f66827028e538f2a04a +size 47729 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png index 63a0f51e47..337e63ea5b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e6432c3aa20c0d2ee9e070e3b2c076aaaae281af0bf222d26f762a91b5051ac -size 47262 +oid sha256:b56a9d1d8e97f181c5e28644592246163aef7e8d340bb9bd40c710638f3fe15f +size 47199 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png index 2f538779d2..4aa852f6c6 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreatorEnded_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cc90d8a47ebb2be4d2191735dc8b672e350f65f514feba064442ee26712a7e2 -size 45634 +oid sha256:af665a28986ef9134cd09636deee127b26118fbb53d2a17aeac61b99949c8b49 +size 45575 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png index a73ab70bbe..7072bbc0fa 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:737a2a37bd4b753981d719e70c366688a92ebfca62e53a1e60ae81a073c40f14 -size 48858 +oid sha256:b3e60938f89fe4e56acec088683232dcce2b13deaf55111ef3e049857dfe2585 +size 48824 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png index 1f3b56bcd9..1909c9455b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewCreator_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffda5057a816628a946e6441a90c47a469233a61d3c8da11d39797b8f44adfff -size 47649 +oid sha256:2aef02a3fbb01e4dc03179914298aa169800e2f866d678ea8fa53a492e5e451d +size 47577 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png index 804455160e..276c82c9ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ebc7039d4c3db7d0a7cf36b7cb317576b9eebac16bd29fc542193ddc78a3467 -size 46843 +oid sha256:35741e180e6c07b452c485099c11473e80ac308ae81d3620fcd8e3bd1385f977 +size 46801 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png index cdf797ba54..85edbd5662 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewDisclosed_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:effa17c9dc842c49c1b67be244f0c8c53e859fe80dab54a373d7536ce3898e7e -size 45498 +oid sha256:9b64a00c01448b8935985343ae33912c80dd84ea2329717b8addfc07dd6ef012 +size 45403 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png index 63a0f51e47..337e63ea5b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e6432c3aa20c0d2ee9e070e3b2c076aaaae281af0bf222d26f762a91b5051ac -size 47262 +oid sha256:b56a9d1d8e97f181c5e28644592246163aef7e8d340bb9bd40c710638f3fe15f +size 47199 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png index 2f538779d2..4aa852f6c6 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewEnded_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cc90d8a47ebb2be4d2191735dc8b672e350f65f514feba064442ee26712a7e2 -size 45634 +oid sha256:af665a28986ef9134cd09636deee127b26118fbb53d2a17aeac61b99949c8b49 +size 45575 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png index 0fd343dd00..66c2cba60c 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4153f27072a59e50417c450d9c6c9a48022f58aebd4790ae4b7721fafeb06789 -size 44788 +oid sha256:79194c49b72f05396e3ecc9faf9041edaa2fd98bb0a154cb1baeaf3a95701d0d +size 44715 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png index bce5d3b342..f59f7fb149 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.api.pollcontent_PollContentViewUndisclosed_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55a9bdd99147171bacf97a0aa1e9e4ef04cf09ff07d6785c3fed7b09c24acdbf -size 43271 +oid sha256:bb8b80c458e9d6581e0a33651dcfa29ae0a0ab610913fa686a5719e4b887f7df +size 43196 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_0_en.png index c3fcb2f17b..77f3d11e97 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:038ef6a808291c6c03fc9842333717a72d918b41dcefc30c3aa7e0e5690d6055 -size 31824 +oid sha256:72d279876d8b58aadf1e8aca76f272b5a785f93fe3e36bea98d7aabb9334bca4 +size 31867 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_1_en.png index e445e1c782..f9c2514881 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb823650a3a78f45953cb968a30cc673ee0e5bfee8b646212b652f2b6f3ae48d -size 36228 +oid sha256:d49dec2d63677550189700908d870d8b3ade414dfd19ce553fbdb2847e604351 +size 36199 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_2_en.png index c08d1bdb2c..54934bcf31 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:280db5d8836456fe0a1e0e080a1274dab4a42b735608a28198e3a40f59ef15c9 -size 37918 +oid sha256:f77908c9549e885df89311d21f67cb851739cb62b88151855b3ce544d91341ac +size 37990 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_3_en.png index bb091e461e..20409b5c94 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6a1b401b0420d859936e6bfb65ecc42b8d3eaa600fddef9be911c756d78fbfc -size 43897 +oid sha256:0ab5170975b38b931f1ae28e842e1005535027a2d5ccaa3eea98ed92e7557322 +size 43922 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_6_en.png index 4dabd8c886..f98c4227fe 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ec17842ff19c481f860026ff97dfe46f0fb48b9ff85c2f95a03ddde8fec0b24 -size 32486 +oid sha256:855a852546c6a2f33c079b585016ec71dd375b5b74782d0572388e47ef6f3d8a +size 32507 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_7_en.png index ecbae20f54..135ab09593 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:007187362281fc7abc71f94ee8996f966d55a710f61988adb09ac73f988e3922 -size 33734 +oid sha256:c3d58d95320f94c75586d575f94344fa118298eaf157d9c2b795f823ea582457 +size 33830 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_0_en.png index fddc69fad2..2e466a7c4b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2dd7f6bb021bce1532ef665c518fb12f45223e8fca3f90bf30d05c2d6d03d709 -size 30830 +oid sha256:8d0de0ff521be78f2117831acf64bf0036c130b4caead8017419425a9b627dd3 +size 30911 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_1_en.png index 882d4fedb0..bf5a258bad 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01f7425cd0207c270e5b4d538b89d6258d71a8b60dc40da3438233bbe6fa1f75 -size 35092 +oid sha256:1091ef4ff6a828ce7b493c9f824012cfa23bf7729d6db8b2298cbe65aa561b84 +size 35016 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_2_en.png index eadb4475c1..8f9b15e40a 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ae04292e7b83d8347c0f15e3c37cfa5803568474f03d8fff87c67fff272346a -size 35835 +oid sha256:9d86c455cfa28e948b91f2fab42333efb8ee631de9a96dab3f8d18a6b2952f59 +size 35876 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_3_en.png index 1fce182221..23ccf42ae5 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:472d4808b40eb045946656cc6a32470e90afb3208ea6233ae4d0c99b464be520 -size 42596 +oid sha256:d2414a68d170ad6f2267a9d3a760571059c7623c00947c02a05c6904b3536af3 +size 42601 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_6_en.png index a386a003ce..dd4ec6624d 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d5684d574033abdd23b7831dd8c8006e012f392b2c3dfb786519362f26a194a5 -size 31460 +oid sha256:9d2ba5293880bc3c40d7a3b346424cc5f514cf970213e626e1c6edd4e23575ab +size 31464 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_7_en.png index 9c0a1b0bcd..c13f5e0f2b 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.create_CreatePollView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6acd80c3b53ad3b077fa0075a3702e9778430ec51966ed3c50039acadbf97a4d -size 31465 +oid sha256:5290184e660f4d1e4f22a11e27a32ca1fb67f2c3dcea1a530ad70c767d716f43 +size 31560 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png index a3c90658fb..65585d6b92 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:505d223578e9311861dbf7a20e1becb36148b9180a687feea7232ec717792f86 -size 56650 +oid sha256:b47d1d3babb5c9b59e975ececb12829df9f2e576ef1487daba8905360260bf6e +size 56521 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png index 8c8397bf39..b92844eb05 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ef271dffed2d6e32bc61d4c48d16e339f1acaea5862ee25c602c06f1b9bc956 -size 60668 +oid sha256:5faffc0ee9d5b5f3780c4eba1464d83108e65bc175e4659770ef0266d0883285 +size 60548 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png index af1499cc0b..281ef07c0e 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:184281a9d2f2a14431d4e6b50a9e876a75b75a202c8e7f598d0f60ad5218008d -size 54967 +oid sha256:1e9e1fe808bb06c2864a9ec68879ec7940cc049761e23947d3691f339deac6fa +size 54874 diff --git a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png index a34af749c5..5aa99c7164 100644 --- a/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.poll.impl.history_PollHistoryView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74ab54160b7f732840b0ddf950a6efb0708d9227a72b0c03e798c83f828cbd0e -size 58794 +oid sha256:5daf469c7f8615c9b3167246027e6f2e366f4bb9a984d5603559fd00467274f1 +size 58706 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_en.png index 08966f9b39..b86c69a702 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42fd1d9b089b026a9edf1a0ecb71da47a4517062cc19f61e16e70f9b3276ab30 -size 59658 +oid sha256:fb6e775ab09eb127cd56db6831f8bb125d3ce8b2403bd986487e9ee2c628fe03 +size 59750 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_en.png index 25f2f73063..efb0ba0a05 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:314ffd2ccda8d0315a27e0cf08fa6d158ddf38fa0903e1e8d7fe45361254aa0d -size 59525 +oid sha256:2cde83c54e65dac37f42d162758d0bb075eecfdaae5508b7790eb2aacc36f4a2 +size 59615 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_en.png index c9b289e9d9..6d10e6b029 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc25ef0688d2aa9be1fcade1dfa282b243cc3c45bde01d3571b2ad9278dcda74 -size 59509 +oid sha256:56e19e11105421fee374e36f824761ddff1e160f3c6f505d7c66241a81430612 +size 59600 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_en.png index 3398dc3826..2b3acbef75 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:229b570a3c938e75f5d7b33c7fec89be9582ec06aa85dfa587b995219b145e88 -size 59517 +oid sha256:27d1cff6cdb23657a1d65855589efbd4a1640370f081c2a492f28fcb624f8bf9 +size 59611 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_en.png index 6767c03276..87e3f5d778 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c9caa916637c212f2cf1e5d175a9cf096b83606e1161b7c2bb1c8ddcb142e48 -size 59363 +oid sha256:c383308325ff9b683a9b001ace0601c04e3ae71b2bbbf3e07aae1917e7bf6e15 +size 59498 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_en.png index e9434a4041..f4c1154539 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:296c4b7449992b4aaa478038db9b6dd4e687ca05f82cc351db258e3f178adb6f -size 59656 +oid sha256:7b634c94a7c36c771c7c7cf7b42f05151aa03479448e2c10ae22bf7e058eb28c +size 59746 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_en.png index dcbfd047c6..738db2b489 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f13aab730039d52c1d92e5ed3ad601095cf7c8b3bd76ddf2303f2006ea6f6092 -size 59193 +oid sha256:4e27c596d0e2462b5a469d27bcfe9073c09cfe51a91cf280599919ef25b74395 +size 59292 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_en.png index 3526e1e6d7..5092ac3e94 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:961959403b1763abd537e05865d86475161e650e61e51e65202522d08faad55b -size 58771 +oid sha256:596e9308895c9a8fec14ed26af4ef348f8c3f5772eb7f296b437579c59dabda6 +size 58804 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_en.png index c1707ebef8..aa72afe58b 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewBlack_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2e5df1191bf18d6c922ca3d2a22584c98c4b871254512ea86cfb324fddf8a2d0 -size 62520 +oid sha256:644204d979bb19ec5a002ae246814098af05e8750316d52910f649ff62eb8b6f +size 62866 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en.png index 880c259789..473f98a32f 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad35559b964b2d1197b256348e175a8082bffc9247024a546eea86655c9c0d8e -size 56855 +oid sha256:a80835ea11094a66e09528413ef411853ad8218f06051cbd77d5b32de32e8e10 +size 56895 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en.png index c3e7180e3b..58f2639ace 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94b94eca0502a081fbb862c426b5063275ac948c8d998e34f40e362a82591d75 -size 56707 +oid sha256:cf87b258d11b13e98e77b145da51afa40d56248682ea2ef23fca320e190feafd +size 56746 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en.png index bb6e078571..62134288dd 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46bd8afffd3a9c4cfb92c7d9ea2c2d0a3c4942115a80809d6bbc16037e2839a1 -size 56705 +oid sha256:2f5cb1d3f9effd4099e1a27efef8e3bd40e911e6e935355944090f5ad62bdfc1 +size 56745 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en.png index c0ea01e3b0..c83202730e 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5fc17122d1466b14e85a49165bd3b462756181ec26cbce280437f015734c8e40 -size 56716 +oid sha256:7f862f27162968dae996e23baeec3291645b125ef25f853d9b9a363d24aca738 +size 56756 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en.png index efc3e893a9..77452af18b 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12cb6a8ee6846a0f44d5e14599fd7c6dbf97da97d35c6b6c83545d601a246efe -size 56563 +oid sha256:98a269501ae382129654d04852123377be4e6c0ee1b665c989dcef3a1d44a44b +size 56623 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en.png index 7ee27433d6..c0806414b6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1546f59a5be6b5f8883729c4b83005ebeb990188a86c100ba384da46b2a1da7e -size 56853 +oid sha256:e2342cf3ccf4c59f1bd17d4276c5fd7f29b41cc1a17105272cc1913287e435fa +size 56902 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en.png index aae9546e31..c79abdd7c6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:714782c0f439f933f6e0127ccf54b6e09138fa23d44a3596017a23665131c119 -size 56498 +oid sha256:3b14f3c517b570a0724f6ec14ecf3c0ba8881fcdaf643d6ce9070f0871e03fc7 +size 56464 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en.png index efadf6c0dc..dd8afdfe37 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a58efd0afbc84c88d8635738d3bb25826c4d25d790d4eaa1aba0e9efafc3b56 -size 56043 +oid sha256:46aca63876af82eb27f9b7f050716429ae323ed626793968f620dc2464009db6 +size 56146 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en.png index 1547c5289c..e851a8517a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewDark_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d502f4f9ccf2d3eff614d9ed2b751a252acd05c1bf5cf4a8b11775c45725c3d -size 59427 +oid sha256:0e73e9eab3864c65badd7660306cfe96e0b45d4963c7cc1e961d330da074b24b +size 59700 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en.png index 1cea623bff..edb79ba518 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c80e9985aec6b183e33f12ecb884753d1b8f67927d6d5713ea946ea8f5d6dd6 -size 59300 +oid sha256:30a586c9cefe4f7d9b342b792d65314657e3ca7f56a785d7779d855fcbe8a428 +size 59233 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en.png index d32d440b79..c747c2e1a4 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dedcf20e368909de0a6cdeade437bff06b38a1f1b6aba3355968983f1387018 -size 59201 +oid sha256:3c15192a3094d3b86613c37b8a40391cb6ade53937c172a27d63d2dd644bfba0 +size 59134 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en.png index 6f672c23b7..440b244d12 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9023d044daba4573bb9a3ed4da598bfb5c27081e4f7a75757a4796bdc44573a -size 59207 +oid sha256:dc6cbdf0c90d70ff85ed3f5133eb1f938602c583639139b9055d43f4b52d6c86 +size 59142 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en.png index 54bd893d1f..868f9d3682 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77eb9f159dbfa30e6f750500c2adf21b18cb5f1dfb7a574be68683db24803225 -size 59174 +oid sha256:b9a5f7b9ecffd994a28a21fabb07f089f4bcda19db05ee23250e8b88966752f4 +size 59103 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en.png index e945e52dfa..0de67666fd 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dca50c7a0f0d7ce96388a01456871decc76285384d2573161773219c79fb876 -size 59060 +oid sha256:2ef7a874894de12c6d6e39fbac20064fc35bc3b56ad17c42e2bf06412f2f90e1 +size 59062 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en.png index 02c571c605..38057861c0 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe4181c3e521f1f788dd06e3cfb1ca078655852415dfd4f26f5480dd47bf084c -size 59303 +oid sha256:e216b29be5c59b8b32173a478e90f9e9b965b4eb7703882d2b8b4499eef4d1b1 +size 59231 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en.png index 7da66a622f..0c76f03f80 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:18602ce14232fd438450782a564354c38ebffb0c56d0c3887d88c47cae53dacf -size 58962 +oid sha256:d9130cd7bdf755cbb244cb77cdbb741d4fd97edd18a4d2b342a4d37b9155dcb1 +size 58859 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en.png index 015ecaf7fd..9e39d93bf2 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3ae0af5031f7f850c40fa6560aa6d70127e006931a3e18cbee04acd7c7aed57 -size 58526 +oid sha256:d96caac765e3945e6a57c0aa136ee31c581406f90f397afbae2b79d0449873ed +size 58548 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en.png index 19d1ae2ca8..a4f99faf45 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.advanced_AdvancedSettingsViewLight_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a980564b6406bbe45b9a170a5744e45c9e019556587d433e5fdffd8ab6f1c6fd -size 62034 +oid sha256:d3d41fd6c09dde0db3e37d2a28442b2f7eddfe46bdc0d119773e37a55c46d0d5 +size 62224 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png index 074820e157..7cca911c45 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7caacb336793b8ae4b83e9a10a82325e25e8b3c036f881898ed28688250eb6e0 -size 55744 +oid sha256:26e14b77fa3c3aeaea58782309e6de8b9047e07945009322990ebf5f4c283309 +size 52770 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png index 2af459c158..7cca911c45 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28a95d4b7ebca92c4e0467f3ecd9acdaf7f6257604d190f5d088a9a25e87d637 -size 55305 +oid sha256:26e14b77fa3c3aeaea58782309e6de8b9047e07945009322990ebf5f4c283309 +size 52770 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png index 36d19c6b72..616c06bf46 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7dfa2767c55a81d3f121b8fa55443b7b05f9369e91639b80e0be349863799ad7 -size 55438 +oid sha256:0ce2519906f1aaf34700ca9ba4bdeaa72030f1f5aff3f7e24352a1435ac67d98 +size 53966 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_en.png index 708313c475..9e5e42f653 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62068492969ad00e1a8e4a44189f93d83c98fee40612e4eecb68d3076d00ed07 -size 56425 +oid sha256:a955265e37fe0a06065f70b0b9648c8cb85b5e6721336deb7735721dc3c0db80 +size 56623 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Night_0_en.png index b69265cf41..3155968037 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsPage_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d92e220d675097c37b60312ca4c4e821eb6ff6475bcd004437dde0d2e964cce -size 54756 +oid sha256:ddb64ac02738159cd0897e7fdf62d8138ce1590afeb05ed7492a41fb361b7dbe +size 54681 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_en.png index b56ed34048..a33ca80765 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf121c0ea1fb3cc7a47a292877535c9c0a1ae1ac11bf7f5ce169d0cd79844246 -size 53775 +oid sha256:d7de600ae1a687929c01ff52255571daa496fbd1c7df8a94e56ebf00f0ef8392 +size 53595 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_en.png index d0a5500209..a45f19a0cb 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:37ae25b9f9c659164c006c9bdb9f94379398ee8215e8a2dd9167620ef994b6d1 -size 52347 +oid sha256:d9c0458f9bf81c02fb10d8d9faf88f3c0813813fc5bad7d3ceedc7cdfe3028e3 +size 52103 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_0_en.png index d2929c43be..81a02b4ea8 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db439869d2b8843cd58251bbca638e0dad7ed2b1ae4b22507e052e3d5521214d -size 52090 +oid sha256:2ba238914f025ca392c7f90d6800f57adef47d48bab03bbf4d711cc2f6036c32 +size 52222 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_1_en.png index 540b910b54..0b7f81266a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer.appsettings_AppDeveloperSettingsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cae56bb14ae7bc1f6c73884c2efb333b7da22c82d69026854a59c380657a5bbe -size 50705 +oid sha256:ea5d9314cb0466aa16c7d7d28056ccf13a60a493a88104be2686384e66722b4a +size 50727 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png index 503b9ad61c..48914fa409 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d18a2e9ba19401f958483bf06ecd7b311ed7383de0df3d89f3bb4d3a57f8e9e7 -size 54191 +oid sha256:59b02b82b889878dc908a859bf32c1486fd926034b89a258028835aebe9ca873 +size 53872 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png index 16be314a0d..dbafdad6eb 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aafbc1f791f067fd0084db3bf293511e3cf7557329e7599c3f3e3c66f01435c4 -size 45472 +oid sha256:a6c6e4d5ff9f34adbf6dc303e107336d675c874ebfc99a903c44b37693c521ac +size 45444 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png index 503b9ad61c..48914fa409 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d18a2e9ba19401f958483bf06ecd7b311ed7383de0df3d89f3bb4d3a57f8e9e7 -size 54191 +oid sha256:59b02b82b889878dc908a859bf32c1486fd926034b89a258028835aebe9ca873 +size 53872 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png index 430756b5b3..ef953a39d2 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcca87aa6eee7e45bedb8f58c3b776e3932d94843573eea70aa686c3de82e03f -size 52290 +oid sha256:51947f9062518b5ab89b9bdc20889b5560146b182a4549f3a2b6f7a5d9ca2ee5 +size 52298 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png index 4225562f66..2ad5c53567 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25e311c9bd46defd9659004d2d36088985c0578189a41906b51bfe683ddb6488 -size 43889 +oid sha256:762fbce69b40b9b8c1209415a88fe95f0480ef87e1dd2c1748bd7ac3b4cc1d76 +size 43835 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png index 430756b5b3..ef953a39d2 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.developer_DeveloperSettingsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcca87aa6eee7e45bedb8f58c3b776e3932d94843573eea70aa686c3de82e03f -size 52290 +oid sha256:51947f9062518b5ab89b9bdc20889b5560146b182a4549f3a2b6f7a5d9ca2ee5 +size 52298 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en.png index 7bf37a76f8..cbda488267 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a5171c9f08d2249562d83d9967deb84cbb59bfe9613df27097ab342890405ad6 -size 42377 +oid sha256:731d4139bd4b0f2876e5df8a481b34e4ed4678f518b81c1e101aca07fab6e54a +size 42155 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en.png index 2ba28bb753..63eeb0da9c 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7b61c67d3fe6366874f7a0048c6e82c66f607fef586fcf0b43b48b1724fc602 -size 42230 +oid sha256:8581ef2719ba34504891e9a5ef46b7cd06d3daca5894b8d664eb067d55a76355 +size 42004 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en.png index f49c317324..4fd802402b 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9654dec6e7d312d9e1d0189e928ec01de8aa86c7d9b8c8a3ebc5ebadfd3588ef -size 35493 +oid sha256:1a3402b8a8458654e8c1c1a7efa81af45f8038b85bea027bcd9b2476812ef385 +size 35520 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en.png index 80c7478e20..9dfb896c03 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae1fc7261b3ea8adf68f2c9a7e88e91a77a816713ac5ec20dd65a32670d2d3d4 -size 37859 +oid sha256:76b6c58712a347586493d9857aa5de12da23bb2603f925f72a2b59f4a3ba7196 +size 37916 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en.png index 89a6d30f0b..6f434d15ee 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27c60b1d1923b1546215255cf9dfb78091802b40abf7f831375a5e0a9d24cd25 -size 55685 +oid sha256:ae04c1ccea9073ab548d08995c427b904318bc3aefebd278622d71b2ff89f8ad +size 55578 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en.png index 90e3292e27..ac43ffb23c 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:156307f3934d6bf4fbc90b36bd6e1e7e516e1401b7253624af93de9801e4fc41 -size 41920 +oid sha256:08baa541e27b1c029e18bdb843c1915997f7234e496c2c8c7583d8a888044f05 +size 41768 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en.png index a595bbe51f..00ca9c12de 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b84aa300ecbcbc9fba740dd3dfbb90fffbc6fa463e40d009ddd5ae394b50c5ea -size 41793 +oid sha256:426db78c889d357ed94977990d2d4ab8194bb48ec4d0466cd54baa8ed1676809 +size 41654 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en.png index 2aa655fde2..b5076580c8 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac2d31aaac66c11e62d45074253efd95190804b5294d7837781912d61cf98a64 -size 34715 +oid sha256:5cfdfb972fcd32e87c8357567875aef7f26597e09a5aabe80173b4ee758cf92a +size 34760 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en.png index 89459812cf..6cc3a12c88 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05896ad1d86b38825fe1793cf83db364404d998585fa60b456061be2093d848e -size 35660 +oid sha256:35e801a6bbfdf73c93a3887e8097685144b33ed7bad142901e878e474ac0f437 +size 35692 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en.png index 9957d2032c..fbf89da91f 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:adc28c6db29c01547a811d825b1c24b1db94a900631e74925edba372760aebd1 -size 54705 +oid sha256:8674e93ab6223d1bde21df6688482df5adc16a345339d593c363018b126cbc26 +size 54706 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_0_en.png index 7b985075fa..08ae236377 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2dd82d156d36a7c7141fd5a4eafdbcbfe9aacc7a8dcede267fdfde272519bee6 -size 52088 +oid sha256:c0aacf68449e737c3c357e974cb8756c65e60db7578885ff9ce4bb726d31bc00 +size 52008 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_12_en.png index 41290c5db8..22d0e1eef7 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74890836fd7256b068ac02e78c83b20a3b1d22fe9e5d1bf6a939f7d6f03abe78 -size 58686 +oid sha256:e41f07dc61af91ef995d2b04cdaf9d78e733189d03b04a4992184e8e1134364d +size 58640 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_14_en.png index 29adf28369..ee21ee384a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72acb2485a98126e53c27459d63fe7d3718ebc94215a597207ff820d4c9e45a7 -size 43439 +oid sha256:47ec77ef02122184cab59688e5ba3f9aadf8875fff73175402c3da499f591ba1 +size 43317 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_15_en.png index b79295b20d..8fcb545029 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a8b4f5fe2d2aa5459aac05180882b3aaa9fc9777f84f4c817c9e995049485946 -size 42052 +oid sha256:4c9e7fc37451a08d7f0e8b1ad2d0dcd75f428114fc8985dc430dbe4b1c913309 +size 41879 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_16_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_16_en.png index f85174c9c8..41a60a992a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba8f5f9d0ce23de5e6d57660887478b04851680d13a9f8f70d1488c557a25afc -size 43261 +oid sha256:c14ee768960796a0d31d6f7de0590a3cde41918eff0aa7e9158392a4a4fce703 +size 43173 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_17_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_17_en.png index e4c7c476f5..a421925d73 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dc8f7d0497632c723311c530d37807261686ed9fe4d7ff926c0a0fbf825cf23 -size 43179 +oid sha256:44f18c872ab94dba349b9b58d285aefa3e32e79676f37f63ed9c50fe1de68e49 +size 43046 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_18_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_18_en.png index e34ca68b36..4408ec767f 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_18_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_18_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2cc1821e0f114837943f9b9ff76f43a1bf871cc49a4eff704e8c87b50cc384ba -size 44736 +oid sha256:bb8f82d825a0e97703793b37c8c9525271aebd9cf33d3a6de1422e8515f7f97b +size 44930 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_19_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_19_en.png index e9127c1ccd..5b4ddf6763 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_19_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_19_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cbf8bd63967dc3e0739ea2cc62c42fbcbe7d0a9cdf50b41f24c1ccab1f300eab -size 39442 +oid sha256:14b9e7f22078be909317cdb8b2823919a9d0f6a179f2964fc855252b4237ab09 +size 39607 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_1_en.png index e4c7c476f5..a421925d73 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dc8f7d0497632c723311c530d37807261686ed9fe4d7ff926c0a0fbf825cf23 -size 43179 +oid sha256:44f18c872ab94dba349b9b58d285aefa3e32e79676f37f63ed9c50fe1de68e49 +size 43046 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_20_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_20_en.png index 4c2b80b959..0f7dbeb57c 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_20_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_20_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0c31e3d7a0788e91287da4ed4f0b6e5e1ade8ce542392f4ba6029d524372c32 -size 41551 +oid sha256:c048e3b635b98cbd4ce8f04278f568888413d4a7e2414662f57ea6ef662c2a22 +size 41665 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_2_en.png index a35714aff4..bbf9e79392 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:176519a45ab97560dc2f8bf1416915759039616458f5fde22def7022595b4cc9 -size 39890 +oid sha256:d1803afde307769d808a1c4f9f764da822ee5a774d3c159524b66852942157c6 +size 39980 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_3_en.png index ce4c8a5f2a..71d8627267 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7efafe0931f350b3369a73fc4cb4156f641d894db5e939202ab9fec5cec8423b -size 39229 +oid sha256:f53a28516bfb1898bdde08ea2c8a408b0e4533e0df293ca526460366eac2ed30 +size 39271 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_4_en.png index ce4c8a5f2a..71d8627267 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7efafe0931f350b3369a73fc4cb4156f641d894db5e939202ab9fec5cec8423b -size 39229 +oid sha256:f53a28516bfb1898bdde08ea2c8a408b0e4533e0df293ca526460366eac2ed30 +size 39271 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_5_en.png index e4c7c476f5..a421925d73 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dc8f7d0497632c723311c530d37807261686ed9fe4d7ff926c0a0fbf825cf23 -size 43179 +oid sha256:44f18c872ab94dba349b9b58d285aefa3e32e79676f37f63ed9c50fe1de68e49 +size 43046 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png index 6ce1addb3a..ff8c8bfeeb 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73cf2629ea291b423460d8756814e97b2e8720a064aaf7fc9f3f3a7cf9a34862 -size 39186 +oid sha256:964005811374c5747c378220205979cb646df301755176d270bd3f8f6a3e5b91 +size 39341 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png index e368d72b51..0f9cd69b16 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efb91f3ae38c55d585d86d1c83f8c52e7244b62b64c82f51ad145ac3ec9841a7 -size 43493 +oid sha256:d0a6d0e6c1e54a1842178576a2f63b29277a116c3d63e1e83c58ee2a2061c43b +size 43680 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_8_en.png index e4c7c476f5..a421925d73 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dc8f7d0497632c723311c530d37807261686ed9fe4d7ff926c0a0fbf825cf23 -size 43179 +oid sha256:44f18c872ab94dba349b9b58d285aefa3e32e79676f37f63ed9c50fe1de68e49 +size 43046 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_9_en.png index e4c7c476f5..a421925d73 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dc8f7d0497632c723311c530d37807261686ed9fe4d7ff926c0a0fbf825cf23 -size 43179 +oid sha256:44f18c872ab94dba349b9b58d285aefa3e32e79676f37f63ed9c50fe1de68e49 +size 43046 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_0_en.png index 1859be12da..e9066fcbff 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d921332fe1eb11a80750ed8934f3d386fa267e180bbd29960a750181bddcb49 -size 50570 +oid sha256:7019689badf7430a8a3a12eeaafb575de4b08fc2872a383d694085b4ae41f6cf +size 50545 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_12_en.png index 6beab389f6..f8026d34c5 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:684d9d7475db5d003772337aabe0834ecc95079105d0820f387654a7db1f5a37 -size 56947 +oid sha256:57d7d8d9e6f0867662121cdde52e32ef7be19760bcf534c2f4586e0d57cba03c +size 56878 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_14_en.png index f300562d3c..2e127ed838 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a189eca358d0bf0c2ed4f107252b667d996e560822ea8e39cf776511ebb0fde4 -size 41989 +oid sha256:d93a5e5632ffff786845b69b532994642d04c2d306ede1d8f246ac157a73682e +size 41882 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_15_en.png index 28dad18993..71d599d5d9 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:019e7a646c19f2056873f186e8c7ee73127e79468e5149034e85455460b689be -size 40637 +oid sha256:89456057ead8933e7ebf3c2f4210da1fb92a1c9d4fee10ceb832cc0d3fe3797e +size 40524 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_16_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_16_en.png index 16bbe20275..f22aa4e4b2 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5a9585f68e045397a46c8f368e4affa1e9fde985bf415014403b91e73de6eb9e -size 41713 +oid sha256:44ca73c0eb048a81f77d2dd70f785261024419ef77fa0a809ee101019db82c62 +size 41695 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_17_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_17_en.png index d6ac948791..56981dc8a6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca8ace95c2cb039826be9e39da427eebada1a8f6f234d6ae82c9e2a69f9a2c8e -size 41760 +oid sha256:a4adf5e05b575aff79e8e0ae1bc039e147b014190cea303abc3dd9e1df6f33cb +size 41684 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_18_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_18_en.png index 0e5833c48b..88e2cb485b 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_18_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_18_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43d661bd16a8343e1750faeed957fe5490cee65d0bcc033ecef6344c7ee85fba -size 42104 +oid sha256:ead1fb3338330fb5f6f3178b2f71ed4d1fa45790938db9045b3cc8ebad85cd88 +size 42167 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_19_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_19_en.png index f169d5f9d8..a5dd69f5fb 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_19_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_19_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cacac247776f92bf1aeaed8b0b11a2283d27e51c6999f4fcd08b62b8aae4c3d7 -size 36997 +oid sha256:5e0dc3c944415c2739e330e7cc0c284c1ccd1b4b4801c7b300aba0af0a144c3b +size 37068 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_1_en.png index d6ac948791..56981dc8a6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca8ace95c2cb039826be9e39da427eebada1a8f6f234d6ae82c9e2a69f9a2c8e -size 41760 +oid sha256:a4adf5e05b575aff79e8e0ae1bc039e147b014190cea303abc3dd9e1df6f33cb +size 41684 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_20_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_20_en.png index 03061e5717..6fe937e597 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_20_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_20_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6685d37388f89b1a6f18a66deb1a7a35f23a88c2bd64e3d4b980f71cd9cc5aa -size 39185 +oid sha256:1bcaf45ed5dec3e86d4b17e5a53fbadd455df81a4b30924a6309e472ddaf2636 +size 39206 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_2_en.png index d1678d364f..242258f056 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:50d4e41bfed974afdcdb1864f95e9b5ea26675f67c16cd17d82c431547be4b5b -size 38565 +oid sha256:afd1e21c834ecd9c3d0405749ea458672d2ac785c9f4d615ba2d780879d11a42 +size 38489 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_3_en.png index a6c678cb89..e87402fc99 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c31c52efbf995bcc237a309772be0c70221db7d30dec38c734bf01f75bb1a97 -size 36856 +oid sha256:fa9d8b31efc5b2c369d501bd002f66edccb84e812fa10d5b3284ab13357f7404 +size 36831 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_4_en.png index a6c678cb89..e87402fc99 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c31c52efbf995bcc237a309772be0c70221db7d30dec38c734bf01f75bb1a97 -size 36856 +oid sha256:fa9d8b31efc5b2c369d501bd002f66edccb84e812fa10d5b3284ab13357f7404 +size 36831 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_5_en.png index d6ac948791..56981dc8a6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca8ace95c2cb039826be9e39da427eebada1a8f6f234d6ae82c9e2a69f9a2c8e -size 41760 +oid sha256:a4adf5e05b575aff79e8e0ae1bc039e147b014190cea303abc3dd9e1df6f33cb +size 41684 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png index aa887109d2..fc16482e71 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:64b969354abd79e131dc6bf644f48e2218216fd4a6b8e93527f52defc8b2cb38 -size 36836 +oid sha256:3efe00ff653c1c6efdc85ef3ab244d8078f6f36cf6cde2620c4b4f5776b019f9 +size 36861 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png index 4e38e5b2bf..fd9b76fd36 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b07d98cdb41d4daf9bec18285588ad5bf99992a52ef27f2da66545734b8db843 -size 41036 +oid sha256:67539cba9fe0e53fd902a878c76b0927cc0afad2a9541781e2ed4a81eba652a7 +size 41089 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_8_en.png index d6ac948791..56981dc8a6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca8ace95c2cb039826be9e39da427eebada1a8f6f234d6ae82c9e2a69f9a2c8e -size 41760 +oid sha256:a4adf5e05b575aff79e8e0ae1bc039e147b014190cea303abc3dd9e1df6f33cb +size 41684 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_9_en.png index d6ac948791..56981dc8a6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.notifications_NotificationSettingsView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca8ace95c2cb039826be9e39da427eebada1a8f6f234d6ae82c9e2a69f9a2c8e -size 41760 +oid sha256:a4adf5e05b575aff79e8e0ae1bc039e147b014190cea303abc3dd9e1df6f33cb +size 41684 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png index 9d8eec80cb..6e46211c3e 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e83c8d052ce340010f97c4ef2750e4b921a129639a0004bd951f71c7348622bf -size 40597 +oid sha256:cff89dace11868ae57ad7c701303ab19096be52bbc21f7b43f91097fe8a612f1 +size 40300 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png index b04da30f28..053b0cf1f6 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a6ddec2c9743976674657e454cb14bb479d774f1aa13882a34ceb89ff75b179 -size 24424 +oid sha256:92420711d5445edf625ff3125ecabbfbd4317dda6d7e29b4484a3b38d8d3193d +size 24297 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_2_en.png index 18869e3590..2c9cc8de20 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95e30b24d5a6571cf42a707a01f0458cf509428c9ab8333924e1679f6d4d4f31 -size 35778 +oid sha256:f36ead42cf5f79023ca960698b25864e44a098b71d4de8a4fbff6e2cb0a86b99 +size 35546 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_3_en.png index 2786b0cb8d..2d0012240f 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e54c2c665235d6b4c45161b4fcc0b8f0a96ce7620bbed9f56e04ecb71916f3e -size 26640 +oid sha256:83085cec3cd4e3a8eb9c8b112d54d9aa1eaa6ca3206b5f526b6e0edc7392ce92 +size 26743 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_4_en.png index ff630d5aab..a89b3d05f5 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2fd721612e0620c3a4eac0f0835ac1d03ffb36ec45477340bb732ff1c63cc30 -size 26921 +oid sha256:6a9739c8908859f2401d118e32f4354a2132d6d08173c4e5683eaa1b8dee8cc5 +size 26897 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_5_en.png index cb6c51d959..d5f5b7f6ca 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewDark_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c7fc020ec4bcb2f67a3a534a621e71233488b469b24e6bd6d3efa42f9f944a1 -size 20263 +oid sha256:c0d9335e3b6900a366d4770849736b7bc866bb205c9b6f004a3521d6a058916b +size 20020 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png index 5fe3875d72..d527233adc 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a07bd9ac57c1fb6074b81134edcd169c2c7edc3dd19039766dabbfe8ccd5d8fb -size 41621 +oid sha256:a911c0f75b2146fffb24d3bddac02ae096eac871285ef15c4d1477629a5b2d49 +size 41390 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png index a2d4d1b036..77170a40ca 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa1a7c175f6551680b1a71ddaac14014f6503ccc2928d4ad97eced8a80626ed4 -size 25158 +oid sha256:dee0eff6123dca9f9b3ba544d2db16b1e2ab982d20a5d8a0013b0e08e37afddd +size 25094 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_2_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_2_en.png index c188be2848..7be86a8757 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67bc6eac2128230323aa7dabb6896b98c4249e6fba9edb4d1769f36dbe031135 -size 36346 +oid sha256:6fef2b0dd09457de0079e3c00ea6e07a81bfb7d0f500d228d38c9054b446708f +size 36271 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_3_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_3_en.png index f2ca7b4a6c..046163551a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a40fe5dc4a671ec2384265da36f3d42a3cadb2792823308a62dbd82423110652 -size 27552 +oid sha256:9a8ef73ae13ff39f1612dde7582225a18656015c2608fa45510bef3d8a52a705 +size 27701 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_4_en.png index 8ce81e889d..1c8583ea33 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:007aeb20270db25edcd3cf2e1ac8e4e0d714e08a043af0473c2263c1e79af452 -size 27634 +oid sha256:691bdc37a68ad14bf1ac08ff242861412915c597017b7980850fb2a82070c228 +size 27646 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_5_en.png index c402bf81c9..5c6556e3b3 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.root_PreferencesRootViewLight_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d644bc2a62596b923d782150334f60b1940730824af0b7a304d2fdfce85cd0e6 -size 20493 +oid sha256:41c88c94e910f524567d7054d7914eeddccff2b0249e331582ea1ab130d40d6a +size 20454 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en.png index f59f8b6da0..a5c4e992dc 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d521236e5470339e854f490bbf4fc8e7ba355e3cc27e32145320df217be31d1 -size 18387 +oid sha256:015c7855f265ea896320f5bd3319e05a1fd09708644ed4980150e8cf4c6eec1e +size 18365 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en.png index ce1568c007..f44041159d 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:322d3e0d5d7ca5aec1814e8e78eda2abf99ee178aeaeb9c4b9341ac35c92eb38 -size 14766 +oid sha256:1c2993725d56690edb632d5a5a8776cafbaddf98e213ec5e912c9ab7637c74bf +size 14810 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en.png index bd06c2643e..2f9d7380a3 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a1588effb798e95e7b312eaeac298317851afaec7ff16a79c27ea0778ccbbac -size 17005 +oid sha256:79cf0d6e42b99ee91917aafb3d28ccb81e45042954370b239703fc3084eb5897 +size 17074 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en.png index 197a3c53f5..cc47b174cc 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.api.preferences_RageshakePreferencesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:606ad1faa861583d9e03a05f4aa9fd315389118700c062c7fd694492d2aafc95 -size 13902 +oid sha256:ffd643d1356b6317480b9852974df74a8675107aeaa7c28fbbe62920a2e0a2b6 +size 14034 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_0_en.png index 0599f2300a..d600a67219 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b243025f40d5d4a91e32d59a6cac9ec21a273aaddbfac020cb26b3dc86c906 -size 53339 +oid sha256:112ad29fea211c36dcb15a0674f1684869318858260799ee52913514f4e3b1be +size 52976 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_1_en.png index 9e2407229c..29fc43b66c 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e98722e0c21fe6b509b2bdf4a9ce7f78a1c83b606411329d2fd97a676fc4bed3 -size 113728 +oid sha256:0bcdd2cc0e47a7303cbcdcf34e069c556287ad30454bc36b068360d9820b88c0 +size 112924 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_2_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_2_en.png index bfd0f366be..cf7c538197 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44eed3e8a093977f51d706acbec65cf29d592dcf0af3cdc9fce85d2b8e570eb9 -size 51038 +oid sha256:6b4572b681595f3893188f9f78e7966d52508d4119451fd7ac86f7bb4f5cef0e +size 50635 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_3_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_3_en.png index 0599f2300a..d600a67219 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4b243025f40d5d4a91e32d59a6cac9ec21a273aaddbfac020cb26b3dc86c906 -size 53339 +oid sha256:112ad29fea211c36dcb15a0674f1684869318858260799ee52913514f4e3b1be +size 52976 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_4_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_4_en.png index 1a5d877a24..f581ee930b 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:781287977ff2637fe6479c3653270783c4374bc10fffb91da8b45d4e4f588a98 -size 41744 +oid sha256:e935f2b1f46b5330ea034b6824628f8dab7417f9d185fd720297ac8a5c1ce838 +size 41507 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_0_en.png index 3fea4591cd..a1b520209d 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f690c34f97eec23f01bfdc3c2606a229bb12abb91fe86fb79c89da79b08480a0 -size 52049 +oid sha256:a6388912c7e4797b63799f2c938a02dc1680de65cbb28ab57fc1961248ccb61d +size 51398 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_1_en.png index 957e19a4ce..cf2783581a 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:751b442e5aecd9d3938817f8a1af11b7cc1d250c1166c9e8bd3154a85268471d -size 111765 +oid sha256:ea54b01d2e6b607db3dacfba356ed3e3e3bf4c00ff91b3b65c748c478e776e66 +size 110685 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_2_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_2_en.png index 390d0faf7e..b141191872 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0719e803112640729fe2b59c40373343db3e9f2e8dded9258d4b6c44547f8fd1 -size 49420 +oid sha256:c20206fd5603cf207dc8d504f43b350ecefae39710dced25f0fcca1f34f05c68 +size 48912 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_3_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_3_en.png index 3fea4591cd..a1b520209d 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f690c34f97eec23f01bfdc3c2606a229bb12abb91fe86fb79c89da79b08480a0 -size 52049 +oid sha256:a6388912c7e4797b63799f2c938a02dc1680de65cbb28ab57fc1961248ccb61d +size 51398 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_4_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_4_en.png index 4fd1ecbc0e..69d1edb4be 100644 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cb10ddf4a9dee4a001276554cf32cf874062e1e5d7d0ebb673f6417641530bf -size 39730 +oid sha256:1857e44c3a2e5a0ae49bb4bde22a86eec2e420b71e7f0aeb497b85c92c5d1ab2 +size 39675 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en.png index 90974411fc..548f4fb92a 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42115371f725ac37b484d22a7ddc0c48c5a4246360779e75256cdf2e45c4badf -size 49163 +oid sha256:d181933f188d7e5800899e6f97fababd50c3000a27aca63a2a11a5edcac8ad19 +size 49083 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en.png index 4d1dbf68f7..0150967253 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:555849e00ac48ed8b4dbaf2dd19b990d281e6db2a4787f584f5a07a02ed85ee7 -size 47831 +oid sha256:f5238d0915551c987e2e01de6268fdc4085df411103fc0a69fbc6511201e2d12 +size 47789 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en.png index 05be6036e3..ff7e8ea70b 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9b741585aec49860eadc2eb294d23f9bc275872176c45a3d0a465d3c6c85b6f -size 49081 +oid sha256:4e112e30bd75e1768a436475a63b290ac8bdad3842ce8589aa65a7a12569ec7f +size 49003 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en.png index 4887d37e61..66eb55c0d0 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5914d8b0f98943fd8f059853623b5f9cfec889e28699d6025feddb29c67e8b3b -size 44219 +oid sha256:9c01b62bf6bb7bd47b09660e311fee7db5fea13e09539b071ff87c29c8f0f8d8 +size 44288 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en.png index 71fafafd14..4f46f9607e 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ef05fd67b842ca7134da5a21306ff70768fc4a13676effeadf9cc86cb1ce04d -size 43230 +oid sha256:19e197ad8ea83cd381f33df27444a59cae5788b31454fe34b0c93005f6f1d41d +size 43436 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en.png index 2ebe8074ab..29964f66aa 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d49ac650aeab172c3b5fdf7939ee459773e1135f7873abbc14502f5b33d3f8c8 -size 49989 +oid sha256:a10264258982ef82c3c5692b5aebcd56d25c87b96901f497c7c0ac4ce8c2c6c8 +size 50208 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en.png index 27cf718290..df3882744a 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c4660b161de0a2daa06bcf7d931d97c1f29e8f2958b6b309df002adc180b45a -size 48598 +oid sha256:dcbe7fd975d477c3d37722cd6b95941e30ab524804b1e8a013d65fbaf0031537 +size 48571 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en.png index af4ca3b0b7..134ad1fcf2 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e351c0a3968472284aaf175fa3c36f23903727bf74621d26fc59c6979bb5314 -size 47950 +oid sha256:2d4d206671385a19afabe3ed60c4f34438c44fbfb0f950d3bbc91adad86aab66 +size 47849 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en.png index 949acd5fc5..1c04ecef27 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98f9d2867796a2031b374d1cc05f4a8218bab0a2e44ab8eee5c6feb4eafdfe2e -size 46638 +oid sha256:71ee36dc169d4f39e9015d8430aefba6785c625a5e5677a47ce71e7ed36c170e +size 46480 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en.png index d516119920..c09d6e14af 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:50f74a2ef7c200d901155cc6936ace84193ebb0c801aa7ab938ccaaabe5ad8ac -size 47855 +oid sha256:f94fc5c78b20b45bea71a91d0f9ad5ee3008e0e9dd4fe7adb72d6304940bb2bc +size 47755 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en.png index 2593ef8ee3..f149763a22 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eda97e80b8302323f57d07409ea2a83ef3ba8aade3b4e329bf0bbe8176c65c10 -size 42844 +oid sha256:3019ccb270aef63a7b33fdbf18b78801ea7e55baf8d303349591d15a55d89c54 +size 42933 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en.png index e4296df2f3..e344afc5e3 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95a0b7d54697b6e7ee3bfaf97413991876938563008bbdf89dffe337f815afa2 -size 41202 +oid sha256:ff75cc80b45beea841511c179a1d75a4b859a3d1ea392bdbafd5d7db2dfa7865 +size 41282 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en.png index fe283b6453..63ce660ab4 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2af2d6cbd32fe906d66773c0015383bfe28035d09e43939d3ee71ba516bb1e67 -size 47790 +oid sha256:16d0a0ce6760b8ffe6d346e5ec8e962f1dd1eab6589f05762c3d0b591b7eb3f8 +size 47868 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en.png index 6dc2c3413e..6708a06368 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.permissions_ChangeRoomPermissionsView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28a659ae5432a6b452476fb486486d5fb1e9bf28640f80b291a4193870106309 -size 47298 +oid sha256:1da041b4a7856026c22181a963f310e1208e6ac0337b44d639b2e35a3c0f659a +size 47271 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en.png index 031e824d00..1d74d53ef9 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6b5330dd8afdb53538bccaad58a688798be1a97c2855f1766e8b5c50499f406c -size 49560 +oid sha256:468f68d04c5a4f18f2458714117c69a5d464f997f8102592017fdc670ee9c304 +size 49547 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en.png index 5405b2f535..253838d70c 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8199ec44477a9e8fcbc3507e609ca1bddcdd422e2d52429038e6289ea25066c7 -size 52137 +oid sha256:e8fb8640cc168b3337bf17f893179daf86eea29e0e9124e113ce98426a1a9ef9 +size 52090 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en.png index 596aae0702..bdbba9f408 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:826b6ed7c407abee85fff8795ca41f3cdd78936e050787b62c4da3bac91911f3 -size 53762 +oid sha256:32ccdc2e065691bd4e557eb794ee98a313011f19a5a920099612521515b65a30 +size 53712 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png index ec0926fe98..716872f929 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cf9484430efe87465c5aaedd53d866c7479982c77dea9ff5f5c33b659557e30 -size 58423 +oid sha256:f4acc8042fe23f5a352b5d928aee2393b4952f1cb2a00b807b35a8c0fc98c827 +size 58592 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en.png index 028a49cc90..2f262ba181 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9e6ac535c10c1cfb042419bd1f5af51b8d4a51b234ace59b6f2bece599c4451 -size 66724 +oid sha256:3e7d05b3314fe5478e451283b848e1bc0f1d9d5f420363606b38c6c06c381dc4 +size 66074 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en.png index 03e7a81404..6d8014b510 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7418b3c08ffdcb58a7eee06eb86f9feafb0f02a0ff567d90833babef5f50a5c9 -size 60596 +oid sha256:de175424df113b1b0688509a23dd514679272c6641b64850ffd7072f2bdf458b +size 60443 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en.png index de2a58e79a..b916b4e68b 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fabf3e373947091f9b061cb1252769f9954a7394a39f98ce3c29665d46d7de9e -size 60554 +oid sha256:521b6f5002e3dde3ec57b0ad89a9c2415966cca80997962de95333c9f7585420 +size 60404 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en.png index 0f5dccae40..95aa10ca1f 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a4c600313b32c36153a90098f5da273d664aeaf6fc4de4b6be07b1e84a1f5b6 -size 54461 +oid sha256:e6cd97d0475b6dc1950d67be57a8cc9867d07c6428db828fd9a541118c8b3143 +size 54283 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_5_en.png index 83f543fcc5..61dc44978f 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80c77888856e76935dee1e7512991287321a856c72f722298ec83fe54b9832ea -size 12367 +oid sha256:d261286b2d36c8e58290bef31d647214aad10dbac334b8151d8670239bf4e8f6 +size 12377 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en.png index 3994e5b8c9..1658700b51 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba14e3f3a756cc227fb6ad1fbe4ffea174cdd6e56ec982cba86b6025d65c7b16 -size 56354 +oid sha256:e553ac2b5b35f694a35f56948196f6f10612904d758b749c5878ca4ee2e1ec07 +size 56360 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en.png index 2bfbe443b6..af2737442f 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae2cd1fee72a1bd76862fe522fcc4afd942f763c677f37ec38198bb1223b593e -size 60836 +oid sha256:a1cdfbb66bef6d51807cbcbb75e8277bc9475d41f8ce95c5ad8440fa17265131 +size 60727 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en.png index 9ab5346177..f8b4c759b1 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28f0e05f1c37cfd0b47b231c213b9101f0cf4deddcdb0a3f600c105630b8100a -size 52017 +oid sha256:06ab908e6115f3962b9fdd86df644af55ef731898da958e1041d6113ac46e4f3 +size 51947 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en.png index de2a58e79a..b916b4e68b 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fabf3e373947091f9b061cb1252769f9954a7394a39f98ce3c29665d46d7de9e -size 60554 +oid sha256:521b6f5002e3dde3ec57b0ad89a9c2415966cca80997962de95333c9f7585420 +size 60404 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en.png index d8a24019cb..9ddacf0d4a 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:293daf287f9af7820b9117cc959eede1690df093d9e9e1b2008036b78c60ad13 -size 48712 +oid sha256:76cef9dd905c59735aee59b860360c12de6d0ff663cc0f40bb9a9f9b1fa19159 +size 48716 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en.png index 6f4516aabf..020731c6fa 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97fcdf04d36ac5610abdc12ef2bdecc3c4ecbf122c7a829603a7ab1fa6d6fe93 -size 52821 +oid sha256:ceaeffcb2bd4239d61e3c4f51d15d60a43626938a949dd5004a57ae35891f426 +size 52649 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en.png index 4e61663da4..97a84d0ce3 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0ff06a7d946dac97fcfbfa9a8ed9273915c3aee046e4dd5de5531d404d33ee2 -size 54457 +oid sha256:58768c1acb87ee8f74f077e84295d409713a54f6b91b37309c3fc189f913c513 +size 54298 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png index bcf0034ebf..07fe24d1fe 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3af0b02af1e4069d41d08256b252edc0bc6994bab9208144a46133f29ca0ac42 -size 56820 +oid sha256:e12b02d20a079766f858939c837878c6284ddc568d881585ca70321f6c4642f0 +size 56691 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en.png index 94bae794fd..44d6f46631 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d284095602bcd3fee4f63b2071de9b64d6a4694077167ca7915317574107cba -size 67211 +oid sha256:f1bd3c62483126552f1ac4ade2e19190ee9049c7aa05b3092fb0cc44d1d2c9db +size 66663 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en.png index 5b0252c2b1..da448e7437 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:881dadb37886ad8f1c2265466b38162941cbc0c4a5551f50ab7ac2f7db6b20d9 -size 61391 +oid sha256:b90f5e0c365d378fdbcccc0d8935b60a4b866ea2a7262ef5e5fe72316058e52d +size 61226 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en.png index 413b1cb404..3216eaa50f 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ca4d64ba665223ff81b990571d95e0ee4fac62d80452e713be7d3e0b7f36585 -size 61351 +oid sha256:4de200678e33f38d5787cf569f46b3c0f980705b827374cb3ee77d0f0636658a +size 61190 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en.png index ee55ce808c..6da554e6e1 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43feb55b7bd4078957549d4c998b9c5c83ae02ede6222e7fdff522bb40fbe0a1 -size 54900 +oid sha256:1fcbe996ab969856de2c37da875aedbd3550c9209f58bc4eaaba4ee5f9e6183b +size 54697 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_5_en.png index d3810d3da0..d808d93986 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:278da63de530e59035f6db74d46c81f1d26aa73649da0806adf2050cd67ab20a -size 12373 +oid sha256:2d7d643792fcae5b32dc2a14c738bb9f4a04c746adfc5d8abaa2aa1bae963a1e +size 12379 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en.png index 7cbaf82be0..7e9793abbc 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a41e7efce708581e0ab116737b59549b55f73cbacc8e1ff308332911d9042d8 -size 55462 +oid sha256:6ca4a8b7f73297d2130a0e7657b9abdfaeb47ce5e6c7da2c43105acf54be9952 +size 55449 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en.png index c855eae4e1..43a93b06ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed511d35b0a0bd4b5d1fa1720d87ef540f95eb1c07e7909d3bf8c990a1a537af -size 59290 +oid sha256:a116956e710f799768c2725247e4437d29876adfe92c584945bd1430e06aa7b7 +size 59210 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en.png index d5fb1cf198..451d85f21e 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3fe5d748130431c697e11374acc7dcff18fa7d6d8c8b5aac522bec3d9f25cc93 -size 52078 +oid sha256:9d724dcb19dbe6b55cd5a0f0c5e9ba30b0e505be7d8466d5cda96412a1bc6c29 +size 52004 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en.png index 413b1cb404..3216eaa50f 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ca4d64ba665223ff81b990571d95e0ee4fac62d80452e713be7d3e0b7f36585 -size 61351 +oid sha256:4de200678e33f38d5787cf569f46b3c0f980705b827374cb3ee77d0f0636658a +size 61190 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en.png index ca58eeeb17..21a5549d2b 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b479f0c88766634a4c0522d6260f31a1bf2e9fc07018cfc2a4818eed19faf3bf -size 28328 +oid sha256:fff83d7065e2e9f60cc9eea91b3ba4eea1adde637d1cf51c6df01517c96879fd +size 28348 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en.png index ed38da4f4b..e3e3f4daad 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d6796ceb09d9e063097266b12f5533ff425d6dc89b1fda2ede6e049f1fe8bde -size 30164 +oid sha256:bcbe510bde44898e1967ba2b8311622afd3cc599794b300a57b4b3b8632000ab +size 30188 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en.png index 7d384e609b..0edb2f7b9b 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab852889a65d07e3ddab54a50c7d989c7ed761fdb4dd855b7f10d452b7840ce9 -size 58187 +oid sha256:5b3ab3cab91ff916f2bf6db476efeb9f809a35a602f90d0cf50f283a6dc0451f +size 58189 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en.png index af2faee64c..6ed5992b27 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:230e766156de551fed6ec641e813a136c3bcbe1160828777623a2198eba194ab -size 27747 +oid sha256:f122ac9e7601af3b03825ded5eee90a942d4cb3415b479b0c603a7664c12acbe +size 27894 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en.png index f1032d7bac..28089c3a19 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea23ae24e9d7d7eba6cd75e009129a10e90311f2efddf0a4d5781b97d944184e -size 26718 +oid sha256:c48f20baf7ccead203a15ded178a46729d83f492414c907e67956f869c14452f +size 26772 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en.png index 59b0916092..6be69c6fdc 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b124e86fcfb1c1fd6aa04200065bd90966a32ac0eb66aff71c5cd9e362660939 -size 36693 +oid sha256:07ea854f28bfe2328d160739572ad8f2240823823780ba132be39786421ef45f +size 36742 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en.png index af2faee64c..6ed5992b27 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:230e766156de551fed6ec641e813a136c3bcbe1160828777623a2198eba194ab -size 27747 +oid sha256:f122ac9e7601af3b03825ded5eee90a942d4cb3415b479b0c603a7664c12acbe +size 27894 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en.png index 5c120513de..707c03e70e 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c73af7aa4ee7b60969a0bfdfe77494ad6c8456f3108450605242e41f0e50f90 -size 27053 +oid sha256:de6537fb8cab6f228c2b837c1833e63bde99cff5fa7d5660e99e0bd6c62d34ad +size 27105 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en.png index d14022b8d4..05e024ff89 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ec56279c2c0c390ffcf90798f121add48d1afd64e6cab96a5e0af6f61493d63 -size 26655 +oid sha256:5481e49a79c7f5bd2698ee44df7fc78aa2a7cb8567c9ab6f2c28f93f36ee60b7 +size 26620 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en.png index 0471e73a55..750272f011 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1ed853f9fa3a58d4f1fbc6f028264029b76b53fd5a7baec1dd46f694766457a -size 27456 +oid sha256:c2da90677e466c2856fe59aa0053598c163fe33bcb673672f58d4d9a502126de +size 27556 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en.png index 6d29fc04e6..8de25ea721 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6f34de05ed23c58362015cac39d28917b6735872c1d1521b43127a283078cff -size 29121 +oid sha256:e56bcdadd28809627bb3f5f0557b37be511a6369ccd0a9861e77cc2337a0a5dc +size 29237 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en.png index 895f52fb18..6420909c90 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bd29696b70564a9f78cd98f957c671faaa450ffbb9aaba37885d50c729028e7 -size 55526 +oid sha256:e1a4458211c4158f95837f3d3388a770e8e092ba43d6653b616a57f5030702e8 +size 55537 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en.png index 83bc1a6fd6..78090c5620 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:610649cb00a0818364c2dbd4ff70246886a82ab0d0b21d0dd8e82beb2da54981 -size 26677 +oid sha256:1c5548cc4e398f15a7ed1118b78520e793e358a67f1d218d003b03f1be13aff6 +size 26751 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en.png index defed0d920..48a711299c 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d91747927961186377681a43a5190ca6923409781adf833d61e547ed133ac75e -size 25179 +oid sha256:c23783e4367a8e732e3f3d528842670a4e110b26a9866fabd8598f382790c1cf +size 25211 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en.png index b4c18aeeb7..be1dba1967 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66016e7926dfd7db206c8695dc9bcc2ae0ee40700ad31f7c00f67d1ff425b761 -size 34479 +oid sha256:3dc931893c2233a6a83fe68bf8712ac0793916298978fbdd41c481cfa63eaa98 +size 34495 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en.png index 83bc1a6fd6..78090c5620 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:610649cb00a0818364c2dbd4ff70246886a82ab0d0b21d0dd8e82beb2da54981 -size 26677 +oid sha256:1c5548cc4e398f15a7ed1118b78520e793e358a67f1d218d003b03f1be13aff6 +size 26751 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en.png index c05bf83229..893fa03361 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28594fb95b9607e224279fb03d06961faa80618adafde5112283ae84a67daa7d -size 25556 +oid sha256:1fd326fc0c8e70625b792ee1d058c370401820ba082aebea938ebf092d200a14 +size 25584 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en.png index f2fda142a6..b64cee9c22 100644 --- a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.root_RolesAndPermissionsView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b5c5abd858c9b78a9f354e81977d9fe370dd511c242d75bd02385122101c766 -size 25826 +oid sha256:c2518b9917b3eaf7381a1dd12d6f3b3aba65ab678fedb369889e8f76d609782e +size 25750 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en.png index 24aa702c79..acf2d10b4a 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:acb77b2b218774a4f19537af5658205f2ef8150355282d1e1d85e68888712144 -size 31578 +oid sha256:419fa8d8d1e5290bdd2506824663c995cef09f52c9b4a9a52926b6cf94809b37 +size 31620 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en.png index 0274af2d42..366bf36bc6 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca592ac12d7cb8583962d8c0d5d99a57396ea807f830c4a727fae5ba077c3a1b -size 35709 +oid sha256:b5cbfb1852861ab4ba92355cf0c3e59919e2209338cf299cdae39791472674d3 +size 35398 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en.png index 21f4043acd..23935dc73d 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42e732b8e2c65c05096fad71211c8cee185c20d25386544d7245211f10922d40 -size 30159 +oid sha256:91f38a465b40119727d4a0995ee26170d35d128bf485dbff1d6aa263e5f17513 +size 30303 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en.png index b3082edc14..7c63030292 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8ce8c575c2b6e313e6623e72b772a6ee5fa175a4bf69a1f17ff8628cdfede4f -size 31489 +oid sha256:836ab57eebcd04857028dea821380b0d8b46964ef2775bbeed0e4ed1a6ee05fe +size 31547 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en.png index 21f4043acd..23935dc73d 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42e732b8e2c65c05096fad71211c8cee185c20d25386544d7245211f10922d40 -size 30159 +oid sha256:91f38a465b40119727d4a0995ee26170d35d128bf485dbff1d6aa263e5f17513 +size 30303 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en.png index b3082edc14..7c63030292 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8ce8c575c2b6e313e6623e72b772a6ee5fa175a4bf69a1f17ff8628cdfede4f -size 31489 +oid sha256:836ab57eebcd04857028dea821380b0d8b46964ef2775bbeed0e4ed1a6ee05fe +size 31547 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en.png index 24aa702c79..acf2d10b4a 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:acb77b2b218774a4f19537af5658205f2ef8150355282d1e1d85e68888712144 -size 31578 +oid sha256:419fa8d8d1e5290bdd2506824663c995cef09f52c9b4a9a52926b6cf94809b37 +size 31620 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en.png index 653b7031b3..64e9b67cd2 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dae1b0140dd927945df0e9abc143b15fce938747bb1d94759a9d6f198ebe20bf -size 30598 +oid sha256:c1639b16313e7c2e552fe741dc5af84c946bb9bef39fdbf98f3a5b473fa8de1f +size 30651 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en.png index 57bff77a51..7aa4fbc6c2 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56c928d1868ec3ff1f251d532b532397f688949e8cd6705ef363651c88221019 -size 34350 +oid sha256:12374c4bc5ad2290b98319d3301ba365d6d3d3d3c74e3705a621272179bd149f +size 34316 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en.png index d9b229a745..c44f3259d5 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1e1cb86dd8b566d3dc4dad42a30bb89de9fb6990d36572589ec5938e8411a6a -size 28940 +oid sha256:d935d8a9e4254d5f7220576f2c3a3272d2668829ab9f0cb0b7f6739a0b52658e +size 29037 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en.png index cb74a59e91..b2f184d679 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9eaa802a8e16d04b622f861c84b2454bcd5da52d27497972490a4eb7d9970153 -size 29554 +oid sha256:58d71e51474d4247b855e2155a287ba7785e25f2ef962bf11c0ad4967bff3f35 +size 29562 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en.png index d9b229a745..c44f3259d5 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1e1cb86dd8b566d3dc4dad42a30bb89de9fb6990d36572589ec5938e8411a6a -size 28940 +oid sha256:d935d8a9e4254d5f7220576f2c3a3272d2668829ab9f0cb0b7f6739a0b52658e +size 29037 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en.png index cb74a59e91..b2f184d679 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9eaa802a8e16d04b622f861c84b2454bcd5da52d27497972490a4eb7d9970153 -size 29554 +oid sha256:58d71e51474d4247b855e2155a287ba7785e25f2ef962bf11c0ad4967bff3f35 +size 29562 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en.png index 653b7031b3..64e9b67cd2 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.notificationsettings_RoomNotificationSettingsView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dae1b0140dd927945df0e9abc143b15fce938747bb1d94759a9d6f198ebe20bf -size 30598 +oid sha256:c1639b16313e7c2e552fe741dc5af84c946bb9bef39fdbf98f3a5b473fa8de1f +size 30651 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png index 25302db21d..232eff8a27 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7c187e173ae6d02d6c95c03bcc24cce91b0922e6aa5a08677732748aab0fc30 -size 85320 +oid sha256:dd57c6da7471850cbf9d4fd749b249589cd1dd71eebeac50fcef8a1db9efc04e +size 67420 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_0_en.png index 739ff5f268..77c11f54a2 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8979ec6209ad6e0deb6946e00ce227f3db41a565218afe31b72b889bee224daa -size 46268 +oid sha256:a78e7d4a345b9beca19dedd29282f9a891ceabdc05d203cb4091790924b0bbf3 +size 40335 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_10_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_10_en.png index 7609f5e725..5764767fef 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:16200632461dcbbf0f6211b7064b61a1e2fa04cd34e14946beb12b9e9f4d7b7f -size 43901 +oid sha256:29304b6e03fae0031e6fb536ffa038c436b224cf6c2fe095af1509d8cf1729ff +size 38520 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_11_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_11_en.png index ef1954720c..d242f48a87 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2279893a284e620cf487f6370982a14278fd57bb278e53932a5fd7c5cab8e95e -size 43033 +oid sha256:966f9a73b258b8b0036255d2519c64a306c07098001f9a140d5a3af9a7ed7734 +size 38088 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_12_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_12_en.png index a0cee002e6..d3baeac29c 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d4da60a94c56b13b65efb797825c54c1e107fe4440f56b1fcac5d47779cbf64 -size 44502 +oid sha256:44fbeb3efaad275d864b9cf58075fcc1df67c49f5498017e53a6c203ad5d0513 +size 38858 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_13_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_13_en.png index eb330780d8..a1e27998fa 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee2899f7870b09f287b45b327d5d0462b423ba65afa1087dec1be862507378de -size 44411 +oid sha256:82f34129e77fb9e84c513a950b7c3d2e20af376f357135cd7bfec67ec0850b62 +size 38790 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png index e09c2dfd95..fb02b6a6ed 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78ba2ddfdfc47febc0503daa0985a5fdf04ef15bdc391b4a88c3c630b1946b35 -size 46004 +oid sha256:cfa7cf1c8e98ecf02f00a20096e5edd5a720050dffd8a359335d479493b40f50 +size 40212 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png index cc49f40494..1da1c133bb 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4a832b0e395498b15e176529ea55c50ed129f6d2330fbec4ff1f8e3dcaeab93f -size 46543 +oid sha256:8f5be262e881a33b9ad1425164ff8424ca72e12a276918f173fd3ff5cffb9ed5 +size 40555 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_16_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_16_en.png index e8c0ec1046..645a7ac9f4 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8e738bd873339d195b4190f65a18016f2f0eb1bbc9f513a2b25467cb5f5828c -size 44745 +oid sha256:dd555ca1156752b9d07d808702c2e7bb04af00bf8240947e1cb4a7ffdc4814a4 +size 39066 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_17_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_17_en.png index 5098ecb3a2..99451027b5 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:892dd301ab08c6a302e8286d3f86878178130a22baf550402f2102ba98f0d21c -size 43982 +oid sha256:8630ba0169ecb20ed5076623fc9a6bfab6d30c75c8040958fcbe3663661f5cf1 +size 38502 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_18_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_18_en.png index 899ef403a4..9647ec0023 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_18_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_18_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:809c597757d6f1385803c1378a494f24309b533168df59c7e06852c1ce34b8d3 -size 41408 +oid sha256:57d4c23cf1f13899370c0bf0c99e23b0113039dd50a8fdbc1706df7691943044 +size 37354 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_19_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_19_en.png index 0625fcfe05..b786e48fd2 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_19_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_19_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3756793e5d92f0fac18e96a49e69ac7ed6901c1195d3e6526088027405e82dbf -size 41361 +oid sha256:9256ef115348a6fbcdc5bd275c7dd97c5018b890104c1074b65d0eef6d2ca319 +size 37334 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png index 346c9cf052..9114e9a598 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:099f571485ce8476d4b8a2313610b6c1d03a7d7420132e06d6258b483d640a08 -size 39130 +oid sha256:9c4a343ba9e0a8a6c75eb9cc54c4fbd460606de184c8078242a4e06eef7c3304 +size 34641 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_20_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_20_en.png index a58193c18f..449946c634 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_20_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_20_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66fd2cfb9f343c77b8db0a4fbc0d7a1571a4dfe1d70c78823a4ba03bfbc846eb -size 44934 +oid sha256:ef52fdbd2ed8efdf526efe2fab402d7100952522b7e01023ec73e10415e27700 +size 39183 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_21_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_21_en.png index 37bb88b0fb..b10f7d38d0 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_21_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_21_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:465ecd337f705262c8f533b3b01daa6a548c6ee88752be405609660ddfaf56b1 -size 44676 +oid sha256:0215a5c510ebd2b99176525f7f317654e3c3b2fda4f5599c63b589f5c6286efc +size 38951 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_22_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_22_en.png index 6356cec349..5fd4e0e5ca 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_22_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_22_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cca233c171b6c6709a94163ca1f0024a42ff66200383fdbcaf57b321251522e -size 44390 +oid sha256:bf37f6deee46b8949ab91e88c49811013876307009b9c84ffaefd8229034a26a +size 38837 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_2_en.png index 3846aec585..96f469822a 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e5e8b39197d115c6190b89fd54033b3319b36dfbf5c6f152dd84e6c79147bbb -size 37877 +oid sha256:569c1c17bae3b57d21f04d9ffec1ee91f7bae1ee773e75e7418850e9f83f3281 +size 32286 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_3_en.png index 08ca4ad1e6..557f249715 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4899d2ffcc6da1f414f7fb223440b8463250dc5ac07558cfaee2947f95c93362 -size 42236 +oid sha256:6db7bc187b92d8fda605212e54168649f1385f7fd5d938496510289cbbdcfe63 +size 30729 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_4_en.png index 062c440463..240291e5da 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:577381a33e7f0a88ceebb7f2be6528c3e99417cf1351b74c134aab948664cc64 -size 42149 +oid sha256:8be6501b50d413f75e860bd04f03803cc13965a991e7d64019e1a7e39a0bbf2b +size 37416 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_5_en.png index 1ff34bd6e4..7ee59b0d02 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2bc2699d8dcf770103726c571a6966eacf173cbbad05c4fa6188815aa9ae231 -size 41052 +oid sha256:c56e98e7ff452bd15b7a635d748815b1c8dd5490b9309e09a93a3cd4832db660 +size 37066 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_6_en.png index c1decbd918..f30bbd9f27 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cba49398954a404def6b37f3cde057cb88d6f59249b943f1689403ccd902326 -size 42024 +oid sha256:a10328f429081b196dba40ae60a6100f2489a60a2aab37388deb645549fadfcb +size 31485 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_7_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_7_en.png index 379f61db22..ea46034c38 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:405a29c158295616560152c5790f189a8019bd635a53a69b581c8aa595e6e9ea -size 45494 +oid sha256:cb772e96c733fddf80ba6dda94039d971b1541a39ae349b3736e1a272f0857b2 +size 39440 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_8_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_8_en.png index d0ffc70f42..00e9e79aa4 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f948e9cc2eb7bc73b0441fbdea72d582a042895b3404c8302b7e182c3481fae -size 44425 +oid sha256:cbdce666db6f4fb2a35f854b3e3c652dbbf4c0ba798aff3f5f7bfe0da4510950 +size 38841 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_9_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_9_en.png index 2894ac3c71..7530f500f9 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4702b18ad5d203050140e6e1a18553344f52eb5482fcaf6ab497698b9ec59fd -size 44432 +oid sha256:d9fbc551023fce72f97c6f562306e80e4e43bf83ed35ddbfcd86a1a3053c1545 +size 38936 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_0_en.png index afabfcecf5..f63ae1fe95 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4189b58dd1263a81566ea86d9881c02f053ecb2a91ba9442553fbe0f230e6860 -size 47105 +oid sha256:3b7a58ad7ba5f3a81f0b06a9f464f91ec3b4b39fea3e4db6657bb9bd43f80321 +size 41501 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_10_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_10_en.png index 9f07ad1624..d292c67bfc 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3fced9019f81e5804ea57c0b1a2750868626ad35b9a7227009a796d289595556 -size 44659 +oid sha256:5f92b85722afbc65a584f6e6f064fe6b3b38a888965d97c569c727253f4cc7d7 +size 39519 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_11_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_11_en.png index 74c4a9eef1..f36d741372 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be9bb839a503d169d67d4332a133ce2b3d76b3ff4c52c063436521f8a74c973e -size 43894 +oid sha256:77e3e9dd2ec03e1a4a988e25a8a094d96296149ce7b6dc1d319c71b84dabfb2f +size 39357 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_12_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_12_en.png index bd85882fde..069df089eb 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:82c2781c37b7cefa198f2061a2c8e900b27bd57653db88733be5ff55dfaf5eee -size 45251 +oid sha256:8c182019343e29d186a1f2a7551f82573999a26d12c77c10ee2563aee44045d9 +size 39893 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_13_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_13_en.png index cac488f3b8..d8d659411d 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36feab599a6a2d4269b68f42149a6f82832ac0f6f0e9f01fb49adc21b3a58d93 -size 45172 +oid sha256:85e5490ba14a46176971c2c23eec05d352e871463eed9241862faa9929c11188 +size 39837 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png index 3e7cfcf672..01041d80be 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04bedd62b5ceba766197dd18da9efb0ff086c2c01c9c19446f8a3c42ed43ad87 -size 46813 +oid sha256:c07ef87165b3f4e13108882f108cd3f217f3c6f8930c703b8909f431b2a9ed2a +size 41337 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png index 27ec9f7a25..5a90de8c66 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:828b065aaeeccd826e98e9601069819d7a75ffabab9820a834cacb627416edc0 -size 47409 +oid sha256:19dbd2929dda9108118ede7627241db2249f8ab7a062f17bdc3619ff42253594 +size 41768 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_16_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_16_en.png index f96e1aec74..3d2700e9af 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4740bcd118f8583334dd1c03b5011e33c5384ea6810d1c83711f538cf9f1d165 -size 45521 +oid sha256:c87ff2cbbe4d5912cb17fccfe5fa7614d5260b43ada3b952dedee57a3c004cbb +size 40117 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_17_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_17_en.png index 4d88149a93..10b75e049f 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7fab53a63021ddae8384aed8eaf0a3803d06e8c80645ecc13f79a7f5cced6e68 -size 45024 +oid sha256:77359209da8ffbdd933d123a1a6952da961c75b3ca6a70b6d49ee9be188fca7c +size 39670 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_18_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_18_en.png index fa7e99aef2..4cbe816fd3 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_18_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_18_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:89a2c619412ad9ca43c79cb76ebe72b827da71743dda7044a9b44de2990f160b -size 42388 +oid sha256:a7190a790a208709d20691052ea3de64a359e7ca16d8a988d0ef62b33a64da3f +size 38756 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_19_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_19_en.png index 9b27b61083..8eeffdbcf1 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_19_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_19_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56ceed440bb51039ffe7e4419477a57a235eed153a0188838e6265c241896a82 -size 42262 +oid sha256:15458edded2d32980c16163e6674d714d67442a2421d0af73594590cf6f144d3 +size 38718 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png index 0542085126..c4c2f1822d 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b03e9da2d73cc0e3d0485b73470e576d7ebd4b8b5f375f2a478f1c1524772fa -size 39948 +oid sha256:13ac1bdcdacb72bd268cf00e8e754f5746928723891fe1f70277daa46f67ef1f +size 35720 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_20_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_20_en.png index a320657a26..c70dbc195d 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_20_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_20_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a686a2596b9b85b17c6882aa986b12e13a83a47ed217c4eb6de6aa2cb3ec2d50 -size 45717 +oid sha256:b4b9ca327302ed396498c60db4341c78e3d48079e04bfdbb4ce8f024e82684f8 +size 40307 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_21_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_21_en.png index 920b670806..3a06126d05 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_21_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_21_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d6bda369c1754e2c07216f4bff0285e017f87b550fe0dc6bb5f127845d52c9b6 -size 45462 +oid sha256:f4c7a00882958b916e99ef643cd698229f8659fb8f21e4e2b86db1432362f508 +size 40007 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_22_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_22_en.png index aeaa04b269..e6ccda4710 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_22_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_22_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:285045769d912e98df0371c829affd925642c8a20cd0b6b09dfa92ab5f143538 -size 45131 +oid sha256:a9bab5037912d2bdeb85ed013e169d98f5f7333c274430d69667e32dfc72c1fa +size 39880 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_2_en.png index e7fe0e7cef..0f9431284b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:463548e170b48509d68c0993acb000748b19921e5d4be784b07ce83252c8a5bb -size 38613 +oid sha256:c074ba644aa7ab073e2b1893a2f82a8e11eb479e8f50ab9cbd6e991709cc5d5e +size 33376 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_3_en.png index 76eb564d8c..56cfd78cd6 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1d19c2b8c6b3c80b68214da2bb9f54a6897a279aa70e2d8cab88c291332cece -size 42980 +oid sha256:a07f005c828af6a622527a062e6cd2d8f4120ed4ac4a63daf675cfaf1b36da11 +size 31486 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_4_en.png index 40ab9e310a..f82973cda9 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2057479cad5d3b9a89ec835ee1d06705c6c459f7810c2875bea26b975944bcf7 -size 42960 +oid sha256:ee239549a179ce7678494cc20b32db88a211bba1f6368ba17fa1b18ca3400810 +size 38586 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_5_en.png index e549a92821..a37eaa2ae6 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:073addf26e8d0b638bce93db99d1fe9740abd89613a1eb8ef5bb4324e489d6fa -size 41924 +oid sha256:b56916b6d08aa4fcf55ee414ae928946d5a2bc5eeb610f9ec4ac86cf783aa11e +size 38429 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_6_en.png index 29a8b0b4b1..f305d86263 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56d72cab4a9d7af568cc497b68d6ca9055874544cfd462c93da37fe368801fdf -size 42984 +oid sha256:b576b33a5c3bedaa8d1e7df6e95541730559c8149f5a0d920c9245449b33c26d +size 32616 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_7_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_7_en.png index 91cf700f52..964ccd2680 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9141f5fa4e054dc5cf70126309830bc38d564d467a215eaa1130f3601b15e761 -size 46350 +oid sha256:a7b1c29bca9904fc55d17356c27a8dbe035e1fbbf0ffa27ee2b466cf1558c418 +size 40573 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_8_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_8_en.png index fe0b629925..2ced0a9e17 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a062b8cbe4dfbd94a5b068b1f7c4654ed8b697a7e98ae4c2bcb6c3e5bf473b49 -size 45289 +oid sha256:8ad0f0df59f4231bd85a0ae99ad6eccb74b338975353a201f434e5047fd58628 +size 39963 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_9_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_9_en.png index 26d59539db..9e24db9017 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46aafd39e1a93f8d357def4c5f3f024ad0ee13931ebdb9f72475dbc911fd7532 -size 45266 +oid sha256:616b6050ca126b0630b5283901afe4096f7d041a40a5d6ae8e64ff808f2d4e7d +size 39971 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en.png index b5ff7ebce2..202f8a06db 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49ecd29e87c23ac92f0b5775e95a1b46dda41bbd7bb52a5cbfbcf7cd039824c9 -size 17240 +oid sha256:75880628a454ca00a186e5d1c5438117e7af4ab9b23eb6fbf9c9696210234169 +size 17246 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en.png index ae186ece30..9186ac2de4 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ac03bbed84ae266088d0e487e36ac30ddaac22bdaea6218423a8a41b77f4c5b -size 20217 +oid sha256:1fe61c20e2c6a7bb72e82aefd546469dfc49bf736b6d12f4c1927628df1bdb3e +size 20211 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en.png index 6311df6e6d..ca8464fad9 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d44e5119301f217903d1ca232f17ae54ba96da9a6878e668f603c57bcc23761 -size 22612 +oid sha256:ca3ee9a09bbbc69f2ba7e8b40cdc5196cc53745fe3222282d98bcf948dc16745 +size 22596 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en.png index 90b562aa09..945743ff26 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:980b9744a36174bb8b080a431b277b544dfc045869102147fb9d1186e396b5e9 -size 22720 +oid sha256:96971a8981aea8918c01827403933c9e75275a2fda92716f803e6f28ad284bae +size 22702 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png index 46dead6c87..eb96c3e39b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e611504d154db3889c1a5900e6af392ca058462450d66f0dde762ab4a45e1b76 -size 29532 +oid sha256:06ca0aa653033b59313325ad508c5916e2fedf29ba6dd3a5f714e90d01f4bf7c +size 29644 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png index 73b8b8e50c..5c597300e4 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8a3ad99763929d2783147814e44fa9ec7e7efb7b99949e3580f23c38fb5d971 -size 9398 +oid sha256:21aee17ee9a292bb2f0d3d2ec2db565ebb8d5df753454a5a002f033ed5ed39c5 +size 3853 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png index 9399857173..9b9542917a 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6135b24d94d7732342ec9353cdefb115ce5e9a799dfaee5d57b2e8e0a7ed631 -size 26505 +oid sha256:ebfb75986cd385e9837a24a5f279e07f0744bab5613fd7cbaf0a493d021c7699 +size 26606 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en.png index 8380d60ccd..18d1be85a7 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7bf31df95e781eae5530ed98ab9773f3e7d0f4fd4152226596b78328b88d69a8 -size 27223 +oid sha256:a58e6ed7f10d7014c9c3b55fbb769e04619313212449a8fc582501d2904d669f +size 27315 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en.png index 1a59277355..c1b0c4ff1e 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ebad5a2935050fa87c16c518323bdf3db4494fd8a14a5a03809e3e51f047b70 -size 16318 +oid sha256:bc96eec2d61713f01d43c92812bbf27bc44a202ce55f0fa1dc8e8659dabcfcf2 +size 16347 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en.png index 9e8644ac62..16b567164c 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b427494aa12528f795a49f27912b90ebb59392be0420fc27e3c4014a3599680 -size 19155 +oid sha256:56c4df7da32b71dca109a1db1f4a797a2930e3b42c00eb51d72f0e1f5b99bf48 +size 19200 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en.png index 01b60a339f..ec10d3fd8a 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d301576daafc3b86949208e281479183558d61cbadeb412007ee8436aa7eebb9 -size 21590 +oid sha256:592c6ec197b193803679eee5df7769fa4858fe883a2f3a1294f39ad87f9f4ff1 +size 21610 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en.png index b96d820784..5ff44ac3a4 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc69bdbe8ac22e7d6470a8b547ba364e3421f6d61ccd0c364492dd860b1ce093 -size 21682 +oid sha256:62e99b8070a394ea5b2d666f3a8abf0fe41ea4a34a382223903f2de4085195dc +size 21710 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png index c5d3a63af7..2f5afc02b9 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:641f434040dfc9f040622fd0f17519d353f0bc45a17603ef837e53fad2b529c2 -size 27570 +oid sha256:793cff43740f6e477a255af566985d8bb7b0242d89484b3f0fc5cfec3b4a2af8 +size 27608 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png index a06978178d..4a9b30b4cf 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d9c0f0c69bd55b5c9a925cb89587d959998a833c5927873b4ef358959ce4ece -size 24944 +oid sha256:ad842be0c519bfd7713eb93df2a7216d159970aff1ea44725641c5db26f3ad6b +size 24995 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png index a87d89c701..d47bf90664 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f3a0cb5d9bae6725a1c527f3d9575aabf85d3edf63a28d9faa23f4f0b65e2d0 -size 7624 +oid sha256:520cae2544153ba45f8fe4b021286c2d22da06aa1b60be7f1b13879723ff994c +size 3664 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en.png index 4c39cde004..4964d7d1b6 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f17c5df90399b6de382af8111ba36b0ec072596f42103f76477692a801493799 -size 25515 +oid sha256:541b9ad607838fc9d44d6d3759d61df54c178257fe646366304d96ebda5f7e77 +size 25565 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png index 92bb8a2f0b..cfdc2465c2 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14b54f69d324aceef11b754a3b66def948a22697cda3e7584303b3a9e45c536f -size 64169 +oid sha256:7db669adacaceb7521c6c29a6ffc4b5a96bcfe6de12b36ca37bb944a76999048 +size 70989 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png index 16bb3b6d16..8d8f25cb28 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af9848cd44308df46cf42f3ed812f26e61740d52500b66b979cc03c378110524 -size 56130 +oid sha256:f241e93ac7db5568ec81fbfc23d2aaa8d1a6defa3280f3340b845ed7b554704d +size 57897 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png index 5a91d81f33..860275a09b 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:286b10d2c7cdaaf08373479de879b72dc674d4de1ecb62976ec6fcc53dc72289 -size 62825 +oid sha256:feb4a95d94bd3eb666a75ab9abbd314a2aaffbabf58ef6e48e400ad9fab1b147 +size 69123 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png index e417c8c9cd..e387e49f85 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.root_ResetIdentityRootView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c064561c817ee9b305fe9064d976aa80f4047f8ea5e0cf74f0b186d370f2edaa -size 54045 +oid sha256:e73307fb019a9ca043ece75bd5f34e0198e86e5caf3a82c2e1517e2d121ffda5 +size 55756 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_0_en.png index 1fe1e31cd9..7575635c8d 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e38857c0fe6e6ff461ace5cec20fdf6d82caed44b0f554910fcc5dc4676e6748 -size 30468 +oid sha256:198e6320c42714d651e1c0a770efaa620dca94dff435683a34f06c2e1e946a4b +size 30480 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_10_en.png index 1fe1e31cd9..7575635c8d 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e38857c0fe6e6ff461ace5cec20fdf6d82caed44b0f554910fcc5dc4676e6748 -size 30468 +oid sha256:198e6320c42714d651e1c0a770efaa620dca94dff435683a34f06c2e1e946a4b +size 30480 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_11_en.png index 1174143a80..2daf914755 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf60051d705987828e0bc5c1cbf99b3a65c792fdcaa205376539c8461dfd1177 -size 31381 +oid sha256:0cec64b7a5f5762717821cbb10fccfff4f06695a88d9404a08fcc5b51fc96e3c +size 31382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_12_en.png index 1174143a80..2daf914755 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf60051d705987828e0bc5c1cbf99b3a65c792fdcaa205376539c8461dfd1177 -size 31381 +oid sha256:0cec64b7a5f5762717821cbb10fccfff4f06695a88d9404a08fcc5b51fc96e3c +size 31382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_13_en.png index 709cd8354e..d9747b1991 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9aebfcbfed290def2f0d9c04dabfd9ac0e3bbbacedcad9533660583080424519 -size 60014 +oid sha256:3b46afa99f390d90461f74ca3c25acc3a5a9a47167fc828e2d7bb732073c4502 +size 59824 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_14_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_14_en.png index e12dbcd08d..a004a503a1 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d35b333fd03b952f4edfa724382a489f3a84b7a010980dac6e9e9dd0f56bb69f -size 60442 +oid sha256:d776daac96caf933c8043f4525a7a3e10bd7df82375fb841e876f3855a58d82e +size 60289 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_15_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_15_en.png index 59c7730b5e..4e20779219 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2da1bc59e3f504073ed1875640d8fb696653dd70587161e97d2b738c1c50a7e1 -size 40954 +oid sha256:907f6e63ea0975f47ebe9bcf6211d54910d30bc03bb81a966d0af11f3b8cc410 +size 40967 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_16_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_16_en.png index e31324db68..1a9570f98a 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df2e1fb160f4fba1418c401a6323132ecbbb8718605704d475336547356aa609 -size 57377 +oid sha256:c01448cd985faecdee7a30b2a9195d80a333e874e47ac1d96f91f01163c5b911 +size 57420 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_17_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_17_en.png index 00db7b8791..a011ffe8af 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2203bd270e716624b93f25adb37dd71afbf25a5590e72e65ed4e53827355f02 -size 38832 +oid sha256:7b36d73ccf855d00bcb85772da0a295efc4982bfba45867373adaae9cc1da086 +size 38816 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_1_en.png index 1174143a80..2daf914755 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf60051d705987828e0bc5c1cbf99b3a65c792fdcaa205376539c8461dfd1177 -size 31381 +oid sha256:0cec64b7a5f5762717821cbb10fccfff4f06695a88d9404a08fcc5b51fc96e3c +size 31382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_2_en.png index 4d13452bf5..4a2acf121c 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87dab9cb3231c932913d446c9b60515a31394f7c2ea87093aff460a75d1f85f5 +oid sha256:a92bbc343d11f32019369bae97c582f1ff0e6d867c9bb85b8b2f82421cc0656c size 31738 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_3_en.png index 51a6988af7..80b46c897f 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06e4300605e15dcd7f921c2bf74ebae809432a0b723ce986d18b853144ef9de0 -size 30557 +oid sha256:6b30fb3c864ef609f3e6fa861bb77773f25587ccdf77ae2dcfa71808f39474ec +size 30571 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_4_en.png index 1fe1e31cd9..7575635c8d 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e38857c0fe6e6ff461ace5cec20fdf6d82caed44b0f554910fcc5dc4676e6748 -size 30468 +oid sha256:198e6320c42714d651e1c0a770efaa620dca94dff435683a34f06c2e1e946a4b +size 30480 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_5_en.png index 1174143a80..2daf914755 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf60051d705987828e0bc5c1cbf99b3a65c792fdcaa205376539c8461dfd1177 -size 31381 +oid sha256:0cec64b7a5f5762717821cbb10fccfff4f06695a88d9404a08fcc5b51fc96e3c +size 31382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_6_en.png index c87102abd4..d846e3547f 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25a0537f0b46efc42176e30bfa3f9e789b0b53612fe6cf683270ad5c5b51399a -size 32105 +oid sha256:2e1c127d917fbc8a655fe1f957b879472bb940c7258c33e406d5e257732fb9d1 +size 32093 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_7_en.png index 1174143a80..2daf914755 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf60051d705987828e0bc5c1cbf99b3a65c792fdcaa205376539c8461dfd1177 -size 31381 +oid sha256:0cec64b7a5f5762717821cbb10fccfff4f06695a88d9404a08fcc5b51fc96e3c +size 31382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_8_en.png index 1174143a80..2daf914755 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf60051d705987828e0bc5c1cbf99b3a65c792fdcaa205376539c8461dfd1177 -size 31381 +oid sha256:0cec64b7a5f5762717821cbb10fccfff4f06695a88d9404a08fcc5b51fc96e3c +size 31382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_9_en.png index 1174143a80..2daf914755 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf60051d705987828e0bc5c1cbf99b3a65c792fdcaa205376539c8461dfd1177 -size 31381 +oid sha256:0cec64b7a5f5762717821cbb10fccfff4f06695a88d9404a08fcc5b51fc96e3c +size 31382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_0_en.png index 5558390316..888bcc72ac 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da05500aaf5ed3adf5f1057ff3ac865c12a9dfde77791592425260f3578d1161 -size 29619 +oid sha256:507a24f95e364976360e03baa3a8c7fb9aa47ae013e1c299b984a757a83c6211 +size 29627 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_10_en.png index 5558390316..888bcc72ac 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da05500aaf5ed3adf5f1057ff3ac865c12a9dfde77791592425260f3578d1161 -size 29619 +oid sha256:507a24f95e364976360e03baa3a8c7fb9aa47ae013e1c299b984a757a83c6211 +size 29627 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_11_en.png index a720a81a0c..aa48b9f158 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e92252579b05080baf11b2b5ae7b761e1225f9648365800c30b50283e7fd5afa -size 30497 +oid sha256:dbeeb89350b85c5ca23f9e4d8bb980bcb5620217150b6434d2b4c4d1df4e74e9 +size 30498 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_12_en.png index a720a81a0c..aa48b9f158 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_12_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_12_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e92252579b05080baf11b2b5ae7b761e1225f9648365800c30b50283e7fd5afa -size 30497 +oid sha256:dbeeb89350b85c5ca23f9e4d8bb980bcb5620217150b6434d2b4c4d1df4e74e9 +size 30498 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_13_en.png index 6dc75b18b8..7a6b531589 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_13_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1dcd0009809a127c1018f6e942fc90baf78c7802c86fd384a273f51483a1706 -size 58048 +oid sha256:eac4a38a303f4d590bcd98d5f82402234009d4929d42290661b9a388972dedf9 +size 57879 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_14_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_14_en.png index 18b9b26a65..503ddfa0b5 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_14_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_14_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66e2230268a632877b50fefe34ddefcd6f9ff31a34b3107c420c36b12d7d0f83 -size 58539 +oid sha256:5b87f75ef0fb631db93894aa13b4a157b70d73a3143f8a6efaba6e5fa2993856 +size 58587 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_15_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_15_en.png index 8b3123e8f2..4e00fd1711 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_15_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_15_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e4cd430376a28e6ca20082c328d1f15953b5ff54e00d99cd49078eec9e62a54 -size 39883 +oid sha256:ffd6e9fbe283e921d5db9a6df46801300e0d1ff3879694203520491e4f7e33f0 +size 39907 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_16_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_16_en.png index 77d0152a6f..3f6dfb400e 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_16_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_16_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b69d7e7875b3b4c332d683b121902f88ad217641841f72cfa9e95a64eec53a5 -size 56252 +oid sha256:1ae027d2fd14b2fcf5ce1121c0986f4e54f1156d660d16e667b8d176a1ef2e81 +size 56365 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_17_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_17_en.png index 792574e392..ced01412cc 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_17_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_17_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45d4a147b71606727225be183a67b780dbd01a2c9301952c9dbd8d712da8b56a -size 36418 +oid sha256:ddd31f317fc31f901a25a55b95dffcdee36a054e69230a45fe8be7179b77fee5 +size 36405 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_1_en.png index a720a81a0c..aa48b9f158 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e92252579b05080baf11b2b5ae7b761e1225f9648365800c30b50283e7fd5afa -size 30497 +oid sha256:dbeeb89350b85c5ca23f9e4d8bb980bcb5620217150b6434d2b4c4d1df4e74e9 +size 30498 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_2_en.png index 5efbc25fe9..779bfb91ff 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:227509f9ae8414add5f091cde3cc068aec0385674b09c5c985b1e0758bb759d9 +oid sha256:e15b5a6bc261e7a5f579ef87d1a6fef7896f74edebe4bf01ddbbdaf4439be34b size 31010 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_3_en.png index 89fb6f32c5..fbe7eae12f 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa32559c70491ea4bb7f315e493effe205792d8a7186e4ba8e484d31c109eae6 -size 29733 +oid sha256:622f8a378608576d7491597c6ef50e9cbef3e9fedf3051339c4891357e70e9f5 +size 29739 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_4_en.png index 5558390316..888bcc72ac 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da05500aaf5ed3adf5f1057ff3ac865c12a9dfde77791592425260f3578d1161 -size 29619 +oid sha256:507a24f95e364976360e03baa3a8c7fb9aa47ae013e1c299b984a757a83c6211 +size 29627 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_5_en.png index a720a81a0c..aa48b9f158 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e92252579b05080baf11b2b5ae7b761e1225f9648365800c30b50283e7fd5afa -size 30497 +oid sha256:dbeeb89350b85c5ca23f9e4d8bb980bcb5620217150b6434d2b4c4d1df4e74e9 +size 30498 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_6_en.png index 3f191818d9..a792c8206b 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77d5c5c44ca5d5976300b5e580184cb414a3c1f8f49dec9cff50fc0ab6b749fc -size 30226 +oid sha256:d921b380e05063273f52c4d7fc613f464a43ad1dd28c8aeda6ec101f653f2fd5 +size 30224 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_7_en.png index a720a81a0c..aa48b9f158 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e92252579b05080baf11b2b5ae7b761e1225f9648365800c30b50283e7fd5afa -size 30497 +oid sha256:dbeeb89350b85c5ca23f9e4d8bb980bcb5620217150b6434d2b4c4d1df4e74e9 +size 30498 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_8_en.png index a720a81a0c..aa48b9f158 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e92252579b05080baf11b2b5ae7b761e1225f9648365800c30b50283e7fd5afa -size 30497 +oid sha256:dbeeb89350b85c5ca23f9e4d8bb980bcb5620217150b6434d2b4c4d1df4e74e9 +size 30498 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_9_en.png index a720a81a0c..aa48b9f158 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.root_SecureBackupRootView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e92252579b05080baf11b2b5ae7b761e1225f9648365800c30b50283e7fd5afa -size 30497 +oid sha256:dbeeb89350b85c5ca23f9e4d8bb980bcb5620217150b6434d2b4c4d1df4e74e9 +size 30498 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_0_en.png index a5f2c81709..9d9b261e38 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba633616e0a212c5d527173132f1d53a8e9775b50e57a5a36890d9c718c6ec71 -size 37675 +oid sha256:0cf081ce4abb6cc0d5e80ac8387a91e29139f79762f107eb274d70246950c552 +size 37667 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_4_en.png index 7eae95af52..3c34238b9a 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b50240738139691f82a0a202e31c19c23f9a6102b405c36349429868dbca3df -size 42037 +oid sha256:4e89a186de091f4e23630ad5fc71c0e01296876d8c3a2a5fc6fa6ac00220e468 +size 42083 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_0_en.png index 6e9c334d4d..519167682a 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ba6d622adcaaccf8c6cfb8a446ef0d350a55d749dd6687e6a46d7b0564a2bb1 -size 37680 +oid sha256:4be298e13b622228c0890d8597b304507fd7c8057fb776cb8f1857a5b9e6d731 +size 37588 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_4_en.png index 2008361428..43a70b4471 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.addroom_AddRoomToSpaceView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b028d11caea922f209a19d3802ba9c7ce753a3146d7d77461e85c741f35d6dc -size 42481 +oid sha256:bd2b7f829f6232c62980386225e82dd946e132dd50f8e571b74a7f305965d26f +size 42395 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png index bd95e60ce0..cf3ad87af2 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73608be44121b6125f14e3186ee533a5e479e30124e4276d342a25b476c00fb7 -size 46960 +oid sha256:5bf5bde86a7f7e873a6871d359f04f2139099724f9977601f5077b2590e97965 +size 46711 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png index 02756acf7b..a31ad79f82 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ea33f7c49c55c81f976111bf79bdee21eb58f3394c8135a0324f6a503dc6fad -size 47044 +oid sha256:078079bf6b37471c7a16363c9d49f7deb5bd9d044ed0591ab86ac8a20800ba03 +size 46795 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png index cf42cff8c7..5f77c0fa62 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed108284075a1fc2523ac38d63dbff3176dbeb97942995d4b83aa4f0bc3de240 -size 48636 +oid sha256:d36b97324b3794ff1d01fc13e9e59afb010130d6e022dcc2d7cc9387a13a787e +size 48387 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png index dc324f5b6f..5f67807828 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb31f13ac29f7ebbbe18d2314bfaccfd20f87c308edda618ba36a6f968e2fe33 -size 59929 +oid sha256:986cfe49b91c522cf3a85d0425c0677a6929c44dca1531923bff2c1766ce46ae +size 59583 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png index 462cc991f4..12d1c506ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ddc1a68ff028108928942a2ceb6df4caa3ce4322bea836b409e9a7ddf991194 -size 60567 +oid sha256:20742175a23c7116089cec7b9886ad567db50d899dd5dca4388534d6120d73ce +size 60252 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png index 34300310ab..490c357afb 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0322da022d57cbd3b167f939d00bffdba69758c6508256f1251826cf5621b18b -size 56970 +oid sha256:7228db8e07c808d0a8780ed06f04f22ff8f1d620327f9243b1dedd476cecb902 +size 56896 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_6_en.png index b955245363..2eab6f67d5 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66b192f5717657395d5a5cbb9d5d409bdc8ed5df9afc010d5a619608a9e8b867 -size 32741 +oid sha256:9e74142d69c0223cfdb41d31321c997f9924a911b10961a85dec5d7a9b55f763 +size 32889 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_7_en.png index 310ba5f663..71d817456f 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3aecd8b25c698ed6c0b1682535657f196edd677bc0648ba0d42c1b109840fdf8 -size 33429 +oid sha256:335a04a4ba72df31e5daeede1a4e3a4a83c77c1317dc736bc29ba6722fc9ed86 +size 33573 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_8_en.png index 386b14d431..826e4f3f05 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4d0e00d43b270c509920103f913609e784387b1c06e4cacf01dd106387b3ed1 -size 47806 +oid sha256:ee34f6503ca5de3a1f0e4bfb546605b3ab4fe2c710891733cbe16fb176cbef12 +size 47747 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png index f9e70f5c88..039776804a 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9b3bc80e39daf9809464a771089e431be993e8faba40431784990f61e7c2a4f -size 45233 +oid sha256:d28be1c00397b6ac456ef93dab7b1da469a7665380ab2c326124efeef3a1c150 +size 45143 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png index e6e4b0cec0..6847911e3c 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa6f0b045b83a4bd8b1f2ff9727964ec82ce7781f575ee6c1e306eeecd7da63b -size 45319 +oid sha256:81523eeba6cf9e4ea1e92cc819845bc95bbd76f9e977b462f2357fe1d2e3d335 +size 45230 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png index 3bd02250a2..763fae759e 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:471ed0a332d92a41a82536c5ac2204909391730b811d44f54d8b308fb03447f9 -size 46791 +oid sha256:cdff40a4ce4b77a98818798c2b6ce3ad18ee5117f40c47c075b30d7006626f10 +size 46703 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png index 15f3619b7d..760d8a7533 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:325ef5fb725ea61c382eec96668b4fbfca9eee08e1503eb72e298b4d62d684e1 -size 58256 +oid sha256:1d331297c0912ffc278828cd00f886c926a71e59aadbee9fef994258ea56c822 +size 57757 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png index 51d1ddc9f5..28ef695554 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd73b018c8fd459eab5849c942e4f992357abbb4d0e0ba1cc5847e0985ff335d -size 58836 +oid sha256:ee1ee7ae5a0350ca808b1839d7f033cb83947d33305a5cb5ff9a9faa4a5dadbf +size 58345 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png index daaaf7a44b..5f5b2315e6 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57cd29c2032d425f94551a0fda528ec5dbaa467900f6235fb40aa6009ee22bec -size 54897 +oid sha256:936cf07258d4a001b80b08df4b804c990b9e399bf8a5a544443beebf93caa298 +size 54825 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_6_en.png index 28ae8f6a72..918bfffb69 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:053a96fd3fa0cc84d7c4eaa7464568ff89b6354b1c59a286a4f9a328f9744c8a -size 31849 +oid sha256:f3c87dfc20c6a6ff08e6828d47670812af0cea19640cccb9a9e5a8ca1f61728e +size 31957 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_7_en.png index 3e9cdacb45..eadb187764 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb4de4018e0e43a9e2d858d14a36faaf9fa44208641fcd2779710e184d091ce9 -size 32371 +oid sha256:199acd884790b0eecd1333235561ad5dd2419c527e3245d58525d46ad7c51262 +size 32537 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_8_en.png index 214301a8d4..926f10755d 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa8f3988277d095b3747da35db43b8ae1c854bdeef484c243ca415d728610535 -size 45173 +oid sha256:66d5ac09ac603108821e0f333866a8e0473d562deceb103cabb67c4988be2c72 +size 45107 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_0_en.png index 4a332a8477..95af0557b4 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6d6fb02ec741944efd1a9f994f096cb74cb43e90896934a815a7f3b0b75af06 -size 22085 +oid sha256:65e6adcb15b51201224b3566ec85b9a935a45bc5b9a4b9a5d2d1db125425fe59 +size 22063 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_1_en.png index 4425a314c4..e50ea76ce9 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc1de1f9b7172a67649aff0c2fa2cfe2a63fbc46659a8ad2bcc5d417b3340e9b -size 18415 +oid sha256:f1b901895aa8cce2f8c183ed872c5b50575faf9c1cfb58e0225a22a08b0443ed +size 18385 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_2_en.png index 00f43cff0a..83d98a46a0 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f26bbf2bbb816afe552d90b8acc3bce845fd7c51ace192693d0f92c5e5ea8985 -size 25939 +oid sha256:a87ef69a7143c6b637bf87fc82d7d04ea64d5024c6f44411d2fa60fb04d9d882 +size 26065 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_3_en.png index 7ea1b72ecf..842ee7204f 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d8e3ab098ffd7d1e3e2abe71d0f6003915e470c68830c40617ca28f4af1e59a -size 26576 +oid sha256:7e6bb50005ca745dae15c2e4d7a5f28368effce2917c9e35ebeaf21b69e5c4c1 +size 26584 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_0_en.png index f1d2fea72b..aa6160d8af 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8b74f059c7d27982d0f8d33e7b59a3a588d547f755d0bb352836fb55f57687c -size 21495 +oid sha256:087adc479cf8e9b87f4f269b94fb8b3661b0a6902a0b9d921622bfafa53e0610 +size 21516 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_1_en.png index aa024acf89..8ea57ca08e 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9f9c84fe76cb723586c05febe97fd45068de975494be4b0aebaf518b18826765 -size 17809 +oid sha256:afabb2f9b78af8ade56f79a4bf02039c6e4b3ccef8c60e89439de091da089ca7 +size 17840 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_2_en.png index 2312f3fb08..c538831670 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9bcf5c92a8aaeb33c7d56709e8be38f6262a95b8bb07e4ff266685eab901b64 -size 25088 +oid sha256:0abf4b9725268a7762ff1b426cc97f96d8e71012d35102c968f518f05007241d +size 25210 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_3_en.png index ae049d944a..5df4e31394 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.settings_SpaceSettingsView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be20525369f79cf4ebc5057f9cc46123bda55b923470e33712acab2f2a6841ac -size 25700 +oid sha256:9c5a119b8c5bd09a62382343043333dd478ab82fdb6f04ce420641edaf6fff7b +size 25649 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png index de213ca597..fe1b0eaefc 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80e8c8bf0bf9b34d3de0b0db7f67b84a667a9f510d6e9eefc708de25dd1ca5f8 -size 76725 +oid sha256:bd072c509f967d275a644f545dd262f3dd20f08137bf807d33417ecc84376734 +size 76496 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png index a980e0c914..1b32cb5522 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7e8bc45d019ed73b4795f29b36c28411e8e20cd4bd231e76e8619e011b64b31 -size 40203 +oid sha256:e2055eb028a88a3b657919f4831c42ae394d473be2fe16a62300add6c636ff9e +size 39914 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png index 6a5952ed17..ab57e18c5e 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7624e76ce5c2f4af5b79f0be0beb3475d12bb24bb2db0cb1ed0efa506a5dfdfe -size 38153 +oid sha256:177b40d6be14bbf9c54722f8b6c0186b6b484a0435fcb43e888fe013a6f27a45 +size 38537 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png index 69f773c50e..757ee11ff6 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94adb63a8654181481e7f62652100cf0294f9c79c1555e2e078b1e27bb15f066 -size 52548 +oid sha256:998781e9e468edba5b1c5bfe6bed83c8c0dc49754d5bc965181a061abf031b94 +size 52304 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png index 850752a55e..b4545ab901 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a75b5ecd5a4747566d8a39ecc4cbbc3583e5abe6a78f9eb820ae0a8d7ee9e7ae -size 37654 +oid sha256:32e7c3787719824d7921145dbe734db4ee4c733c81e7e236a30b0cea9c0c4867 +size 37675 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png index 80c43282b5..459ade084a 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba3e35a4ffc2bee9cb71dd997b9b431faec269a345d2e3f7e93357aa2f16ef2b -size 38941 +oid sha256:bd727247ea40290f61c8ab9a9a1a4397985ebcfc77e31fc4b8efa8741cd671ae +size 39343 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png index 90c20a973f..553160b7a3 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e908ed57e0b9b8072267b571b7ef0689f643ee30e40d26235184cd4bddde9be -size 54034 +oid sha256:3bde94f2127ee00f5a6403f8fa246658269c59eb80542cb978d6a62928566eda +size 53675 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png index ca5a3f8dcf..66aa1970ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0d318e399e0b3120ad74b409f0d53197c527f2d0e6d8396e301b7a70a9473af -size 37592 +oid sha256:28f70212c98536a1887e5c2d3189ba080bc51528f433667789767562584c1006 +size 37493 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png index 0880cea78c..625cb9e429 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f648cf1318c4b2bb46a626d6d444ba602bcd40bf21ade7aa1f0cfbc71b6b3661 -size 16863 +oid sha256:cbf6d4801f297bed6a78b2a7ea6fe3fc842dbf25b523600f4995071a26707e07 +size 18513 diff --git a/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png index 5ae710e4df..27f8eb68a4 100644 --- a/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30b6854ad7a74c42953bdf1a00f2106504ceede002fd944b66c82a086e512cdf -size 15831 +oid sha256:b357a835c068cfacf4f304490eff060f5758750f407043f337fcff3e4c771398 +size 17471 diff --git a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_2_en.png index 7951440a2f..3419a50b07 100644 --- a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8185065602221f9bf675398d42c16f9e0c7ae65952b865689263878f43c545d -size 24110 +oid sha256:9973d9a9fa00d362eae8f50c2936e5ae0adc2653b4671413b856c1e73538eb73 +size 24261 diff --git a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_5_en.png index 12563b1b76..7e6ca5d507 100644 --- a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c3ff3444b2f720b09de118af05e1376001bf3cfe9be66acec4a68cecfe9ae6b -size 22357 +oid sha256:4a4154169fd6e74358001ecc151a0cb4635423bf4a0b2d72f1d5bb12dfb0ea95 +size 22446 diff --git a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_2_en.png index 61d82d6084..224210123e 100644 --- a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2f2787f0aacfa36596b9fa0e25d990710870bf5ed25d831b47c5c71ac1d3de9 -size 23377 +oid sha256:e28754f90d584c329a5e3c51eba89c166320c69fda309b6b06b6f5ee9c74c1b2 +size 23549 diff --git a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_5_en.png index 90376bc952..408be83664 100644 --- a/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.userprofile.shared_UserProfileView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e7e43be60d1a545621d9d64ae3500980056f2c405c8d22629ab63e149aad224 -size 21816 +oid sha256:3b815d4cf8ed95cb983072d75419637c10bd4808ddfbf14865409d0a4fd64c37 +size 22070 diff --git a/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Day_1_en.png index 8d3858b48d..852737ca38 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b44e998e6777d291d1ece8dd0417b585627ad546376e0fc79fa6854d0ca55a8 -size 43011 +oid sha256:8c2e04e52d03cba2460f7a0799cda970bcc49bd45ed2cb2de3d39912c0af3a2d +size 42267 diff --git a/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Night_1_en.png index 84cd91fc57..978e8ae5c8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.accountselect.impl_AccountSelectView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4a49586145ab8dc1a11ff0212e3a38d865d39c929ec9c63083c9e2ed0e50ea6c -size 43869 +oid sha256:db7080fcb2bcba0ae22264ff0cd0cc5a843b3d860d0809750d4927a0eb1a9a27 +size 43353 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en.png deleted file mode 100644 index 39c95115b8..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.organisms_InfoListOrganism_Day_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e7d9d8fed9ba46489e2e079fd8999bd0b4716192c68f4be9a109b998ee5c2f15 -size 11185 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en.png deleted file mode 100644 index 549d8acbf1..0000000000 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.organisms_InfoListOrganism_Night_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:32284987439f0a1dd25daddc666348b48eb842ccf3c58d3be22f4c7973bc507f -size 11014 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar.internal_AvatarCluster_Avatars_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar.internal_AvatarCluster_Avatars_en.png index be83c1a4a5..ed8f933e05 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar.internal_AvatarCluster_Avatars_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.avatar.internal_AvatarCluster_Avatars_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ed3c503d7aebfa335e7fd32e3b324acd6554d4bc64c4b943c20e2c9b01749a6 -size 59593 +oid sha256:117c38143692e2b556300ec2e004d778c7a0ebba898f835f6c42804ce51128f5 +size 59248 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Day_0_en.png index f4959053a0..a14d3dcd4f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:93573679718ae2a1f3a35474252405d7c6dfac545291f9ccd7a722ad4507aa73 -size 58491 +oid sha256:eccf518dddb9b946e435bf391e56d6c4ddb4b5a7784d5bb37255f6e41e115376 +size 58509 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Night_0_en.png index ee5b8d78b9..e93b92458e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.button_SuperButton_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f50b0f7cd8c1e3ea5ac706f93d4dfc5854fb56004d14ecf687c99aaa06c79daa -size 56908 +oid sha256:a6f1cb3bf4371adeaba17975c9f3d601bd021a29f4ec2c2fd9517d1a35fc61f9 +size 56982 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en.png index 071b8e84ff..29fe0beee1 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceCategory_Preferences_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4fb6f62b05652561db4287ae9da33364dbd03d80f377674539055958e098f6bf -size 24840 +oid sha256:3f56ec8ce787f1c5aa7f107daf76b1c114b4336b9e863b09392966a1568077a3 +size 24714 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceDivider_Preferences_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceDivider_Preferences_en.png index 31b672c5dc..c57939a437 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceDivider_Preferences_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferenceDivider_Preferences_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c85b1425ad016cf91918b845ae26b0d2867d8ee87ef2c234720d69350083232f +oid sha256:4a1517ac6b95b00e5242bd15cf8cfefcb996a5bd16f1e464be852eceecb0c006 size 3723 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Day_0_en.png index 6e0970e7b2..64086bcf0d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7dd7f2e6cc58bdc6e3e0b837a95c71b6349acc7596316c13cc3ec03d302a3583 -size 22143 +oid sha256:2765082210b5e2d66badac2176460337972df0c5c82c8512a700fe941cdeeb7d +size 22232 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Night_0_en.png index b231fab335..4b3ca0b6ec 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.preferences_PreferencePage_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce795382500675c5f7b6aedea6c02353f91115e807fc3f6b3f8d9687dd69b74e -size 21501 +oid sha256:9020479ebc44a6a41f4542bd6bc78240ed701dde274a320f2dabb5e3a62d8fe8 +size 21548 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_InfoListItemMolecule_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualListItem_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_InfoListItemMolecule_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualListItem_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_InfoListItemMolecule_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualListItem_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.molecules_InfoListItemMolecule_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualListItem_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualList_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualList_Day_0_en.png new file mode 100644 index 0000000000..ddbaaaee08 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualList_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa84713e216a9f9f153470d94886024b3ddead8aa0ccb5ca851cbac590ee2e6d +size 10341 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualList_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualList_Night_0_en.png new file mode 100644 index 0000000000..3a2b980e3e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.visuallist_VisualList_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd517f2b15ead6246fc42538a85663d7339c3d441e562b71be6016a9c2debe8f +size 10207 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Day_0_en.png index 8651620e23..3968564313 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12195a28876c3c90b0488edf00046f5b941faa8c7203e60f5ab9317dcbe35cf1 -size 25757 +oid sha256:8c25056de98a8d1ede49e5cbd2c233a167162302f42e2c659aa0e1695ce09375 +size 25642 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Night_0_en.png index 58efded42e..8687df4a7c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components_SimpleModalBottomSheet_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d6ab0c3e8353c2e3ce517065fb66c1fca10d58b96081c0dc7a44d59dd084cb3f -size 24498 +oid sha256:7ffa5947893e59d3e534e070116a66e93e3c0163a76d7712b551177c2fea7bc0 +size 24314 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en.png index 9a43a2f7c3..c2cc051da5 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerDark_DateTime_pickers_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:15974f532df8a3bebbedabf337889e3a5d71cf9d594389e00dd3e7ce62fc84f8 -size 30491 +oid sha256:6d15e20d75dbdcee96ac1fcaf1f32113a70f4a6764513cd43cfe107c435448a1 +size 30474 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en.png index a31ba55583..db7e037964 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_DatePickerLight_DateTime_pickers_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46f03028f5a3275c6b5a988de5dcae722effb383830f85fada87384ec6f5f1cb -size 30854 +oid sha256:c807742a58a19dcc4d40ee9354a65bc4078f861fa1b6ad269363d22f10784cf9 +size 30875 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en.png index 264ff76564..bf5214a86c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerHorizontal_DateTime_pickers_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0672e8d71e04366d0fd7622b3758e7ca310b627b7424639fef58f91c324c3598 -size 46781 +oid sha256:bd3ed851b338dcf146956d4e8e20e21d9251f0db3568c053d67151ae7130b6bc +size 47620 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en.png index 9a38ed9e3c..c6ec33f16b 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalDark_DateTime_pickers_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b456443ad681ee4edcbf5a605f9799062c5482f060506ec0f597056cef5510be -size 24316 +oid sha256:3b264da66c8b9fd84cd489bb861469b40466d9a8f50c7192d79fed1ca6aa13e8 +size 24987 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en.png index 393ac87bab..f6bb2f88bd 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components.previews_TimePickerVerticalLight_DateTime_pickers_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f60460469e16407dc671c08071a03553d2ffa81cde48bed19628f46b86cb778 -size 24033 +oid sha256:064c5e3b6b456607280127c44e4d62184365fe35a533fe584c123b3316907a99 +size 24683 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png index 79992a9708..fa2208b50f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_AllIcons_Icons_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30b39281fd597089c94c8ff1680297143989d6da97d6f5b15198be5f92469483 -size 114653 +oid sha256:de697fcf50bd244978da1143a80f872650a424c3e308fd2c4c66005f30cbf6c5 +size 118141 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DropdownMenuItem_Menus_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DropdownMenuItem_Menus_en.png index 7a670bffea..5a9428a52e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DropdownMenuItem_Menus_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_DropdownMenuItem_Menus_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b46d08f9eff6321a3102cc9756b53a665702a32021365a2d2b8917446beb3efb -size 23804 +oid sha256:71076c2b51e510c0a7bdb8d2e57196bdab02072964e82804fefd853b3eaabfc7 +size 23957 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalDivider_Dividers_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalDivider_Dividers_en.png index b391c4321f..0cbd7da153 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalDivider_Dividers_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalDivider_Dividers_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c8372627f3897fb6caaa4a23fac112b4e2aa7a9d6fc8a6fe6a48752c5d06345 -size 3845 +oid sha256:57a530a13f053a775520527c3909e96aeb599521b42eff587061911a3e29ade5 +size 3851 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png index ee5c582240..58546b8522 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75de341f705bb22955f9399180519b65ad59c2e1917317d56e50ea4db78f35bc -size 12102 +oid sha256:30357bf18792db5ab20085010251170a724ffe8c00313facd04ee704e806af64 +size 10982 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png index fedead0fa8..52fd9b9693 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4811667dec0f32accc5e2c8a5dd5c0b34017fcff8d1e0376ee7a4708426bca0f -size 9838 +oid sha256:58b9491aaa5554b89d86c62a5c9c44975367538c6baa5562f8dc5768f76d8264 +size 8705 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDescriptionAndDivider_List_section_header_with_description_and_divider_List_sections_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDescriptionAndDivider_List_section_header_with_description_and_divider_List_sections_en.png index 24654229ff..4b6b96dbe3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDescriptionAndDivider_List_section_header_with_description_and_divider_List_sections_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDescriptionAndDivider_List_section_header_with_description_and_divider_List_sections_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56e81753c623450107b1f34eed6ef12473c3891c5d6f23e90fa1265369623b35 -size 25341 +oid sha256:3145a6b1b6b74831f0aea71fb002fa7fab97affa6f8bd9a2a62a22bbf4dd391f +size 25114 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDivider_List_section_header_with_divider_List_sections_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDivider_List_section_header_with_divider_List_sections_en.png index 88193307f2..ee77d862b5 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDivider_List_section_header_with_divider_List_sections_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_ListSectionHeaderWithDivider_List_section_header_with_divider_List_sections_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5abf26afbad167c6cc1f92a60b1eb73c0d2e1e5c1f354d66326990c7a729ee9a -size 8610 +oid sha256:aea3fb4fabd829e27acda01561ee58dd885c8348d150ce05d128081e7f9f3517 +size 8582 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en.png index f5d8e0173e..50b712b4d2 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:368aec8db00c98f5e2b73763826f484c4ca395bfee9156cc7796029f57ceb907 -size 13464 +oid sha256:88d49b19b4ad6ec1a04e6adf0c0a7bfac5a20759b851a021cf3d41685e174508 +size 13530 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en.png index e16de72924..6422edb4c3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarActionBottomSheet_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:707eaf1db064e542041746c1fff6f81a47e95a45579a9738f7f02573ce6db0f8 -size 12261 +oid sha256:02dbdd5d3c6c8b3dda43b71cbec72448d89d5950ea70c270d4ce88270b3c8c03 +size 12305 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Day_0_en.png index c4375fefcb..419371ac1f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:806e56c218a0ad1c69dd997089cc8362e30624377fdceffeefadc523c712203b -size 173137 +oid sha256:90218efcddebe9896e2b2c937f4b408ffe07479f2ed5418ae3e070b718195cb7 +size 172920 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Night_0_en.png index f946b46642..e1ec5c888f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerViewRtl_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e25f6630680dcdf1e685235fc551dd6ea853b0902f30234e5fb9d4050f584450 -size 169862 +oid sha256:22523ffcdecb0d1775ca08f3b2fd29c24eae32b7dbe2857dce5d70020c975101 +size 169627 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Day_0_en.png index 7cea979d00..1d03fc7475 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8185dee1ad113c2b32a74de58c440abb366337accd1dea12047a85d323eff9eb -size 171610 +oid sha256:39f937c61446d35ddc45f76aa53e612ac3855d00cbae475574c954926cda8250 +size 171084 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Night_0_en.png index 7118f2310c..9ef00c806a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_AvatarPickerView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a13dd8a9228c1526482f0c7fd5e0347c8fa4998849507b759a0c9548455adfe7 -size 167957 +oid sha256:f0cf40f1bb4d180e2cebeac0381cc38c714be19b57f9b0ea7d0e316a4ead531e +size 167332 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableResolvedUserRow_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableResolvedUserRow_en.png index 28e63caa03..32ed8ebc5e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableResolvedUserRow_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableResolvedUserRow_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d372726c65f1887a8eba63f04301212780ef04410fd0758d314562f6899859ea -size 46072 +oid sha256:ef82fb23d7da19f1c3f37c3fbd1472f138a8edb27c307072cebb3b2444c239ae +size 46245 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableUnresolvedUserRow_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableUnresolvedUserRow_en.png index 1cd0c138e2..4655e07a84 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableUnresolvedUserRow_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CheckableUnresolvedUserRow_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea6ea46123a211b87daadf29aa87588f4e0fa5e5c25ddc0307db490c72f865d5 -size 96925 +oid sha256:24c890859cac9e93ac69ea6914902a185109e6c063c1187f64e3740307414e3a +size 94973 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en.png index 1c57c30014..a44cb090a7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbbe069eaeff3c1bfb39e4b3e3356e92864f10a57ca4ccb2029e38b5977b6f45 -size 25648 +oid sha256:06d26a7f7fa05f1844a93130ac8110c987e3d53d51da246cb474f770edd67413 +size 25541 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en.png index e8d101b4b7..2a2a9e5708 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97e6bbc6cc6d5bb90606bc7f934258c8060d7ca5fade8da6a1aae288e8558bb4 -size 38390 +oid sha256:70bea7e1a7e3fcfa9029b61c2f1ce49c911bb7301b14e10d532334337dd50ac9 +size 38316 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en.png index 0a5082edbe..ec9d631693 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b14f8a5a50deb5dd4854665cd41511228f5ba47b0719bf35b4d1675d0f20ce1 -size 24527 +oid sha256:0d5a96a18c59042d9560ae657e91ed0cfc7667fd430fb3b1423fe88f18d63ceb +size 24348 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en.png index 6d872bf044..a4b83c0500 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_CreateDmConfirmationBottomSheet_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:841042eabcd85626a5182108edae46b4514f84a8f22c57e324c02430536acff2 -size 36738 +oid sha256:f7d2e2efb9d44584e96986d8dcd69b100c75e64c2f4474e6f1e0852565d40410 +size 36571 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en.png index 355afd8b64..0f252b1607 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2222b0d2d1589df67d73aad8eee9a1f30efb1392e0c5493f47f69cac01c8710b -size 31044 +oid sha256:39eb057c5afa754f2a9f21789cc946901982efb7c29adadab3396680051d7a96 +size 30951 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_1_en.png index 851f4f8125..ce070bb34c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20fa72623728a8f1b8206af75dcba3b83384aeab2977fde952bc4d3000aa7d7b -size 43579 +oid sha256:48bd7238ff41e9ae218c1b2369a6841ba4462194db0522ae24d4a88e04cc032b +size 43509 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en.png index e1cf8ac4eb..a3d08fe929 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ada067f89b469fccaaf4b9751c0469a9f776ef6206d5ebbb68b7b2128d77ce3c -size 29564 +oid sha256:00948f7166eec146c6e7092b4b9562a12fb1fa5fbacb080256ade04e1d8cc1a8 +size 29385 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_1_en.png index 24793ec7c9..9df4a43aad 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDeleteConfirmationBottomSheet_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f717f0e4ea67364e505e8c756931d11bdb696d7be5f11bb155f085c9f2a668cc -size 42149 +oid sha256:12d4fff60ccddbbc45aa2ee15f7191a761e5b944ba990d0c7ec3d8d579b7c297 +size 41992 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en.png index 8a527331d9..968c84c321 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67be1e8e93d0c10366f4b37f14ca0f90c1f4ccd5da9024c9a396d3d46507e18c -size 40339 +oid sha256:f6bc140ee95f9971e95b1eebdc08cd524310cb9f19b5f392832a9cac42de87ab +size 40369 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_en.png index 8a527331d9..91ede41b24 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67be1e8e93d0c10366f4b37f14ca0f90c1f4ccd5da9024c9a396d3d46507e18c -size 40339 +oid sha256:989b79de2661de014aa33933cf46e3beaa83853f1c4a5869a64aa9569c8f4903 +size 38334 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_en.png index d53b0ecf7e..efa60ac998 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f89a1039bc2d101af319c0b6259d8eebc9d313ae34947aedee525945be23799 -size 44604 +oid sha256:9a11fe51900ac2f82dd134f03cdd070e0d1eea7ef1f857098a719b737c5740c1 +size 44700 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_en.png index 69da701004..08414d12f8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6144f221b9d11c70d15b54321bfbff3d1de1454e6c73be34d7b2e82bd1625a94 -size 30701 +oid sha256:640f57346441f38bb5e46bf0feabfa570cf59b1a68225621a748415b9bd36a75 +size 30587 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_4_en.png new file mode 100644 index 0000000000..3842333bbe --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Day_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b6cf67bf5ed218c3506304ff0062a91e23c95f189dac2bad32540a64e6556b2 +size 40821 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en.png index e16a2bc691..3d848e6a90 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a512016e96b933f6089e60b634fa77f140dfa7de50d3a8c1a62092ad552d7f2d -size 39216 +oid sha256:3d19ed9cd344be378c3ac33cc3efe8708e7803fde0234c524d83bf1a27fc2b71 +size 39320 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_1_en.png index e16a2bc691..843c4ca98c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a512016e96b933f6089e60b634fa77f140dfa7de50d3a8c1a62092ad552d7f2d -size 39216 +oid sha256:99a42e82444e021a1fc6b1fbbc92b525fa47b9134ba6cc1f96a625f9ed71bab1 +size 36958 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_2_en.png index e36f282ba2..fd2043826c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8608e63ef9ff79fd698c202d60a8c73f8874f8610601a0ff6dc85663ed82c7da -size 43537 +oid sha256:0d68ba74c14b13e484ea241ca84c57790504774f305b4201da86074a2ddade7f +size 43594 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_3_en.png index 2534bd5d0c..7dd7e76f03 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2898f00a828a69ce9cdd56994d7878f6aae8c5b2ea5d1150df57aa2ebd7e537b -size 29233 +oid sha256:27e1ee018a732cf5583007910e3fae9301c734a25276131f74150b180ebcd049 +size 29039 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_4_en.png new file mode 100644 index 0000000000..9ade235007 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.details_MediaDetailsBottomSheet_Night_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67331c3aefde56724a506736863330168c3cc847beae6fd1220fae26c569f8c2 +size 39789 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_0_en.png index 48c6bff9ca..d9f1bfbc09 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d81773c99f740992755d35fdeec1720267856c0b201f246cdb4d8442ca4e3063 -size 8301 +oid sha256:de447e1f21d51bd3e21a0fe4de6817c375a408beb8225a6ad5deb85025801e4f +size 8293 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_1_en.png index ab5e7492b0..ca71909e7f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ee522d0d8f87577177bbb2e73382d9736178214c4834508f2e7bbccff6ebd9c -size 13049 +oid sha256:f6c7e6ecb02d33e3849ebd2624dfd1e994d77b9f7f43e7ffe9afcf33e8436d44 +size 13041 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_2_en.png index 421815294d..037395a7f8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69e9035843c450cd0fb45ed0e287ad6ff43fd58c12d6f27687e5f19527079563 -size 35318 +oid sha256:75f5d30bc99d5b09a69b77d544aaafaf665b1c377405f7ccb04092ac0da0a114 +size 35334 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_0_en.png index 3a0c862132..93cbbae2f8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d1ae3ee5e7bddb2efe646024f04e051c37d46b24b12f75d861b0ed585ebe8355 -size 8078 +oid sha256:7b3105694519d42956dc164a04b7642dfff4a303d7b96cfd2967ea3ad1bc19cd +size 8071 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_1_en.png index b902ce98ab..6c89e912be 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8711ab77a43fb6ef26d7ae79bbfbd3d49ae11f4de9d444bfb8beca3b44dd0863 -size 12450 +oid sha256:8fd9f5dfc87d0a6e65e9c10c67f4359abde2ce85265770f8a47e3329f2f64a2d +size 12443 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_2_en.png index 68da14886e..1fb003e7b3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_AudioItemView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d2e1ab9787c7168f6e7f6ebed884e1dcfe45f2304acb241c2fb0d63abc48468 -size 34388 +oid sha256:97f49b6969c5a852624558077f9fc9b0add39a12e76e744a385c85785d4489ec +size 34405 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_0_en.png index 0b6cd8eb47..ca864249bd 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b645f3d06de7fed5673ac1b93df45a9e60ac9cb0829a132e413df9188d01cc38 -size 8937 +oid sha256:31283735c33057ede4d2ba20024b00ae4a4f45510cfbb47c21f980f7151c3858 +size 8931 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_1_en.png index 66625704c3..e4eb34aaac 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4019a4116933dc5fe984eb9be639e8a4196df05ad154a6a2ffc7dce4e3862ef -size 13341 +oid sha256:0a2decb05c73655390dd2cfb3d88d209b17ded46d5d6c40cc8672e5781b48348 +size 13334 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_2_en.png index 5cb7302aa2..d2199b862f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a00cb76be6037667a3c43f708dba216275075c2b835d42e2063320c6267b18b9 -size 35952 +oid sha256:21803c66fce41f53cd7796321fb9f3fc774e0c4fc99cd3683a3a8b22e00e2615 +size 35966 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_0_en.png index ef2fb3f45d..c9a00ed743 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59b12c104b96d9c53d9d2ae4f369e3de2217776939f4dd83092e9488f03c050a -size 8641 +oid sha256:11300a4c85f2e8daa06ddb4a3f8d6f72432dc581dca279366b1229450d3b973c +size 8634 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_1_en.png index 78030e568c..e1090265d0 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f92b128f85e00172b208f8bf0aa03c1160be64771945f488f5754ea0f0c15816 -size 12716 +oid sha256:1c8a1759a613527cfe5912f6e811121e29611ed05b8a8cecb95391ffb1bc5be2 +size 12710 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_2_en.png index 19f3a00321..e73cf16f0c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_FileItemView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b9a57364c3cd404b3564c88b802d73e98f6d9f50728e16ab07a121a658b8d3c -size 34927 +oid sha256:c53798a077d020700ae58aa93aa507dd7ce88984c48aaabf11ba863e8b1773ed +size 34944 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_0_en.png index 3d0bbf58eb..ecb8160d12 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c5b5c9b528a7b425b9181c2ee94024d09bb4c4477f7fe54e1d77c0a08c0d2c48 -size 9287 +oid sha256:2ef97e6e11a66c49ed5ba1863567f24097fe8121ea34f7de5fc5cdda3f0c7a0b +size 9279 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_1_en.png index 7dc0750153..2ee1097de9 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c3fd4ccd645308d061d8315c10a1c1da70a0e33032a50c40d3efe1b558cc9f3 -size 9839 +oid sha256:49bec9adfef9cf1637c722f5c96e0fec677c21a4ea3f89fd4555a9c894090be0 +size 9833 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_2_en.png index 603298db3b..793b579aab 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac9e0112568d7067b7c439d423c6c282ca35889a64fbe34d6f778e935ada9135 -size 9585 +oid sha256:a010f16ec1221a43ba2bd5266da05f3de48d354b98dfc087974ff605d32d095d +size 9576 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_3_en.png index b2012fab3b..08a42124fa 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70dbcc38e6353a77decb7eff90e0b2ee06b2d9f3c92a688efe09da308e5ca1dd -size 9723 +oid sha256:c91316c96e75ba29e3d1bae38cb8b0abf255d7316ff3a616fdbddafc550c744f +size 9715 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_4_en.png index e147449055..7250c6af6e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ccaf6378995747cb914a89da7c4a74a60b43e3dd5e4e4ec4174069b0ab8d814 -size 9828 +oid sha256:0f8945f66443988d9b36084868241079e22e61605f21cad055d8e21e8e063c0c +size 9819 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_0_en.png index 53d0a71144..f6828af0c8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e599734b376ce6c8fe4989903288e2e26c0df2fd27c4f20afe9c5a2f8f33dfa0 -size 8719 +oid sha256:2cc4cb7aca28fba19e6e5d9398ca7d26c9c361298137552789024f84a78a7f70 +size 8713 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_1_en.png index bb8713cf6e..2639fb33e1 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87d86e984ca7238676d5e642b1706894b91f6f12fc19ef5f0545ce6ad34342e2 -size 9344 +oid sha256:48a1a38461c9d2f0bb66878b977673531808eafc0aba53f17beff779a575707e +size 9337 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_2_en.png index aff2001f4a..a68f3fd1af 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb88847548a4c520fe5fa7235161c2e437faf59ade57405447059f3f12590468 -size 9101 +oid sha256:98990600b7b05b8fe64404ef1f463bf5be99f48b90b6d6aab64f799d5b03f737 +size 9095 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_3_en.png index 77fcada22d..de56ab0f99 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a3030f28baeae07c89e784624fd58fad8cb4441deb669fa91d94f847e566700d -size 9200 +oid sha256:c662180e91e10974f7709364a07fa54194df0061425565e08644e731f5922dfa +size 9196 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_4_en.png index b3cbcc11bb..fc138d7153 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemViewPlay_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3fc0c77a58255fa4d5e5c45d3baeeeed7bed667c5d2b1df025b8805b9fd2b5c -size 9318 +oid sha256:5c08ae126aab643824bd431aa4449a855e382e65840ebd980d4849e19ed17152 +size 9310 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_0_en.png index e2cddc5835..eb40570d60 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aafa8d9dc782dd8829e3cc542a0247173b2b1f7f13f0d2083ac276b88e7708e0 -size 9348 +oid sha256:9a3c0e76d07f250735fd75061fb076732180b254d8e8bc145887e0d307272de0 +size 9340 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_1_en.png index f5f65eb855..508eb5b48e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d49c7282b5ec080bafca160e1f257e812ff09ed18852be159dfccc7fc29a5cd5 -size 11663 +oid sha256:08357309dca3a8a3cd8a38f0928522eeefd3a0cdd91990fcc590929e187b162a +size 11676 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_2_en.png index d7df5420c1..3f7c6715b7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae27b73bf52133e75c0685dc584f46c26cddccdf864b01bb242be41bfa589447 -size 36842 +oid sha256:d03f232373aa8cb3f0f6fceeecbd4b1ef86f8703ac6b887683cbfa5c5e5af4e4 +size 36831 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_3_en.png index a6ba59d4d3..2cc97641ec 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26303598b3bdf1a7d977f8d54e9a36810a957d849d4662cd314df5a0f862ce85 -size 7642 +oid sha256:886dff267c22e2ba300b81f13e3071756483c5938e9d1cfb357f633357f5ff06 +size 7634 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_0_en.png index 5982076411..b83e6823b5 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bc8b9d98e0fc0a2ec522c74988e9461e1e5598dd232362d209c7d8c10fd008f -size 8785 +oid sha256:5c11e7b79420af53a8b934b3ad6dbe9c68d8ea5635322389663b55f62160eade +size 8775 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_1_en.png index d87fa0e77d..a0ee911211 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25a37d6659117fc81de7e7131c503089d9091ab25fa408ed4305fda13c926014 -size 10917 +oid sha256:22f76d8fbeaca8d0b986b4ac17a28c16e5f757e2022466200215fca333f69ede +size 10929 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_2_en.png index 5fdc8077a7..6f77d72e3f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4cede06219d43d773b4e1ea81c7c81ee9c28c6e6d002687fd3133f9d7df4b9c0 -size 35125 +oid sha256:73cc7f1b0f8b9bff2b2e6c9a88b833baaeb9f39923c2113a006399c6a877634a +size 35118 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_3_en.png index bc1bf1c7ad..c82f55de11 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery.ui_VoiceItemView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f924b3e7b7471c973719e2d33c3bd10f9bb63a4903df4e9ffcb5c9c1bd7e9ee -size 7249 +oid sha256:d4d538dd90a36eefd2f9c8f8f66847cce6bc17f60e503513bf1890e6b5403d12 +size 7244 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en.png index aa15a1f8f4..be668fb03c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91da9a2b01eccb0451288e153d01d159fe80e1b0b2c5d366d74622af564ecd33 -size 33157 +oid sha256:691c6ffd759b01f216128c1f7d59e7cae76e1f1a83c95a8b89e6f2f55dce3b9c +size 33009 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en.png index 809459297c..968c84c321 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ddbddbf5303bb86f901cdd880ca2fde15c7c4af22dd7cf1a7903dcab5df25b3 -size 40254 +oid sha256:f6bc140ee95f9971e95b1eebdc08cd524310cb9f19b5f392832a9cac42de87ab +size 40369 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en.png index c3f0453d99..341dc6115f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d60dd5ae119c4c020177fe37f54a9a2c8f05ee1b9133d3f04c5eca125bb1f43b -size 31703 +oid sha256:e218343a909a15b66c6c00f46c6bbdd783ad1365aa380ed576a9e66c6dc3c09f +size 31646 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en.png index 1ceb7c6b68..3d848e6a90 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.gallery_MediaGalleryView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:89e17d0b8fdd749b6e97385e8369132d52b0e10adf7d23157c3bdbeb7721e694 -size 39007 +oid sha256:3d19ed9cd344be378c3ac33cc3efe8708e7803fde0234c524d83bf1a27fc2b71 +size 39320 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png index 3c218ccbbc..cdb602aae4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b918ce7162d95c873f0029a657ee07fca2e34926e4c3cdb39eaeb10123a08721 -size 25340 +oid sha256:2c2976543550c63540f3e4533685e342ef5775018a37f5e282bf889e42c199e6 +size 24955 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png index e6925f9f5b..148d707197 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d62cf7beeba92ee47193a871becad07f50d27e6f6fa0b85f6c620c3f1b04b6ce -size 24697 +oid sha256:c8eb14a3df5edff4af450b39224e6af6efce20f0734119835e6fbec210491412 +size 24251 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png index a094305aad..fcf2e1f03a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f520fc8eac5e100bc4e8b0bf0c84e615078dabbdf502411e6dca5a4d579cfcab -size 12255 +oid sha256:71381d66fb321f01d6d874c025681489224626ad9700c0f15fe619f73f1a648e +size 12532 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png new file mode 100644 index 0000000000..779d297fb6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb2ac4d88f51c8c1718a525a5abeccbe2bb19df75a100d504de0cb106ff3117c +size 13857 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_2_en.png new file mode 100644 index 0000000000..e3e7f9da05 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3eea2cd53364f9d0c85b803c8faa29f083f9db59123ba6e980a79bff7779402 +size 14113 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png index 3692cfba78..b7daa3bf21 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:79fd6fba99568650dcbdac47a0ecfda6faa2cd893ded73d5ac4cbf852b59bd63 -size 11889 +oid sha256:d834acd383dfe8da50426e28e267a1076e5634fc2f96e1e7593cb6a05988600f +size 12074 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png new file mode 100644 index 0000000000..f2a9faa5ab --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a14ccc9724a15a7ae3f477a8cda366be345acf10b7a98ce63c4889bc1708844b +size 13379 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_2_en.png new file mode 100644 index 0000000000..bc3991b8ce --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.file_MediaFileView_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26e4aa8610c1dede0d1b637072e773b5c46fef24bc436b9e7444e26f3ba9814c +size 13689 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Day_2_en.png index 511027b648..99b5263e02 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94b71c47da614e247f1c9bbe6df50ae036c5587b964f4df460859927d4807d37 -size 6154 +oid sha256:db3ad4fbd7c140588ed40887455e3ee6b77968ca8682769826f0a447d867ac2f +size 6115 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Night_2_en.png index cf25daf7f0..2c843d2676 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.txt_TextFileContentView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e5d66ac02ac2d39125c26406f70880f2b58f3ffb88569f19b0e5104a03293034 -size 6097 +oid sha256:8b91198bf6f1cc53e13eea6c7092142800760c7103349c37ca931d722a549616 +size 6064 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_en.png index 41e45ad002..c45563c143 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e641d1d6604b6c5f489ab38438d9f3b8dcea9802113011200e9ea589c4e2dbee -size 25310 +oid sha256:5a9b7b0c427f40aa8f0a61025fdcfb8093c611e15ef10f22576545a64c6ec35c +size 25286 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_18_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_18_en.png index b18a209110..db13b64ba8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_18_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_18_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46d390cfe8d41536cea5e90cb38aa547969ae24d82027c02cfb71c4fbc780247 -size 667948 +oid sha256:3a8582605ae13be4b4ee00b5e2156eb4fc939174744bd0ef467bb21eeffe8009 +size 679515 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_19_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_19_en.png index e22d5b8e72..59ad8d4de8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_19_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_19_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0bd4f0133fc3a4a159e3eda1f715e4140464b7c67558c551216546d4688f21bc -size 669143 +oid sha256:f5a5a84faafc58b6315237373a413ddbbaddd9b2495bf842882d20243daf6d50 +size 680730 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_20_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_20_en.png index 1023508292..2f1f448778 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_20_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_20_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:178de2176a3932665897486ecbee622083af2d5939f4f1f7f0bdc4667a61e36a -size 668061 +oid sha256:62493d73c48e90e4bd55142594de567fb1543496c97270fe29086ad7a686557a +size 679273 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_21_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_21_en.png index 9fa3e43792..f71ddb8758 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_21_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_21_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bc974dfc6206f389153477d287a69c401ddc154a529cb892227a743acee8ac50 -size 668212 +oid sha256:5d3b717ce973ff874713b965cfffbd505d939539172002e0f80f6675eb38d9f5 +size 680008 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_22_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_22_en.png index 081ab9a80b..96c74d1427 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_22_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_22_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7ac632f2062aa4a13ee46fd2fef6d9e6be25270f4790247131231163670cbe6 -size 670668 +oid sha256:efe53473954202132a757155217a3a7dd3c06b8f69da4437dd82757fca2110dd +size 682749 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_3_en.png index d122817b15..cc94e583b8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21b8289db279172f042fa902bdbdb70d87104d342a1140357bb1ac2bc18f6590 -size 668482 +oid sha256:d54b2bccd0f5feb6de0051d66310deee7a776b479c8982d634cf2ace2e153d0f +size 679587 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png index 797c1cb2cb..e705db22de 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f72964447f2fa66e8df38fcff4a84ada1cf62e1646a2e8a00c61f8f151abfa8c -size 206507 +oid sha256:54e3011eb38f3c3e21cf64e4a9e0ee4d0c96bc0c2705975ae06dbe7422e03fdb +size 212870 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_en.png index a092bf37ac..3afa92e837 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e23aad00065523bf1ee0e26cd094eb6a9bdd73d65f0bd9cac62cb79e7876481 -size 196533 +oid sha256:515d5a47d530117ff21cb922d1cb2cb81b22d02c083c51bbff69964f92260bbe +size 197095 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_en.png index 619bd4e8c6..d78b959356 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d98ceaeb669342160d04783f07fbb21929d8be46d30181b60e0f09a99abfe79 -size 197127 +oid sha256:b9f402d6f56e6b9eb8d46add584ef28bf88d4a6c16ae050b7773895faafa8d38 +size 197707 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png index 77e9dad534..6ac98e0150 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:094c1de97c33431390f3ff71d73019d9af9a62ed57ba98c94e53f1f9680851fa -size 210728 +oid sha256:2871bd26b6c21d31ca251761eb5a203468406b4d18c13662fa815c53f015b5e1 +size 210297 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png index c3caba08ff..6f49e5ee89 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a17d0f4bc47305b9c8a3866f70cdddb16fcb5ba10c8007c8739a329025e846a -size 211342 +oid sha256:d9dadffc89e0a66b54a0e6b94006f392569e1907dda2c6d0b6134aad187ff84a +size 210913 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_11_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_11_en.png index 1ceb7c6b68..3d848e6a90 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_11_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:89e17d0b8fdd749b6e97385e8369132d52b0e10adf7d23157c3bdbeb7721e694 -size 39007 +oid sha256:3d19ed9cd344be378c3ac33cc3efe8708e7803fde0234c524d83bf1a27fc2b71 +size 39320 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png index 4734e4e6db..430511e490 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b593f6827598052cbde0e580dcd43b92fb098f6755779b95a60bb691d9ad5003 -size 134711 +oid sha256:d298f8dfd834c532f3607ee6d23600ad40b877ccb6fe08a8297ab094a457f20c +size 134789 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_18_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_18_en.png index 057e117409..6788c98af6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_18_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_18_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0487a6dbc3a2f3bfb79a709c782fb692ef93f37607b4483095ce76f08954580e -size 396582 +oid sha256:c9fd18a67499a6a3d9d12dea3fd5bafa45ed2e380fa0658ec0da004e50d7b6c3 +size 398823 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_19_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_19_en.png index bc7a7cc257..86a3fd29f7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_19_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_19_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29833e4103ecf4bd3e1c5da384d3bcc20031073a14261971825e97bc9f1dad23 -size 397593 +oid sha256:47f12ee4d355cda76dbe58bc3d6a6af64e0e076a973073ada1930195bcef0c23 +size 399533 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_20_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_20_en.png index aa8d934627..3ceebdd6fc 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_20_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_20_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b544362587868c37edc424b675c6758e7ffcff359fa12c1cfcb874a0502e25de -size 397284 +oid sha256:f65b6d5297d4c7c4904da07659bc8cdcb866418b787ce7a116b0b7bafef2690c +size 399331 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_21_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_21_en.png index 26758e047f..3c6eb97e1f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_21_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_21_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51e183ca6d518d803471ad4eed0ee932397c32a4c1ffb064714b39f13ea2003f -size 396825 +oid sha256:2b0009b38846b314925ab9a8ff6994fc99e156ada817a8798ba5550bd12eb8de +size 399156 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_22_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_22_en.png index 7f34e6d53c..7f27c3422a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_22_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_22_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b6623e0e784a93d6a3aa220b620efe7d1f9e040aedac7f34d01b24262fe101b -size 401770 +oid sha256:3c4d7f3fdbb0c331ef19f4481ab128b2515e6c7110b40ba2734efc44caa3620f +size 404812 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png index 7d1ba874a3..a737a9e582 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d56f08f1c37575de90a67ebfeadaf1c891c9ac9e4925af7d048922df9fec5aa9 -size 396815 +oid sha256:9343d4b20f7e676ff52f8f48a046d70b8762c6901ea2d6cf254eb6e447397c4a +size 398255 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png index 52f17795bb..f318a0eb96 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e3a148746b4f7428688a634f2b1299f0393bf669a665c94fa9af12d7839e72a0 -size 130834 +oid sha256:e0b66b9b49be0cf623679062eb5d7fc8e0c26523e228522927d26ebdbee9ac4a +size 133376 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png index 31403f8980..3bcf436edd 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9cd21b6d9a9d0a9ef656bf895d6d135ba76160695355ce034fe985991d6955b -size 123949 +oid sha256:9fe5efbf527ef99de18a44e05edb9654b5bc58c17a2fd2d05f57567fbe27ef2c +size 125021 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png index bc0720e4b4..347c05b83f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2dce0794e50116043fde9f6eb76b0c05ca21fc9cee26bde01618024c24c154b2 -size 14952 +oid sha256:203bb59909a9adb94eeb51d63d8199eedee93d2f1d257572e779af9ada9a8980 +size 125404 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png index 932ddfb632..53aafed48f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43ab4873fc5fc812bf18af50cbe620c83b273ee70305b5ea06a7aeabdf8dbc93 -size 137637 +oid sha256:cc65f284ec05a8ed7ea496c49c52afae585f09d26986d8582c00385459823393 +size 136782 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png index 924e24ba8a..b3740e9938 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:33048dafab286cf0e5c84040c034d93a42d69c234edd53132d918a4a1c135ece -size 137908 +oid sha256:039749e7d726be826927bf69a89e3676a3f60ee60a07e8754b4376a08584af0f +size 137077 diff --git a/tests/uitests/src/test/snapshots/images/libraries.qrcode_QrCodeView_en.png b/tests/uitests/src/test/snapshots/images/libraries.qrcode_QrCodeView_en.png index beec069b37..7eef6a2893 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.qrcode_QrCodeView_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.qrcode_QrCodeView_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c07e9a4ec69a889b003bee4293a610c9fe0fd0f83c10c0da01322e076e9c980d -size 10750 +oid sha256:a8cba2cef4b9bfc962783765544df57930f62eea322078a10969487ce08e14be +size 6401 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png index 051db89ece..88c43c729c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d06e84c695086a799c8377bcf48869675b98dcadd1b5320e685d775589ac40c7 -size 30950 +oid sha256:e9dd0c6858e4cd885d05aedfa92797c9aae6d56fb0b60268ed59793524121465 +size 28962 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png index ddde486abc..2e4c86a4c9 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3825e3c312d75a865545745ee00b64d8c2259e515dc45fad64236963e91f2427 -size 28999 +oid sha256:2f2601edb209c898a03dbbca33c963eb0ded0c8f1258f145d743b263e99b8418 +size 26945 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png index 821a37d7c0..4e53ef31de 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b0f7e2b97a343d0e1bedd9595a1057a03a4429c3fa72613451ac86a7146392a -size 33382 +oid sha256:0ec941914c0e4a5d4dfe376a6f13b4330b46eac3fc1c31708ac0122a3e6c1038 +size 31129 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png index c19c6f4fbb..dd7e2b791c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cccff3215bc81e2a6491f3b0da3f4d8997179b54c698f962eb245f535e6cc9fc -size 28655 +oid sha256:e3663eff19bb6c270af51109248836b8ee8da778538406ae2b67d10a56263d05 +size 26639 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_6_en.png new file mode 100644 index 0000000000..57ea66e527 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Day_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6511dac276623acfccbdde7f8b3f79930107b5e386b8e60b3d3f5ec733a41202 +size 30781 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png index 97ff3939e2..5a6fe4a2c0 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b38450dc7cc24e6f9a0db829aa11058d10ae45d433945afd534627534f362554 -size 30261 +oid sha256:014b95f94a6a0c7711146df291fb22a49fde5e98c8584bdb69f3cb4f0b626e36 +size 28375 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png index 1c3dfb9480..28efeca99a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1b36608e269c7572c93c6f10cddeaf42bfeba404c6699a6e050144bc28bc55e -size 28569 +oid sha256:7cf02e53cfcc806cf02c04ecf275abc84265401e2a4e6ce4ebfa64e1c4e0f9d4 +size 26519 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png index c4689af159..5eaab7201a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96f198461d8d60d8610f337c3dbe90bebd8c98f32a4739310532d629ca336a1f -size 33113 +oid sha256:ac935e780ea072953e6e15edb4a845605ca77776d6ad50c5782018ee5dd84d5e +size 31120 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png index 5301142de1..736e9bc843 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12350783e27c09074bdaba2e74ac445b643ff6a13251c13a7cdf98999274325d -size 27915 +oid sha256:52be506a4811614853b5c101907caddaeddde4a9147e0f6ac0a3ce31610a3612 +size 26020 diff --git a/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_6_en.png new file mode 100644 index 0000000000..6c89cccb0c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.roomselect.impl_RoomSelectView_Night_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a05353b7037ed03cdcdcd5821533d9cfd766e02260e9838eac8c7d86fc91e1a +size 30328 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png index d6c10c053a..619a252212 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f108e1a69cf971588cb8d344fe0d908b0f175619f5d81d9fb43946a3a337826e -size 18521 +oid sha256:b18bd93355bca3cbecf9534ae91959204cdd84c399671ce56782c61e8e5c69b6 +size 18443 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png index 6b176577d2..d990287ad7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_CaptionWarningBottomSheet_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5b4897fe30d6fe2174a2272788b29e087ef63ec777886fd5ca556575137060b0 -size 17368 +oid sha256:1aecd66da70fbf9a065a813951e6e434d0191da0b1a4e7bf9b4f466116e8722d +size 17159 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en.png index 5f54605f82..96215547bb 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a9022d63fa2d6f972b94856ceae281a918bddbdb935962bd21088baf126e03c -size 50165 +oid sha256:d1622f9765fda65985a369d6958f7a5993696dd629c0c1013c0a1647cfb7b562 +size 50109 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en.png index 996927c6c1..70d41498a8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_MarkdownTextComposerEdit_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:adf6cbfa0c5a85debf5f271e16c1cd6ea2d8bf092d8a5ff829e624212805e21e -size 48034 +oid sha256:a94de003f65d2fb30ab42e4ac60802707abf1358b0defed7598a3aad69992f40 +size 48136 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png index 40342f172c..c17cbfdb66 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f8c5be5646019061349e6b3a7f358de7a0e2198f132be83cc44ddf5d82ac6da -size 51339 +oid sha256:fdab4bea33337547250355c29991f45c118e8c2c05abdf69b1824475feced5d6 +size 51241 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png index 2156c25e2a..ef9c49d6c5 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerAddCaption_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:734df31d9ad63ff8ce0877daaa7c1036a0a322209d16ff9c9cf544d26676bdf9 -size 49482 +oid sha256:0f92c594febc463911c8418deeff3b94e5a8ce4171461d812a0f4f527ab0cf8e +size 49245 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png index 12323c479d..d5595c72ab 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d52e9f943bbefe5bc763dcd2b460c2e701625d427efc344b53b1ca38854bd8b -size 41761 +oid sha256:74806187f896f73b640c7401d5d0f53ec058ef788cf85d71859367057fa1ec1c +size 41383 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png index 3b24860bec..94f878d9a4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerCaption_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa6e7dae4a224c2911536a5fc956cdee78fb02b0af2549054dc3705c53aff481 -size 39131 +oid sha256:cefac2bbe8799850080d74b48e437320308d5e0c8f6435b113964293ffeedcc9 +size 39145 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png index d29752dfca..9ba3d99527 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d362911049fc57b2a321042c420e36a5685d29957e8da336babd9abac14d50c6 -size 50031 +oid sha256:81d8acdb1158c3e5c19b5a602e3b9afe7643f1bb77d43f51d3f5c4327478a76a +size 50282 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png index 16b16d8f75..969e5b04bf 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditCaption_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:827d8beccea22589652fde2e1b83de48429775301f7d68c43950605b92940fb7 -size 47849 +oid sha256:c225ad12c5a32e2392606f9afacc6dbc37478a141d5485e4942012c6b22ad052 +size 48046 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en.png index f7c45ecf1c..a0192f0890 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c62b0036ff3375f70003b21192a2e8e05871b54c960022bac57066eb390b47a3 -size 60597 +oid sha256:3cfb1d8b7828692d5c318206770f9484822a1749b3e80a618b502811cf512d76 +size 60489 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en.png index 6135707a6d..c745fa256a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEditNotEncrypted_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d393c37651e18449f5f0fdd44fdd9e91d1a2d4fbb6afbd3a92c91dba5c125135 -size 57722 +oid sha256:ca67409e4af247b43d8594d6351419cd12894485357596aff7b26745e2df009a +size 57687 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Day_0_en.png index 728390d025..635e14be9e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c17f3c52a425eb77760c6c3d5f9e18c4dc4f14ca5fb6e4e386d9205df3b4fbb -size 49990 +oid sha256:8b3a91d104a5949dde83ac38b3127afa342816c631a1e29d78e2ada1bcc906bb +size 50150 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Night_0_en.png index b793c0b42f..573b6123ed 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerEdit_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70700bd9b3b3157f75336c7d4b6f56deb462bd30bbcea6ac773c2da5f993df90 -size 47773 +oid sha256:69c281829fbca15261f196d2134f933b789ff444cd7bebc88d05cdbb7553357f +size 48012 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en.png index cfe22711ba..d50fb01949 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6af8b4ecc2845f6cc8ee6c15507852ead9bc76840e35deeeb0f0318ab9f7678e -size 61702 +oid sha256:7af3da131c81a7e76319bfbf757c331dfb342d5c556a8d6eb4234e0779b156d2 +size 61830 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en.png index d96c551efa..4074caa168 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormattingNotEncrypted_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44d1604be0007f4db8585fd40ae56d4a346801c98388c3b69582d32be34cdd7a -size 58533 +oid sha256:023f50c3ecaaf2879d054c3a1bb825adbefbd30c611fe6400a1927180b63f75f +size 58950 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Day_0_en.png index 1764036218..fa1fad9c0e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24debf9cd1db19d5e6245e556d871b9a2a756d6c9e80fd5b45cb930e9a50a394 -size 51429 +oid sha256:e0f8b6bdab8df8b2c1aeb70da681964724e0c2adbe4ba0cc22029de944998291 +size 51221 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Night_0_en.png index f73f125a1a..022b7c0349 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerFormatting_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e9ce65239d7f8cee5ace51d9559ad4433cba28d762bf535228d9c4fe6755eac -size 48818 +oid sha256:112e5cb4d2cd8f5015ab01f2c2011ae8aeb60be274a239e8bad8953d96bd2c2f +size 48537 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en.png index e35f1b24c8..4a6e665500 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08ea9ead35a143a4a14fa6b4185258417466d7d05659ac839c823d80a950a8f6 -size 71689 +oid sha256:ead7c23c723cbaf116629cfc502f4696454a1da1bdcb4aeaac29605d937d2605 +size 71610 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en.png index 892b7a03b0..3ee771684a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa695595ef8f487bf0503648024f4337ac8b39035a79d8c5612c366dd2c8c570 -size 58177 +oid sha256:4e9d1d7021b65b18e7038e6551495b6d391381e85484827c005594fef3a038c7 +size 57984 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en.png index a2bb96eba8..846a262c57 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e6e9f5972f3119468855637eb0ff4e975ffe1a36162bd88485ff34598bed6d5 -size 71258 +oid sha256:68ef756dd45911d9a06f5ceb2ce4917d0d35ed0c9f1b6aa559fccef662672e38 +size 71118 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en.png index b1ef3a5c64..c56359f7e4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36d9ffefb8b575dbdf308b4075511edb2716f1b5d5de7dcb96a0a13dd68d9052 -size 79811 +oid sha256:63eb5bc48de34efb71ffa644e78f18e0596c709f153b35fb6b7aec49dbdaab78 +size 79800 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en.png index 1e939c2803..4551d86254 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27320b5230058ae90d35f681eb46a64fcdb0a83037b2e5ec2fce49a331e4f525 -size 61091 +oid sha256:fe419a00799214722644f17edb94aa4dda3bb7c3b4f19dad689c490bf05d550d +size 60676 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en.png index f4afd108ed..0beaf993fb 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e159e59cc4fbcb7e33b4db5f0b04b486ab7d07426371e288c9bbc2b80c05097c -size 59854 +oid sha256:864b6a01fbcd041a2cb5fee1602fceed5f311a1d73bab6fb7b10a3acf279f47f +size 59579 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en.png index fa92ec10e6..326f3948ed 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db7a7db0cd732c80d03b561ed3061843bdecd23c6f188a7117d3674a62fa15e7 -size 66757 +oid sha256:59a644589a3eb4ef7d791994caf7c6aae6b23a8964405db4d8e9ebba4fc26459 +size 66594 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en.png index eb02cd57a7..f583680c90 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f4d9572d105726c07387f037e65092adcbb8b631d0406eabad30dbc8382383d -size 88343 +oid sha256:7185c0bbb80d40e3da31df878f5127947e5944dcf3ed81b8266342dea94a585d +size 88177 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en.png index d6a380f3a1..2de8f41575 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9dd1cb61ef6b1a6f15d766882f6d748ff8b45c4cb45588ebf8e3787cfac269c -size 59158 +oid sha256:957b3b1896978c725e03d8d8a22afb767fe032b8c10e499a70f0395eface7d12 +size 58909 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en.png index 3ccd6de45d..f97044e8b6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5286b5cea91c0f474d86413a1808129cecbf4a5b5992dee2059ec0cbe6e74ee -size 59207 +oid sha256:faa3cf430f066965686bf11dc9dcedd7a7161e18f6a96be566b8f9be615ee164 +size 58974 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en.png index b4712967f6..a2a9d84eca 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5330b8699041f01a5874c92152f8b6524755d327612d976c7b731ac9def233e2 -size 66344 +oid sha256:f21ce912bf7ec69db5cbb024c09d385cee117e0698b28432a54fb3c330d4b44c +size 66110 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en.png index b9cc103539..cdd4983e85 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65f9224c7c4556477c362fe81057d3fc89fe9043e447d225809dbb66d1895f74 -size 58644 +oid sha256:47521fcbb94b38913cdffa41faef1a0af40289576a892df84fb166b855a77cec +size 58441 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en.png index aed4467033..f89f4b12b7 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ec9a6e9914fcaece7a5fc79a94437a6798a9ef9fe29da301a9b6b199bc90ecc -size 68290 +oid sha256:82904fd6abba5122b5b243e88e58bbf9a5c128128999afb4b536e689f114b967 +size 68610 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en.png index 9499864bec..4ccf9c5917 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a765b2e132737bb0213be31344fea05e60dc46b30b032c0c53b1a7adae59359c -size 55167 +oid sha256:06e63017d3636a943f015652d90089c6ded569930067dd8d6020df4053d98d3c +size 55340 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en.png index e65958a5d4..aebee6a41b 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c26f7171640584447f185263092281a44b25c2cb3cef9e470cd9d10474c1f241 -size 67857 +oid sha256:b4564c1019c830ef0bbed284bd9c8ac8dd1c8082dc76f89e394ae82a1756fa17 +size 68119 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en.png index 533989345d..42f7ea79a3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9bf5ef7638d415bedef349848c03bdcc093e00f391d91c5d528b466ee8117a64 -size 76423 +oid sha256:713af5b3d329a98e75e9587b8b228e1c017a342dc5bc4663df5d0aebf4951637 +size 76948 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en.png index c8636a07f9..7313e32cf0 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc76afb5738bb1cc70ce048a990cb428dce012eebbf503df59439cbd8546dbe4 -size 58006 +oid sha256:0bf814a838410e92a932373b39aa91deb53b18857055770ffa2c1687d6128e37 +size 57989 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en.png index 838a92aeb7..a372614326 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30b9d933c5e1cf1a5f4bc721cf8328b87ea025fae703c239a81a6d68748775d5 -size 56888 +oid sha256:728842933007c366c10e0293a22b0722bf2436c43e3ced69bb78838fef4e4aac +size 56944 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en.png index e9afa6fd69..639cfeee1f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5308541d962b0835476e6443a4dd1af53bebd477ab2f382daefda9121483cff5 -size 63637 +oid sha256:55c8b429bfc0d518cde9b16127adf05fb23a29f70df2572a6212c3f837f36133 +size 63826 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en.png index fe9f9527af..bdf1ea5885 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2325468ef6b2c89b2989d7ce80526cae29eaab3708da4bedcbde0b2c4c2f9dd -size 84835 +oid sha256:bb8e8cf4624d8b6a75db331dd43fb4b51df2723f98eccdc4d87bc1d4df80c3a8 +size 84918 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en.png index 139c44ba12..465d5a5c11 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:451ef300ac8c65887a1caccf643772dd331f59dd1181c97f0b9c53a0ff457f89 -size 56207 +oid sha256:9c3c802c57eeb15b14ab02677a84b422238aa08515b9151d9e01c8aefc0327b5 +size 56322 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en.png index 71a9acd0b1..3ba841381f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bcfaa8bca539371c914e56ed1108282f0e4df826f99527ce982a720f22d2655 -size 56192 +oid sha256:7995253a70c47aca2215d475549c5da8a5ecd6331f8e1d2268df6979cd5fbc01 +size 56276 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en.png index c4f985c80e..ee775246b6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d65864db2aa76e16df454f6772c296ac4cb9efebe2a417560e2b0e8e65503a89 -size 63211 +oid sha256:8b3868e61ecafeb234c4e3438c138ac420192a569949fc8f4f8e4c946ba42f14 +size 63243 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en.png index 6c2e72c7ce..861384a18e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReplyNotEncrypted_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:483daeec8b5d0be508de8f979ace30bdda1ee1c7b3ccb33af0938deacb8f0f40 -size 55673 +oid sha256:1912b608b35257618b42d8abb602f031b67fcbc9810e59e6b20bc86075002b5d +size 55847 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_0_en.png index 2114fe5594..b78d36fdd4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:247d836caf3bed3b89c6a772861d8e302f0b9c5f9c299edd316ad83ce55c8d9e -size 73090 +oid sha256:745714bf11601a9abedc9526d3ddfcbfebc1ed8d73872ebd33f10cc638119c19 +size 72647 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_10_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_10_en.png index bef915901c..5ef7a3ecaa 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3006fc80bef839cb8a2a1ad83f9572b157f0abfe8fd9f170de2c09f882e02d0 -size 56132 +oid sha256:3a55cd98bc72c250706402bfac0706da3adc60a23010ab3a634290f2115f8543 +size 56527 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_11_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_11_en.png index 72e28cbe9d..94488a8118 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3c5de24b62819c74c8183ea8a934e3e463bd2da4d00641341ade7e58b644e61 -size 71496 +oid sha256:5f4ec0a26c52319ec4c0e3468115c977bf3d4be116fa29d5f234758978b518cc +size 70973 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_1_en.png index 5db52bc9c2..31cf97c9c4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b60c12e4345b74815300f992b5c95a54c9ceb4d91e511f13e98e2f2805bfa1f9 -size 82673 +oid sha256:a34d90d08ce5cd10a239c3accb0a92abeeb5309ac73a079700ded09ed1ee1697 +size 82282 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_2_en.png index f01e79ce79..7cb03f9aac 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04dca8661539bd8c9a4afd97f1882415d7c27858b2b489de4f857205543be4fc -size 59397 +oid sha256:3d2c24321d4e7e827aa56ec9715d591b0f47091dab02b13c1dc045a175a70154 +size 59640 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_3_en.png index 3146c25a3d..e008b3ee4e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8adec1a157ed614916988f563391dc817319bb27b10d5b4a3a41da531e9554a0 -size 58466 +oid sha256:c7727ad7b23e98365dbf7b30f2375500cdbff8062d17a1909b166040e07281a0 +size 58638 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_4_en.png index c6fa978c91..ba46e2e270 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bea8196d7650886772d346a013e85307005d9a3f24b5a681a14fc1f218b971e -size 66295 +oid sha256:b514f0f3c246531c3bab262d9b85f60eb737b960c0f1401c0c8d684d75a4f1d9 +size 66694 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_5_en.png index ae98e95d46..0c23280443 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3e535259e6d81f396970531e095453989908e91f4a8ecaf47325430eb86c955 -size 101506 +oid sha256:1a84a52cd5320adfa2bc77781d7d5b996b21a4dcc94d2800c66e636a06f40a40 +size 101578 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_6_en.png index ea8fccf53c..5b5b142b81 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc534ed58d1faf6fbf1f4fdace08e02958e60b54c457436eac2a9c1357b39517 -size 57490 +oid sha256:795ab6fd6386131a124707e96d38a916dca88fa081562cbaef269f6831fc55ca +size 57855 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_7_en.png index 171702f3db..9de8ba3f72 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a56524de1c9f55eb3d6d88342d6d8576508d6145b3fecb8dddc38c598c82a67c -size 57356 +oid sha256:cae668f5a1adfbe42e44ea472dbf7dc5079ec1c3826507859d3e0536766fdb39 +size 57700 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_8_en.png index 882819289b..e7784793c4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c7299aba8e5340b443223858d405f99ab1a4667721b0abbd895713111055116 -size 66570 +oid sha256:4e704bc61a2ae26cfdc30262a4e43122f24faa2a546ae7f16ad15560fc615327 +size 66960 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_9_en.png index b27cfcbcf3..5b56c20157 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4294a5f0c9b943ccf3e9c5ac6f9ecbd574c34cd5334a044342c72cf72f0ef80a -size 56848 +oid sha256:919a9159a4a6b82d65e2f0a59cf55031620f32fe4066aca9440ffdd9f97ccd01 +size 57246 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_0_en.png index 182b04ed36..b18545b512 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2a3c8af39fa40b72e95cc4191f820ab2b2b173e37b99178ff7c06a5870ca2c7 -size 69971 +oid sha256:758cd0c11cb3d951b7c6db787bbaf66dc87252758c6bc9b36e0d1b479fd495e8 +size 69281 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_10_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_10_en.png index 834036c242..6ec2ca88f6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73a1a7607c6273081ef1b866be384fc40b65283cca4f72f701f174d913973c85 -size 52902 +oid sha256:56711e24449f15fa13b6147d1087180bc18f9a873eb0a96d19acfbaae66f74fa +size 53284 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_11_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_11_en.png index e35a7cd447..638136ddda 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5bbbd86cfe40fb6e861a9473f0a63bcbba808d915da99b14f085a27b9428e15 -size 68300 +oid sha256:b598d4cb370923b7aa28287247c08131b773aee20467dd5d3ce95d0506e26ec6 +size 67706 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_1_en.png index 8ca87c0c40..ccab6d1cc6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9610ae365f1cc089b17cb068e66c5f90414364c6bf181c1c7ea2800353a9914 -size 79614 +oid sha256:3d0300a4ba4a025b29e37cf01e29d9cd77ac411fe00642c64a9c14ff80ee4149 +size 79018 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_2_en.png index 45d11dd4ac..c2a4773ab4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:072afde5059b3a90977929811f43402d396ac64debf2cbf17c1f6efd35394b46 -size 56298 +oid sha256:3224a33cd9db2adf69479e8acfbaacaabd0d8ba00d4d862f1b38fc8e360539bf +size 56546 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_3_en.png index 06d1f5c9c3..a01a166e95 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:563e94244304f75a1d64151fdc35e35a9eee2f0c88d4dd4e4872a580adfc434b -size 55392 +oid sha256:a2cbbf5adf4d45fa65aa176b55216f8dff89114ef1a5b4de57bc86a53a22f012 +size 55584 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_4_en.png index b10f296866..d9592ab2d0 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:529ee850c430ea3bd54aac5b0a768cf49dbce44c6629e41ca4a8293e60d993f9 -size 63140 +oid sha256:c49ee949c20152ff3c9ecef1bd361b223fc4eff62a420740d9b708343f5c6121 +size 63442 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_5_en.png index 80fb5cec31..e6f0772abc 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38ab31d94f2252fc5a6bfa720529eaa1d0f9459395e77383cf55b06547ca6117 -size 97622 +oid sha256:46c32f65a5071767b8603f93711f8c3c6150bfc9f6c0f6fd61317aafdebb2e83 +size 97701 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_6_en.png index a83053dfd8..f18f28fa0f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2b367cb2f3d35dce7c038c3358906e32669245537df0e4d6ec33c21ce6c23ff -size 54362 +oid sha256:b2baad13bfc9fd755108365a9b0f7251f60cc8f9bf335115ab5c02b2d0f19f74 +size 54660 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_7_en.png index 478b23ef50..381119052c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57a1fbbce28ef24a5190758b2482622fafda8ec6206b68b8ed632e0e946dda87 -size 54131 +oid sha256:0a735f4a7003f631c230c29e4248d186d86111ada2c4c4cfc8e6e4fe9897b224 +size 54424 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_8_en.png index 93ddb25b2b..16da419a33 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:261747f96fbf93367dae4819a2d4ae8883573cc75af1d6f43cae77f0eaf55736 -size 63307 +oid sha256:c109f03989aaa14873823c230bb262add95099b44031512ee29b9f8c8e7d180f +size 63642 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_9_en.png index d142023a66..dfa1308111 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerReply_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e5786c4a4e98207f229f41a32defb71e059ac3ea9380acacd8883e188c68e81c -size 53735 +oid sha256:bbe7caa3bd8b8788befae4c4febbcd1bb02bd2ea9d6feb00bffb962d0f2885d6 +size 54080 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en.png index 032729bb26..0dfda89690 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a33faaf5ea09a1d4eb3298d135211bbddc6637fd0c435f4df16874a06f184142 -size 53823 +oid sha256:77f29e3b660aafe3093d502c415129fefb08b355c39b2c6f53ddf37107f3041d +size 53424 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en.png index dd156cd2c7..4550c1381e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimpleNotEncrypted_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c83a621b7bd32ab83639acc7471e9a58a2e591b6637fb09bb74c2186791ed61 -size 51273 +oid sha256:305043a2166b60160feeea6ec850050c3709f23a3c6c077851e1b09485dcdd55 +size 51126 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Day_0_en.png index b163b855c4..41291fd5a3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c801a2ffb192267c9ade286bff5640e2fb03002491de90683f27342dcb692f5b -size 43922 +oid sha256:385ad87d0aee7ae8df87eaf8992b347292ae4ec7a0f1e2ee9a64641a03e13b61 +size 43769 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Night_0_en.png index 2ea71b91ae..ea322a5dc3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerSimple_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:33f43f935a457a85584cf682cbaee153128f0a21808caa8f157e542dcb81ef92 -size 41473 +oid sha256:64c015418356283f177cb8d271c97b289170e48d59551a2c20e953247d93c8c4 +size 41623 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png index e5c8277d21..466fc6d023 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b9ed5a39a881471e8b224edbcc45d46a20db0539e065c44a5eb0d56a24efc22 -size 34439 +oid sha256:08f1c0136f60903f2ef4d21aed359ec83235d73a65ea16f3ea0bc4a3e3f8d9e6 +size 34008 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png index 242f4f2874..90a5145263 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:571383a1822fb9cd4eb629d28260556172ff40a8260c9d05278434b2383a11da -size 32594 +oid sha256:94b7df69c90b93737b9eda490814932c00a7c1c441c1cadfc60196b58769200c +size 32222 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png index 72c221feb6..138c59e513 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9036efabbf937551b240326a092f037398ee2a9586203cf1c05a0725200bf3bb -size 24068 +oid sha256:84542c2e193aa926db19d6ec96f2b49e70954c300725d516b11694353239d9cf +size 24153 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png index 2ce6386e00..9f514b6a3e 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ebcd0a5c857202d82a3685551cde4af4abe48883b5b19296188d8130dba295f -size 22622 +oid sha256:72ecb2b3959113e2f86db8cb0c59ad96f1661608b3fcc52b743a6086e31833ef +size 22678 diff --git a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en.png index fd13ba4166..be602ba91f 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:888f6261561d7df42578e39122b152238cfc75537c964fc5bed1d69383bb263f -size 44064 +oid sha256:b8db643953d2fe589896b382a490a36961146bb0693fcbf39c108d3b6706eac1 +size 44063 diff --git a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en.png index e3bf16c7df..d53897b657 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.troubleshoot.impl.history_PushHistoryView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9061f0465a3a62581721d7acb6024b5a5375cd9a9f40b1153a65fa9ce42795d -size 42827 +oid sha256:17bc49574b4f43610c7c8269bd9fce440a2abc3d3396a4dcc62f133decad48b6 +size 42828 diff --git a/tools/localazy/config.json b/tools/localazy/config.json index 64976003d5..93e1c71759 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -317,6 +317,7 @@ "screen_chat_backup_.*", "screen_key_backup_disable_.*", "screen_recovery_key_.*", + "screen\\.custom_recovery_key\\..*", "screen_create_new_recovery_key_.*", "screen_encryption_reset.*", "screen_reset_encryption.*", diff --git a/tools/sdk/build-rust-sdk b/tools/sdk/build-rust-sdk index eddff9f7e4..91c6ed6e02 100755 --- a/tools/sdk/build-rust-sdk +++ b/tools/sdk/build-rust-sdk @@ -27,6 +27,7 @@ set -u buildLocal=0 rustSdkPath="../matrix-rust-sdk/" +kotlinComponentsPath="../matrix-rust-components-kotlin" rustSdkUrl="https://github.com/matrix-org/matrix-rust-sdk.git" rustSdkBranch="main" buildApp=1 @@ -38,6 +39,7 @@ default_arch="${default_arch/arm64/aarch64}" target_arch="${default_arch}" sdkArg="" +update_components=1 ## Argument parsing @@ -48,7 +50,7 @@ else GNU_GETOPT="getopt" fi -TEMP=$("$GNU_GETOPT" -o 'rs:b:at:h' --long 'remote,sdk:,branch:,build-app,target-arch:,help' -- "$@") +TEMP=$("$GNU_GETOPT" -o 'rs:b:at:nh' --long 'remote,sdk:,branch:,build-app,target-arch:,no-update-components,help' -- "$@") if [ $? -ne 0 ]; then echo 'Terminating...' >&2 @@ -85,6 +87,11 @@ while true; do shift 2 continue ;; + '-n'|'--no-update-components') + update_components=0 + shift + continue + ;; '-h'|'--help') cat << END SYNOPSIS @@ -110,6 +117,9 @@ ARGUMENTS -t --target-arch The architecture for which to build the app. Defaults to the architecture of this machine (${default_arch}). + -n --no-update-components + Do not attempt to update matrix-rust-components-kotlin from git. It must already be cloned and up-to-date. + EXAMPLES $0 @@ -194,21 +204,25 @@ cd "${elementPwd}" ## Clone matrix-rust-components-kotlin if needed -if [ ! -d "../matrix-rust-components-kotlin" ]; then - printf "\nFolder ../matrix-rust-components-kotlin does not exist." - printf "Cloning the repository into ../matrix-rust-components-kotlin.\n\n" - git clone \ - https://github.com/matrix-org/matrix-rust-components-kotlin.git \ - ../matrix-rust-components-kotlin +if [ "$update_components" == "1" ]; then + if [ ! -d "${kotlinComponentsPath}" ]; then + printf "\nFolder ${kotlinComponentsPath} does not exist." + printf "Cloning the repository into ${kotlinComponentsPath}.\n\n" + git clone \ + https://github.com/matrix-org/matrix-rust-components-kotlin.git \ + "${kotlinComponentsPath}" + fi + + printf "\n## Resetting ${kotlinComponentsPath} to the latest main...\n\n" + + cd "${kotlinComponentsPath}" + git reset --hard + git checkout main + git pull +else + cd "${kotlinComponentsPath}" fi -printf "\n## Resetting matrix-rust-components-kotlin to the latest main...\n\n" - -cd ../matrix-rust-components-kotlin -git reset --hard -git checkout main -git pull - ## Build the SDK printf "\n## Building the SDK for ${target_arch}...\n\n"