mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-07 11:00:22 +00:00
Merge branch 'develop' into feature/valere/timeline_active_call_rendering
This commit is contained in:
@@ -44,19 +44,19 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Assemble debug APKs
|
- name: Assemble debug APKs
|
||||||
@@ -80,7 +80,7 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
app/build/outputs/apk/gplay/debug/*-universal-debug.apk
|
app/build/outputs/apk/gplay/debug/*-universal-debug.apk
|
||||||
app/build/outputs/apk/fdroid/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
|
id: diawi
|
||||||
# Do not fail the whole build if Diawi upload fails
|
# Do not fail the whole build if Diawi upload fails
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
@@ -56,12 +56,12 @@ jobs:
|
|||||||
- name: Clone submodules
|
- name: Clone submodules
|
||||||
run: git submodule update --init --recursive
|
run: git submodule update --init --recursive
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Assemble debug Gplay Enterprise APK
|
- name: Assemble debug Gplay Enterprise APK
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
# Skip in forks, it doesn't work even with the fallback token
|
# 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' }}
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Add SSH private keys for submodule repositories
|
- name: Add SSH private keys for submodule repositories
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
- run: |
|
- run: |
|
||||||
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||||
- name: Danger
|
- name: Danger
|
||||||
uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5
|
uses: danger/danger-js@e9b58820039524318198d8059ec98b0c02b7875c # 13.0.10
|
||||||
with:
|
with:
|
||||||
args: "--dangerfile ./tools/danger/dangerfile.js"
|
args: "--dangerfile ./tools/danger/dangerfile.js"
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
name: Generate GitHub Pages
|
name: Generate GitHub Pages
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
# Disabled for now, as we don't want to generate GitHub Pages on every push to main anymore
|
||||||
# At 00:00 on every Tuesday UTC
|
# schedule:
|
||||||
- cron: '0 0 * * 2'
|
# # At 00:00 on every Tuesday UTC
|
||||||
|
# - cron: '0 0 * * 2'
|
||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
@@ -18,12 +19,12 @@ jobs:
|
|||||||
- name: ⏬ Checkout with LFS
|
- name: ⏬ Checkout with LFS
|
||||||
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Set up Python 3.12
|
- name: Set up Python 3.12
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ jobs:
|
|||||||
# Skip in forks
|
# Skip in forks
|
||||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
- uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
name: Use JDK 21
|
name: Use JDK 21
|
||||||
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
|
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -38,19 +38,19 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.ref }}
|
ref: ${{ github.ref }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
- uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
name: Use JDK 21
|
name: Use JDK 21
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Assemble debug APK
|
- name: Assemble debug APK
|
||||||
@@ -78,7 +78,7 @@ jobs:
|
|||||||
concurrency:
|
concurrency:
|
||||||
group: maestro-test
|
group: maestro-test
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
|
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ jobs:
|
|||||||
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
|
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
|
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: false
|
cache-read-only: false
|
||||||
|
|
||||||
@@ -76,16 +76,16 @@ jobs:
|
|||||||
name: Dependency analysis
|
name: Dependency analysis
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Dependency analysis
|
- name: Dependency analysis
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Add SSH private keys for submodule repositories
|
- name: Add SSH private keys for submodule repositories
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
name: Search for invalid screenshot files
|
name: Search for invalid screenshot files
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up Python 3.12
|
- name: Set up Python 3.12
|
||||||
@@ -65,16 +65,16 @@ jobs:
|
|||||||
name: Search for invalid dependencies
|
name: Search for invalid dependencies
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Set up Python 3.12
|
- 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) }}
|
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
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# 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' }}
|
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
|
run: git submodule update --init --recursive
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Run Konsist tests
|
- 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) }}
|
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
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# 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' }}
|
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
|
run: git submodule update --init --recursive
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Run compose tests
|
- 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) }}
|
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
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# 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' }}
|
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
|
run: git submodule update --init --recursive
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Build Gplay Debug
|
- 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) }}
|
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
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# 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' }}
|
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
|
run: git submodule update --init --recursive
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Run Detekt
|
- 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) }}
|
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
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# 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' }}
|
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
|
run: git submodule update --init --recursive
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Run Ktlint check
|
- 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) }}
|
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
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
@@ -319,7 +319,7 @@ jobs:
|
|||||||
name: Check shell scripts
|
name: Check shell scripts
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Run shellcheck
|
- name: Run shellcheck
|
||||||
@@ -333,10 +333,10 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
|
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
|
- uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7
|
||||||
|
|
||||||
upload_reports:
|
upload_reports:
|
||||||
name: Project Check Suite
|
name: Project Check Suite
|
||||||
@@ -344,7 +344,7 @@ jobs:
|
|||||||
needs: [konsist, lint, ktlint, detekt]
|
needs: [konsist, lint, ktlint, detekt]
|
||||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
@@ -360,7 +360,7 @@ jobs:
|
|||||||
yarn add danger-plugin-lint-report --dev
|
yarn add danger-plugin-lint-report --dev
|
||||||
- name: Danger lint
|
- name: Danger lint
|
||||||
if: always()
|
if: always()
|
||||||
uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5
|
uses: danger/danger-js@e9b58820039524318198d8059ec98b0c02b7875c # 13.0.10
|
||||||
with:
|
with:
|
||||||
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
|
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -54,13 +54,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: ☕️ Use JDK 21
|
- name: ☕️ Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
# Add gradle cache, this should speed up the process
|
# Add gradle cache, this should speed up the process
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Record screenshots
|
- name: Record screenshots
|
||||||
|
|||||||
@@ -34,16 +34,16 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
- name: Create app bundle
|
- name: Create app bundle
|
||||||
env:
|
env:
|
||||||
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
@@ -71,7 +71,7 @@ jobs:
|
|||||||
group: ${{ format('build-release-main-enterprise-{0}', github.sha) }}
|
group: ${{ format('build-release-main-enterprise-{0}', github.sha) }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Add SSH private keys for submodule repositories
|
- name: Add SSH private keys for submodule repositories
|
||||||
@@ -82,12 +82,12 @@ jobs:
|
|||||||
- name: Clone submodules
|
- name: Clone submodules
|
||||||
run: git submodule update --init --recursive
|
run: git submodule update --init --recursive
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
- name: Create Enterprise app bundle
|
- name: Create Enterprise app bundle
|
||||||
env:
|
env:
|
||||||
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
@@ -122,16 +122,16 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
- name: Create APKs
|
- name: Create APKs
|
||||||
env:
|
env:
|
||||||
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
|||||||
@@ -38,19 +38,19 @@ jobs:
|
|||||||
docker-images: true
|
docker-images: true
|
||||||
swap-storage: false
|
swap-storage: false
|
||||||
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Build debug code and test fixtures
|
- name: Build debug code and test fixtures
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ jobs:
|
|||||||
# Skip in forks
|
# Skip in forks
|
||||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Use JDK 21
|
- name: Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
- name: Set up Python 3.12
|
- name: Set up Python 3.12
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
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.
|
# No concurrency required, runs every time on a schedule.
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up Python 3.12
|
- name: Set up Python 3.12
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ jobs:
|
|||||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
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
|
run: git submodule update --init --recursive
|
||||||
- name: ☕️ Use JDK 21
|
- name: ☕️ Use JDK 21
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
- name: Configure gradle
|
- name: Configure gradle
|
||||||
uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
|
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
|
||||||
|
|||||||
+79
@@ -1,3 +1,82 @@
|
|||||||
|
Changes in Element X v26.07.0
|
||||||
|
=============================
|
||||||
|
|
||||||
|
<!-- Release notes generated using configuration in .github/release.yml at 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
|
||||||
|
=============================
|
||||||
|
|
||||||
|
<!-- Release notes generated using configuration in .github/release.yml at 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
|
Changes in Element X v26.06.3
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import extension.buildConfigFieldStr
|
|||||||
import extension.locales
|
import extension.locales
|
||||||
import extension.setupDependencyInjection
|
import extension.setupDependencyInjection
|
||||||
import extension.testCommonDependencies
|
import extension.testCommonDependencies
|
||||||
|
import org.sonarqube.gradle.SonarResolverTask
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
@@ -245,6 +246,11 @@ androidComponents {
|
|||||||
configureLicensesTasks(reportingExtension)
|
configureLicensesTasks(reportingExtension)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure the SonarQube plugin to wait for the resource generation tasks to complete before running the analysis.
|
||||||
|
tasks.withType<SonarResolverTask>().configureEach {
|
||||||
|
dependsOn("generateGplayDebugResValues", "generateGplayDebugAndroidTestResValues")
|
||||||
|
}
|
||||||
|
|
||||||
setupDependencyInjection()
|
setupDependencyInjection()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
@@ -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.libraries.matrix.test.A_THREAD_ID
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import io.element.android.x.MainActivity
|
import io.element.android.x.MainActivity
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
import org.robolectric.RuntimeEnvironment
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
class DefaultIntentProviderTest : RobolectricTest() {
|
||||||
class DefaultIntentProviderTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `test getViewRoomIntent with data`() {
|
fun `test getViewRoomIntent with data`() {
|
||||||
val deepLinkCreator = lambdaRecorder<SessionId, RoomId?, ThreadId?, EventId?, String> { _, _, _, _ -> "deepLinkCreatorResult" }
|
val deepLinkCreator = lambdaRecorder<SessionId, RoomId?, ThreadId?, EventId?, String> { _, _, _, _ -> "deepLinkCreatorResult" }
|
||||||
|
|||||||
@@ -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.api.ActiveRoomsHolder
|
||||||
import io.element.android.services.appnavstate.test.FakeActiveRoomsHolder
|
import io.element.android.services.appnavstate.test.FakeActiveRoomsHolder
|
||||||
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
|
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.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
class JoinedRoomLoadedFlowNodeTest : RobolectricTest() {
|
||||||
class JoinedRoomLoadedFlowNodeTest {
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||||
|
|
||||||
|
|||||||
@@ -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.api.OAuthAction
|
||||||
import io.element.android.libraries.oauth.test.FakeOAuthIntentResolver
|
import io.element.android.libraries.oauth.test.FakeOAuthIntentResolver
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
import org.robolectric.RuntimeEnvironment
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
class IntentResolverTest : RobolectricTest() {
|
||||||
class IntentResolverTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `resolve launcher intent should return null`() {
|
fun `resolve launcher intent should return null`() {
|
||||||
val sut = createIntentResolver()
|
val sut = createIntentResolver()
|
||||||
|
|||||||
+1
-1
Submodule enterprise updated: 283c6f1a08...bc38a11f95
@@ -0,0 +1,2 @@
|
|||||||
|
Main changes in this version: bug fixes and improvements.
|
||||||
|
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Main changes in this version: bug fixes and improvements.
|
||||||
|
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||||
+6
-7
@@ -31,12 +31,12 @@ import io.element.android.compound.tokens.generated.CompoundIcons
|
|||||||
import io.element.android.features.analytics.api.AnalyticsOptInEvents
|
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.ButtonColumnMolecule
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
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.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
import io.element.android.libraries.designsystem.components.BigIcon
|
||||||
import io.element.android.libraries.designsystem.components.ClickableLinkText
|
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.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
|
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
|
||||||
@@ -129,22 +129,21 @@ private fun AnalyticsOptInContent() {
|
|||||||
verticalBias = -0.4f
|
verticalBias = -0.4f
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
InfoListOrganism(
|
VisualList(
|
||||||
items = persistentListOf(
|
items = persistentListOf(
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = stringResource(id = R.string.screen_analytics_prompt_data_usage),
|
message = stringResource(id = R.string.screen_analytics_prompt_data_usage),
|
||||||
iconVector = CompoundIcons.CheckCircle(),
|
iconVector = CompoundIcons.CheckCircle(),
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = stringResource(id = R.string.screen_analytics_prompt_third_party_sharing),
|
message = stringResource(id = R.string.screen_analytics_prompt_third_party_sharing),
|
||||||
iconVector = CompoundIcons.CheckCircle(),
|
iconVector = CompoundIcons.CheckCircle(),
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = stringResource(id = R.string.screen_analytics_prompt_settings),
|
message = stringResource(id = R.string.screen_analytics_prompt_settings),
|
||||||
iconVector = CompoundIcons.CheckCircle(),
|
iconVector = CompoundIcons.CheckCircle(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
textStyle = ElementTheme.typography.fontBodyLgMedium,
|
|
||||||
iconTint = ElementTheme.colors.iconSuccessPrimary,
|
iconTint = ElementTheme.colors.iconSuccessPrimary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-11
@@ -36,10 +36,10 @@ import io.element.android.features.announcement.impl.AnnouncementState
|
|||||||
import io.element.android.features.announcement.impl.AnnouncementStateProvider
|
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.ButtonColumnMolecule
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
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.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
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.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
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.Button
|
||||||
@@ -134,11 +134,9 @@ private fun FullscreenAnnouncementContent(
|
|||||||
Column(
|
Column(
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
InfoListOrganism(
|
VisualList(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
items = announcement.items(),
|
items = announcement.items(),
|
||||||
textStyle = ElementTheme.typography.fontBodyLgMedium,
|
|
||||||
iconTint = ElementTheme.colors.iconSecondary,
|
|
||||||
iconSize = 24.dp
|
iconSize = 24.dp
|
||||||
)
|
)
|
||||||
announcement.notice()?.let { notice ->
|
announcement.notice()?.let { notice ->
|
||||||
@@ -186,25 +184,25 @@ private fun Announcement.Fullscreen.icon() = when (this) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Announcement.Fullscreen.items(): ImmutableList<InfoListItem> = when (this) {
|
private fun Announcement.Fullscreen.items(): ImmutableList<VisualListItemData> = when (this) {
|
||||||
Announcement.Fullscreen.Space -> persistentListOf(
|
Announcement.Fullscreen.Space -> persistentListOf(
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = "View spaces you\'ve created or joined",
|
message = "View spaces you\'ve created or joined",
|
||||||
iconVector = CompoundIcons.VisibilityOn(),
|
iconVector = CompoundIcons.VisibilityOn(),
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = "Accept or decline invites to spaces",
|
message = "Accept or decline invites to spaces",
|
||||||
iconVector = CompoundIcons.Email(),
|
iconVector = CompoundIcons.Email(),
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = "Discover any rooms you can join in your spaces",
|
message = "Discover any rooms you can join in your spaces",
|
||||||
iconVector = CompoundIcons.Search(),
|
iconVector = CompoundIcons.Search(),
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = "Join public spaces",
|
message = "Join public spaces",
|
||||||
iconVector = CompoundIcons.Explore(),
|
iconVector = CompoundIcons.Explore(),
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = "Leave any spaces you’ve joined",
|
message = "Leave any spaces you’ve joined",
|
||||||
iconVector = CompoundIcons.Leave(),
|
iconVector = CompoundIcons.Leave(),
|
||||||
),
|
),
|
||||||
|
|||||||
+2
-4
@@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.api.Announcement
|
||||||
import io.element.android.features.announcement.impl.AnnouncementEvent
|
import io.element.android.features.announcement.impl.AnnouncementEvent
|
||||||
import io.element.android.features.announcement.impl.AnnouncementState
|
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.EventsRecorder
|
||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class FullscreenAnnouncementViewTest : RobolectricTest() {
|
||||||
class FullscreenAnnouncementViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on back sends a AnnouncementEvent`() = runAndroidComposeUiTest {
|
fun `clicking on back sends a AnnouncementEvent`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<AnnouncementEvent>()
|
val eventsRecorder = EventsRecorder<AnnouncementEvent>()
|
||||||
|
|||||||
+1
-3
@@ -207,7 +207,6 @@ class WebViewAudioManager(
|
|||||||
}
|
}
|
||||||
|
|
||||||
audioManager.mode = AudioManager.MODE_NORMAL
|
audioManager.mode = AudioManager.MODE_NORMAL
|
||||||
|
|
||||||
if (!hasRegisteredCallbacks) {
|
if (!hasRegisteredCallbacks) {
|
||||||
Timber.w("Audio: tried to disable webview in-call audio mode without registering callbacks")
|
Timber.w("Audio: tried to disable webview in-call audio mode without registering callbacks")
|
||||||
return
|
return
|
||||||
@@ -342,6 +341,7 @@ class WebViewAudioManager(
|
|||||||
} else {
|
} else {
|
||||||
// On Android 11 and lower, we don't have the concept of communication devices
|
// 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
|
// We have to call the right methods based on the device type
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
if (device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO && disableBluetoothAudioDevices) {
|
if (device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO && disableBluetoothAudioDevices) {
|
||||||
Timber.w("Bluetooth audio devices are disabled on this Android version")
|
Timber.w("Bluetooth audio devices are disabled on this Android version")
|
||||||
@@ -350,11 +350,9 @@ class WebViewAudioManager(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setAudioEnabled(true)
|
setAudioEnabled(true)
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
isSpeakerphoneOn = device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
|
isSpeakerphoneOn = device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
|
||||||
isBluetoothScoOn = device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO
|
isBluetoothScoOn = device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
isSpeakerphoneOn = false
|
isSpeakerphoneOn = false
|
||||||
isBluetoothScoOn = false
|
isBluetoothScoOn = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="call_foreground_service_channel_title_android">"通话进行中"</string>
|
<string name="call_foreground_service_channel_title_android">"正在进行的通话"</string>
|
||||||
<string name="call_foreground_service_message_android">"点击以返回通话"</string>
|
<string name="call_foreground_service_message_android">"点击以返回通话"</string>
|
||||||
<string name="call_foreground_service_title_android">"☎️ 通话中"</string>
|
<string name="call_foreground_service_title_android">"☎️ 通话中"</string>
|
||||||
<string name="call_invalid_audio_device_bluetooth_devices_disabled">"Element Call 不支持在此 Android 版本中使用蓝牙音频设备。请选择其它音频设备。"</string>
|
<string name="call_invalid_audio_device_bluetooth_devices_disabled">"Element Call 不支持在此 Android 版本中使用蓝牙音频设备。请选择其它音频设备。"</string>
|
||||||
|
|||||||
+2
-4
@@ -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_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
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.lambda.lambdaRecorder
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.advanceTimeBy
|
import kotlinx.coroutines.test.advanceTimeBy
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
import org.robolectric.RuntimeEnvironment
|
||||||
import org.robolectric.Shadows.shadowOf
|
import org.robolectric.Shadows.shadowOf
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
class DefaultElementCallEntryPointTest : RobolectricTest() {
|
||||||
class DefaultElementCallEntryPointTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `startCall - starts ElementCallActivity setup with the needed extras`() = runTest {
|
fun `startCall - starts ElementCallActivity setup with the needed extras`() = runTest {
|
||||||
val entryPoint = createEntryPoint()
|
val entryPoint = createEntryPoint()
|
||||||
|
|||||||
+2
-4
@@ -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.matrix.ui.media.test.FakeImageLoaderHolder
|
||||||
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
class RingingCallNotificationCreatorTest : RobolectricTest() {
|
||||||
class RingingCallNotificationCreatorTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `createNotification - with no associated MatrixClient does nothing`() = runTest {
|
fun `createNotification - with no associated MatrixClient does nothing`() = runTest {
|
||||||
val notificationCreator = createRingingCallNotificationCreator(
|
val notificationCreator = createRingingCallNotificationCreator(
|
||||||
|
|||||||
+2
-4
@@ -15,7 +15,6 @@ import androidx.compose.ui.platform.LocalInspectionMode
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.PictureInPictureEvent
|
||||||
import io.element.android.features.call.impl.pip.PictureInPictureState
|
import io.element.android.features.call.impl.pip.PictureInPictureState
|
||||||
import io.element.android.features.call.impl.pip.aPictureInPictureState
|
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.features.call.impl.ui.aCallScreenState
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.robolectric.annotation.Implementation
|
import org.robolectric.annotation.Implementation
|
||||||
import org.robolectric.annotation.Implements
|
import org.robolectric.annotation.Implements
|
||||||
@@ -36,8 +35,7 @@ import org.robolectric.annotation.Resetter
|
|||||||
import org.robolectric.shadows.ShadowWebView
|
import org.robolectric.shadows.ShadowWebView
|
||||||
|
|
||||||
@OptIn(ExperimentalTestApi::class)
|
@OptIn(ExperimentalTestApi::class)
|
||||||
@RunWith(AndroidJUnit4::class)
|
class CallScreenViewTest : RobolectricTest() {
|
||||||
class CallScreenViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `pressing back key triggers hangup when no web view is available and pip is unsupported`() = runAndroidComposeUiTest {
|
fun `pressing back key triggers hangup when no web view is available and pip is unsupported`() = runAndroidComposeUiTest {
|
||||||
val callEvents = EventsRecorder<CallScreenEvent>()
|
val callEvents = EventsRecorder<CallScreenEvent>()
|
||||||
|
|||||||
+2
-4
@@ -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.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
import io.element.android.tests.testutils.plantTestTimber
|
import io.element.android.tests.testutils.plantTestTimber
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
@@ -54,12 +55,9 @@ import kotlinx.coroutines.test.advanceTimeBy
|
|||||||
import kotlinx.coroutines.test.runCurrent
|
import kotlinx.coroutines.test.runCurrent
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.Shadows.shadowOf
|
import org.robolectric.Shadows.shadowOf
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
class DefaultActiveCallManagerTest : RobolectricTest() {
|
||||||
class DefaultActiveCallManagerTest {
|
|
||||||
private val notificationId = NotificationIdProvider.getForegroundServiceNotificationId(ForegroundServiceType.INCOMING_CALL)
|
private val notificationId = NotificationIdProvider.getForegroundServiceNotificationId(ForegroundServiceType.INCOMING_CALL)
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
plugins {
|
||||||
|
id("io.element.android-compose-library")
|
||||||
|
id("kotlin-parcelize")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "io.element.android.features.contentscanner.api"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(projects.libraries.core)
|
||||||
|
implementation(projects.libraries.architecture)
|
||||||
|
implementation(projects.libraries.matrix.api)
|
||||||
|
implementation(projects.libraries.matrixui)
|
||||||
|
implementation(projects.libraries.designsystem)
|
||||||
|
|
||||||
|
testImplementation(libs.test.junit)
|
||||||
|
testImplementation(libs.coroutines.test)
|
||||||
|
testImplementation(libs.molecule.runtime)
|
||||||
|
testImplementation(libs.test.truth)
|
||||||
|
testImplementation(libs.test.turbine)
|
||||||
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import extension.setupDependencyInjection
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("io.element.android-compose-library")
|
||||||
|
id("kotlin-parcelize")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "io.element.android.features.contentscanner.impl"
|
||||||
|
}
|
||||||
|
|
||||||
|
setupDependencyInjection()
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(projects.features.contentscanner.api)
|
||||||
|
implementation(projects.libraries.core)
|
||||||
|
implementation(projects.libraries.architecture)
|
||||||
|
implementation(projects.libraries.matrix.api)
|
||||||
|
implementation(projects.libraries.matrixui)
|
||||||
|
implementation(projects.libraries.designsystem)
|
||||||
|
|
||||||
|
testImplementation(libs.test.junit)
|
||||||
|
testImplementation(libs.coroutines.test)
|
||||||
|
testImplementation(libs.molecule.runtime)
|
||||||
|
testImplementation(libs.test.truth)
|
||||||
|
testImplementation(libs.test.turbine)
|
||||||
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
}
|
||||||
+5
-4
@@ -11,7 +11,8 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
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.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -85,9 +86,9 @@ internal fun SelectParentSpaceOptions(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (displaySelectSpaceBottomSheet) {
|
if (displaySelectSpaceBottomSheet) {
|
||||||
val sheetState = rememberModalBottomSheetState(
|
val sheetState = rememberBottomSheetState(
|
||||||
skipPartiallyExpanded = true,
|
initialValue = SheetValue.Hidden,
|
||||||
confirmValueChange = { true },
|
enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded),
|
||||||
)
|
)
|
||||||
ModalBottomSheet(
|
ModalBottomSheet(
|
||||||
sheetState = sheetState,
|
sheetState = sheetState,
|
||||||
|
|||||||
@@ -31,6 +31,6 @@
|
|||||||
<string name="screen_create_room_space_selection_no_space_option">"Не додавати до простору"</string>
|
<string name="screen_create_room_space_selection_no_space_option">"Не додавати до простору"</string>
|
||||||
<string name="screen_create_room_space_selection_no_space_title">"Головна"</string>
|
<string name="screen_create_room_space_selection_no_space_title">"Головна"</string>
|
||||||
<string name="screen_create_room_space_selection_sheet_title">"Додати до простору"</string>
|
<string name="screen_create_room_space_selection_sheet_title">"Додати до простору"</string>
|
||||||
<string name="screen_create_room_topic_label">"Тема (необов\'язково)"</string>
|
<string name="screen_create_room_topic_label">"Тематика обговорень (необов’язково)"</string>
|
||||||
<string name="screen_create_room_topic_placeholder">"Додати опис…"</string>
|
<string name="screen_create_room_topic_placeholder">"Додати опис…"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
+2
-4
@@ -56,6 +56,7 @@ import io.element.android.services.analytics.api.AnalyticsService
|
|||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
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.element.android.tests.testutils.test
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
@@ -66,8 +67,6 @@ import kotlinx.coroutines.test.advanceUntilIdle
|
|||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Optional
|
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_CAMERA_2 = "content://uri_from_camera_2"
|
||||||
private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery"
|
private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery"
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
class ConfigureRoomPresenterTest : RobolectricTest() {
|
||||||
class ConfigureRoomPresenterTest {
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val warmUpRule = WarmUpRule()
|
val warmUpRule = WarmUpRule()
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -48,11 +48,11 @@ import io.element.android.compound.tokens.generated.CompoundIcons
|
|||||||
import io.element.android.features.deactivation.impl.R
|
import io.element.android.features.deactivation.impl.R
|
||||||
import io.element.android.features.logout.impl.ui.AccountDeactivationActionDialog
|
import io.element.android.features.logout.impl.ui.AccountDeactivationActionDialog
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
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.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
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.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.modifiers.onTabOrEnterKeyFocusNext
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
@@ -175,9 +175,9 @@ private fun Content(
|
|||||||
style = ElementTheme.typography.fontBodyMdRegular,
|
style = ElementTheme.typography.fontBodyMdRegular,
|
||||||
color = ElementTheme.colors.textSecondary,
|
color = ElementTheme.colors.textSecondary,
|
||||||
)
|
)
|
||||||
InfoListOrganism(
|
VisualList(
|
||||||
items = persistentListOf(
|
items = persistentListOf(
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = buildAnnotatedStringWithStyledPart(
|
message = buildAnnotatedStringWithStyledPart(
|
||||||
R.string.screen_deactivate_account_list_item_1,
|
R.string.screen_deactivate_account_list_item_1,
|
||||||
R.string.screen_deactivate_account_list_item_1_bold_part,
|
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),
|
message = stringResource(R.string.screen_deactivate_account_list_item_2),
|
||||||
iconComposable = {
|
iconComposable = {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -205,7 +205,7 @@ private fun Content(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = stringResource(R.string.screen_deactivate_account_list_item_3),
|
message = stringResource(R.string.screen_deactivate_account_list_item_3),
|
||||||
iconComposable = {
|
iconComposable = {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -216,7 +216,7 @@ private fun Content(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
InfoListItem(
|
VisualListItemData(
|
||||||
message = stringResource(R.string.screen_deactivate_account_list_item_4),
|
message = stringResource(R.string.screen_deactivate_account_list_item_4),
|
||||||
iconComposable = {
|
iconComposable = {
|
||||||
Icon(
|
Icon(
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_deactivate_account_confirmation_dialog_content">"Будь ласка, підтвердіть, що ви хочете деактивувати свій обліковий запис. Ця дія не може бути скасована."</string>
|
<string name="screen_deactivate_account_confirmation_dialog_content">"Підтвердьте, що хочете видалити свій обліковий запис. Цю дію неможливо скасувати."</string>
|
||||||
<string name="screen_deactivate_account_delete_all_messages">"Видалити всі мої повідомлення"</string>
|
<string name="screen_deactivate_account_delete_all_messages">"Видалити всі мої повідомлення"</string>
|
||||||
<string name="screen_deactivate_account_delete_all_messages_notice">"Попередження: майбутні користувачі можуть бачити неповні розмови."</string>
|
<string name="screen_deactivate_account_delete_all_messages_notice">"Попередження: майбутні користувачі можуть бачити неповні розмови."</string>
|
||||||
<string name="screen_deactivate_account_description">"Деактивація вашого облікового запису%1$s , це буде:"</string>
|
<string name="screen_deactivate_account_description">"Видалення вашого облікового запису %1$s призведе до:"</string>
|
||||||
<string name="screen_deactivate_account_description_bold_part">"незворотні"</string>
|
<string name="screen_deactivate_account_description_bold_part">"незворотні"</string>
|
||||||
<string name="screen_deactivate_account_list_item_1">"%1$sваш обліковий запис (ви не можете знову увійти, а ваш ідентифікатор не може бути використаний повторно)."</string>
|
<string name="screen_deactivate_account_list_item_1">"%1$sваш обліковий запис (ви не можете знову увійти, а ваш ідентифікатор не може бути використаний повторно)."</string>
|
||||||
<string name="screen_deactivate_account_list_item_1_bold_part">"Назавжди відключити"</string>
|
<string name="screen_deactivate_account_list_item_1_bold_part">"Назавжди відключити"</string>
|
||||||
<string name="screen_deactivate_account_list_item_2">"Видалити вас з усіх чатів."</string>
|
<string name="screen_deactivate_account_list_item_2">"Вилучити вас з усіх бесід."</string>
|
||||||
<string name="screen_deactivate_account_list_item_3">"Видаліть інформацію свого облікового запису з нашого сервера ідентифікації."</string>
|
<string name="screen_deactivate_account_list_item_3">"Видаліть інформацію свого облікового запису з нашого сервера ідентифікації."</string>
|
||||||
<string name="screen_deactivate_account_list_item_4">"Ваші повідомлення залишатимуться видимими для зареєстрованих користувачів, але недоступними для нових або незареєстрованих користувачів, якщо ви вирішите їх видалити."</string>
|
<string name="screen_deactivate_account_list_item_4">"Ваші повідомлення залишатимуться видимими для зареєстрованих користувачів, але недоступними для нових або незареєстрованих користувачів, якщо ви вирішите їх видалити."</string>
|
||||||
<string name="screen_deactivate_account_title">"Відключити обліковий запис"</string>
|
<string name="screen_deactivate_account_title">"Видалити обліковий запис"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
+2
-4
@@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi
|
|||||||
import androidx.compose.ui.test.onNodeWithTag
|
import androidx.compose.ui.test.onNodeWithTag
|
||||||
import androidx.compose.ui.test.performTextInput
|
import androidx.compose.ui.test.performTextInput
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.features.deactivation.impl.R
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
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.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
import io.element.android.tests.testutils.pressTag
|
import io.element.android.tests.testutils.pressTag
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class AccountDeactivationViewTest : RobolectricTest() {
|
||||||
class AccountDeactivationViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest {
|
fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>(expectEvents = false)
|
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>(expectEvents = false)
|
||||||
|
|||||||
+2
-4
@@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
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.EventsRecorder
|
||||||
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
||||||
import io.element.android.tests.testutils.pressTag
|
import io.element.android.tests.testutils.pressTag
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class ForwardMessagesViewTest : RobolectricTest() {
|
||||||
class ForwardMessagesViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `cancel error emits the expected event`() = runAndroidComposeUiTest {
|
fun `cancel error emits the expected event`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<ForwardMessagesEvents>()
|
val eventsRecorder = EventsRecorder<ForwardMessagesEvents>()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_identity_confirmation_cannot_confirm">"Tidak dapat mengonfirmasi?"</string>
|
<string name="screen_identity_confirmation_cannot_confirm">"Tidak dapat mengonfirmasi?"</string>
|
||||||
<string name="screen_identity_confirmation_create_new_recovery_key">"Buat kunci pemulihan baru"</string>
|
<string name="screen_identity_confirmation_create_new_recovery_key">"Buat kunci pemulihan baru"</string>
|
||||||
<string name="screen_identity_confirmation_subtitle">"Verifikasi perangkat ini untuk menyiapkan perpesanan aman."</string>
|
<string name="screen_identity_confirmation_subtitle">"Pilih cara verifikasi untuk mengatur pengiriman pesan yang aman."</string>
|
||||||
<string name="screen_identity_confirmation_title">"Konfirmasi bahwa ini Anda"</string>
|
<string name="screen_identity_confirmation_title">"Konfirmasi bahwa ini Anda"</string>
|
||||||
<string name="screen_identity_confirmation_use_another_device">"Gunakan perangkat lain"</string>
|
<string name="screen_identity_confirmation_use_another_device">"Gunakan perangkat lain"</string>
|
||||||
<string name="screen_identity_confirmation_use_recovery_key">"Gunakan kunci pemulihan"</string>
|
<string name="screen_identity_confirmation_use_recovery_key">"Gunakan kunci pemulihan"</string>
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_identity_confirmation_cannot_confirm">"Не можете підтвердити?"</string>
|
<string name="screen_identity_confirmation_cannot_confirm">"Не можете підтвердити?"</string>
|
||||||
<string name="screen_identity_confirmation_create_new_recovery_key">"Створити новий ключ відновлення"</string>
|
<string name="screen_identity_confirmation_create_new_recovery_key">"Створити новий ключ відновлення"</string>
|
||||||
<string name="screen_identity_confirmation_subtitle">"Верифікуйте цей пристрій, щоб налаштувати безпечний обмін повідомленнями."</string>
|
<string name="screen_identity_confirmation_subtitle">"Виберіть спосіб звіряння, щоб налаштувати безпечний обмін повідомленнями."</string>
|
||||||
<string name="screen_identity_confirmation_title">"Підтвердьте, що це ви"</string>
|
<string name="screen_identity_confirmation_title">"Підтвердьте свою цифрову ідентичність"</string>
|
||||||
<string name="screen_identity_confirmation_use_another_device">"Використовуйте інший пристрій"</string>
|
<string name="screen_identity_confirmation_use_another_device">"Використовуйте інший пристрій"</string>
|
||||||
<string name="screen_identity_confirmation_use_recovery_key">"Використовуйте ключ відновлення"</string>
|
<string name="screen_identity_confirmation_use_recovery_key">"Використовуйте ключ відновлення"</string>
|
||||||
<string name="screen_identity_confirmed_subtitle">"Тепер ви можете безпечно читати або надсилати повідомлення, і кожен, з ким ви спілкуєтесь, також може довіряти цьому пристрою."</string>
|
<string name="screen_identity_confirmed_subtitle">"Тепер ви можете безпечно читати або надсилати повідомлення, і кожен, з ким ви спілкуєтесь, також може довіряти цьому пристрою."</string>
|
||||||
<string name="screen_identity_confirmed_title">"Пристрій перевірено"</string>
|
<string name="screen_identity_confirmed_title">"Пристрій звірено"</string>
|
||||||
<string name="screen_identity_use_another_device">"Використовуйте інший пристрій"</string>
|
<string name="screen_identity_use_another_device">"Використовуйте інший пристрій"</string>
|
||||||
<string name="screen_identity_waiting_on_other_device">"Чекає на інше пристрій…"</string>
|
<string name="screen_identity_waiting_on_other_device">"Чекає на інше пристрій…"</string>
|
||||||
<string name="screen_notification_optin_subtitle">"Ви можете змінити свої налаштування пізніше."</string>
|
<string name="screen_notification_optin_subtitle">"Ви можете змінити свої налаштування пізніше."</string>
|
||||||
|
|||||||
+2
-4
@@ -14,19 +14,17 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.features.ftue.impl.R
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class ChooseSessionVerificationModeViewTest : RobolectricTest() {
|
||||||
class ChooseSessionVerificationModeViewTest {
|
|
||||||
@Config(qualifiers = "h1024dp")
|
@Config(qualifiers = "h1024dp")
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on learn more invokes the expected callback`() = runAndroidComposeUiTest {
|
fun `clicking on learn more invokes the expected callback`() = runAndroidComposeUiTest {
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.datastore.preferences)
|
implementation(libs.androidx.datastore.preferences)
|
||||||
implementation(libs.haze)
|
implementation(libs.haze)
|
||||||
implementation(libs.haze.materials)
|
implementation(libs.haze.materials)
|
||||||
|
implementation(projects.features.preferences.impl)
|
||||||
implementation(projects.features.reportroom.api)
|
implementation(projects.features.reportroom.api)
|
||||||
implementation(projects.features.rolesandpermissions.api)
|
implementation(projects.features.rolesandpermissions.api)
|
||||||
implementation(projects.libraries.previewutils)
|
implementation(projects.libraries.previewutils)
|
||||||
|
|||||||
+2
-18
@@ -69,10 +69,6 @@ fun RoomListContextMenu(
|
|||||||
onFavoriteChange = { isFavorite ->
|
onFavoriteChange = { isFavorite ->
|
||||||
eventSink(RoomListEvent.SetRoomIsFavorite(contextMenu.roomId, isFavorite))
|
eventSink(RoomListEvent.SetRoomIsFavorite(contextMenu.roomId, isFavorite))
|
||||||
},
|
},
|
||||||
onClearCacheRoomClick = {
|
|
||||||
eventSink(RoomListEvent.HideContextMenu)
|
|
||||||
eventSink(RoomListEvent.ClearCacheOfRoom(contextMenu.roomId))
|
|
||||||
},
|
|
||||||
onReportRoomClick = {
|
onReportRoomClick = {
|
||||||
eventSink(RoomListEvent.HideContextMenu)
|
eventSink(RoomListEvent.HideContextMenu)
|
||||||
onReportRoomClick(contextMenu.roomId)
|
onReportRoomClick(contextMenu.roomId)
|
||||||
@@ -90,7 +86,6 @@ private fun RoomListModalBottomSheetContent(
|
|||||||
onFavoriteChange: (isFavorite: Boolean) -> Unit,
|
onFavoriteChange: (isFavorite: Boolean) -> Unit,
|
||||||
onRoomMarkReadClick: () -> Unit,
|
onRoomMarkReadClick: () -> Unit,
|
||||||
onRoomMarkUnreadClick: () -> Unit,
|
onRoomMarkUnreadClick: () -> Unit,
|
||||||
onClearCacheRoomClick: () -> Unit,
|
|
||||||
onReportRoomClick: () -> Unit,
|
onReportRoomClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
@@ -111,7 +106,7 @@ private fun RoomListModalBottomSheetContent(
|
|||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.screen_roomlist_mark_as_read),
|
text = stringResource(id = CommonStrings.action_mark_as_read),
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -198,17 +193,6 @@ private fun RoomListModalBottomSheetContent(
|
|||||||
),
|
),
|
||||||
style = ListItemStyle.Destructive,
|
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())
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +200,7 @@ private fun RoomListModalBottomSheetContent(
|
|||||||
@Composable
|
@Composable
|
||||||
internal fun RoomListContextMenuPreview(
|
internal fun RoomListContextMenuPreview(
|
||||||
@PreviewParameter(RoomListStateContextMenuShownProvider::class) contextMenu: RoomListState.ContextMenu.Shown
|
@PreviewParameter(RoomListStateContextMenuShownProvider::class) contextMenu: RoomListState.ContextMenu.Shown
|
||||||
) = ElementPreview {
|
) = ElementPreview(fillMaxSize = true) {
|
||||||
RoomListContextMenu(
|
RoomListContextMenu(
|
||||||
contextMenu = contextMenu,
|
contextMenu = contextMenu,
|
||||||
canReportRoom = true,
|
canReportRoom = true,
|
||||||
|
|||||||
-1
@@ -30,5 +30,4 @@ sealed interface RoomListEvent {
|
|||||||
data class MarkAsRead(val roomId: RoomId) : ContextMenuEvent
|
data class MarkAsRead(val roomId: RoomId) : ContextMenuEvent
|
||||||
data class MarkAsUnread(val roomId: RoomId) : ContextMenuEvent
|
data class MarkAsUnread(val roomId: RoomId) : ContextMenuEvent
|
||||||
data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : ContextMenuEvent
|
data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : ContextMenuEvent
|
||||||
data class ClearCacheOfRoom(val roomId: RoomId) : ContextMenuEvent
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-29
@@ -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.Announcement
|
||||||
import io.element.android.features.announcement.api.AnnouncementService
|
import io.element.android.features.announcement.api.AnnouncementService
|
||||||
import io.element.android.features.home.impl.datasource.RoomListDataSource
|
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.RoomListFiltersState
|
||||||
import io.element.android.features.home.impl.filters.into
|
import io.element.android.features.home.impl.filters.into
|
||||||
import io.element.android.features.home.impl.search.RoomListSearchEvent
|
import io.element.android.features.home.impl.search.RoomListSearchEvent
|
||||||
@@ -42,6 +41,7 @@ import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteE
|
|||||||
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
|
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
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.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
@@ -52,12 +52,8 @@ 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.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
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.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.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.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.AnalyticsService
|
||||||
import io.element.android.services.analytics.api.watchers.AnalyticsColdStartWatcher
|
import io.element.android.services.analytics.api.watchers.AnalyticsColdStartWatcher
|
||||||
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
||||||
@@ -67,7 +63,6 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -81,13 +76,11 @@ class RoomListPresenter(
|
|||||||
private val roomListDataSource: RoomListDataSource,
|
private val roomListDataSource: RoomListDataSource,
|
||||||
private val filtersPresenter: Presenter<RoomListFiltersState>,
|
private val filtersPresenter: Presenter<RoomListFiltersState>,
|
||||||
private val searchPresenter: Presenter<RoomListSearchState>,
|
private val searchPresenter: Presenter<RoomListSearchState>,
|
||||||
private val sessionPreferencesStore: SessionPreferencesStore,
|
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
||||||
private val fullScreenIntentPermissionsPresenter: Presenter<FullScreenIntentPermissionsState>,
|
private val fullScreenIntentPermissionsPresenter: Presenter<FullScreenIntentPermissionsState>,
|
||||||
private val batteryOptimizationPresenter: Presenter<BatteryOptimizationState>,
|
private val batteryOptimizationPresenter: Presenter<BatteryOptimizationState>,
|
||||||
private val notificationCleaner: NotificationCleaner,
|
private val markRoomAsRead: MarkRoomAsRead,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
|
||||||
private val seenInvitesStore: SeenInvitesStore,
|
private val seenInvitesStore: SeenInvitesStore,
|
||||||
private val announcementService: AnnouncementService,
|
private val announcementService: AnnouncementService,
|
||||||
private val coldStartWatcher: AnalyticsColdStartWatcher,
|
private val coldStartWatcher: AnalyticsColdStartWatcher,
|
||||||
@@ -157,7 +150,6 @@ class RoomListPresenter(
|
|||||||
}
|
}
|
||||||
is RoomListEvent.ShowDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Shown(event.roomSummary)
|
is RoomListEvent.ShowDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Shown(event.roomSummary)
|
||||||
RoomListEvent.HideDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Hidden
|
RoomListEvent.HideDeclineInviteMenu -> declineInviteMenu.value = RoomListState.DeclineInviteMenu.Hidden
|
||||||
is RoomListEvent.ClearCacheOfRoom -> coroutineScope.clearCacheOfRoom(event.roomId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +272,6 @@ class RoomListPresenter(
|
|||||||
isDm = event.roomSummary.isDm,
|
isDm = event.roomSummary.isDm,
|
||||||
isFavorite = event.roomSummary.isFavorite,
|
isFavorite = event.roomSummary.isFavorite,
|
||||||
hasNewContent = event.roomSummary.hasNewContent,
|
hasNewContent = event.roomSummary.hasNewContent,
|
||||||
displayClearRoomCacheAction = appPreferencesStore.isDeveloperModeEnabledFlow().first(),
|
|
||||||
)
|
)
|
||||||
contextMenuState.value = initialState
|
contextMenuState.value = initialState
|
||||||
|
|
||||||
@@ -313,19 +304,10 @@ class RoomListPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.markAsRead(roomId: RoomId) = launch {
|
private fun CoroutineScope.markAsRead(roomId: RoomId) = launch {
|
||||||
notificationCleaner.clearMessagesForRoom(client.sessionId, roomId)
|
markRoomAsRead(roomId)
|
||||||
client.getRoom(roomId)?.use { room ->
|
.onSuccess {
|
||||||
room.setUnreadFlag(isUnread = false)
|
analyticsService.captureInteraction(name = Interaction.Name.MobileRoomListRoomContextMenuUnreadToggle)
|
||||||
val receiptType = if (sessionPreferencesStore.isSendPublicReadReceiptsEnabled().first()) {
|
|
||||||
ReceiptType.READ
|
|
||||||
} else {
|
|
||||||
ReceiptType.READ_PRIVATE
|
|
||||||
}
|
}
|
||||||
room.markAsRead(receiptType)
|
|
||||||
.onSuccess {
|
|
||||||
analyticsService.captureInteraction(name = Interaction.Name.MobileRoomListRoomContextMenuUnreadToggle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.markAsUnread(roomId: RoomId) = launch {
|
private fun CoroutineScope.markAsUnread(roomId: RoomId) = launch {
|
||||||
@@ -336,10 +318,4 @@ class RoomListPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.clearCacheOfRoom(roomId: RoomId) = launch {
|
|
||||||
client.getRoom(roomId)?.use { room ->
|
|
||||||
room.clearEventCacheStorage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -44,7 +44,6 @@ data class RoomListState(
|
|||||||
val isDm: Boolean,
|
val isDm: Boolean,
|
||||||
val isFavorite: Boolean,
|
val isFavorite: Boolean,
|
||||||
val hasNewContent: Boolean,
|
val hasNewContent: Boolean,
|
||||||
val displayClearRoomCacheAction: Boolean,
|
|
||||||
) : ContextMenu
|
) : ContextMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-1
@@ -31,5 +31,4 @@ internal fun aContextMenuShown(
|
|||||||
isDm = isDm,
|
isDm = isDm,
|
||||||
hasNewContent = hasNewContent,
|
hasNewContent = hasNewContent,
|
||||||
isFavorite = isFavorite,
|
isFavorite = isFavorite,
|
||||||
displayClearRoomCacheAction = false,
|
|
||||||
)
|
)
|
||||||
|
|||||||
+6
-2
@@ -33,6 +33,8 @@ import androidx.compose.ui.focus.focusRequester
|
|||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
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.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
@@ -112,10 +114,12 @@ private fun RoomListSearchContent(
|
|||||||
title = {
|
title = {
|
||||||
// The stateSaver will keep the selection state when returning to this UI
|
// The stateSaver will keep the selection state when returning to this UI
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
val searchLabel = stringResource(CommonStrings.action_search)
|
||||||
FilledTextField(
|
FilledTextField(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.focusRequester(focusRequester),
|
.focusRequester(focusRequester)
|
||||||
|
.semantics { contentDescription = searchLabel },
|
||||||
state = state.query,
|
state = state.query,
|
||||||
lineLimits = TextFieldLineLimits.SingleLine,
|
lineLimits = TextFieldLineLimits.SingleLine,
|
||||||
colors = TextFieldDefaults.colors(
|
colors = TextFieldDefaults.colors(
|
||||||
@@ -132,7 +136,7 @@ private fun RoomListSearchContent(
|
|||||||
IconButton(onClick = { state.eventSink(RoomListSearchEvent.ClearQuery) }) {
|
IconButton(onClick = { state.eventSink(RoomListSearchEvent.ClearQuery) }) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = CompoundIcons.Close(),
|
imageVector = CompoundIcons.Close(),
|
||||||
contentDescription = stringResource(CommonStrings.action_cancel)
|
contentDescription = stringResource(CommonStrings.a11y_clear_search_field)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -24,7 +24,7 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.text.input.TextFieldState
|
import androidx.compose.foundation.text.input.TextFieldState
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.SheetValue
|
import androidx.compose.material3.SheetValue
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -57,8 +57,9 @@ fun SpaceFiltersView(
|
|||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val isSelecting by rememberUpdatedState(state is SpaceFiltersState.Selecting)
|
val isSelecting by rememberUpdatedState(state is SpaceFiltersState.Selecting)
|
||||||
val sheetState = rememberModalBottomSheetState(
|
val sheetState = rememberBottomSheetState(
|
||||||
skipPartiallyExpanded = true,
|
initialValue = SheetValue.Hidden,
|
||||||
|
enabledValues = setOf(SheetValue.Hidden, SheetValue.Expanded),
|
||||||
confirmValueChange = { sheetValueTarget ->
|
confirmValueChange = { sheetValueTarget ->
|
||||||
// This ensures the hide animation is not cancelled
|
// This ensures the hide animation is not cancelled
|
||||||
when (sheetValueTarget) {
|
when (sheetValueTarget) {
|
||||||
@@ -187,6 +188,6 @@ private fun SpaceFilterItem(
|
|||||||
|
|
||||||
@PreviewsDayNight
|
@PreviewsDayNight
|
||||||
@Composable
|
@Composable
|
||||||
internal fun SpaceFiltersViewPreview(@PreviewParameter(SpaceFiltersStateProvider::class) state: SpaceFiltersState) = ElementPreview {
|
internal fun SpaceFiltersViewPreview(@PreviewParameter(SpaceFiltersStateProvider::class) state: SpaceFiltersState) = ElementPreview(fillMaxSize = true) {
|
||||||
SpaceFiltersView(state = state)
|
SpaceFiltersView(state = state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<string name="banner_battery_optimization_submit_android">"Nonaktifkan optimasi"</string>
|
<string name="banner_battery_optimization_submit_android">"Nonaktifkan optimasi"</string>
|
||||||
<string name="banner_battery_optimization_title_android">"Notifikasi tidak masuk?"</string>
|
<string name="banner_battery_optimization_title_android">"Notifikasi tidak masuk?"</string>
|
||||||
<string name="banner_set_up_recovery_content">"Buat kunci pemulihan baru yang dapat digunakan untuk memulihkan riwayat pesan terenkripsi Anda jika Anda kehilangan akses ke perangkat Anda."</string>
|
<string name="banner_set_up_recovery_content">"Buat kunci pemulihan baru yang dapat digunakan untuk memulihkan riwayat pesan terenkripsi Anda jika Anda kehilangan akses ke perangkat Anda."</string>
|
||||||
<string name="banner_set_up_recovery_submit">"Siapkan pemulihan"</string>
|
<string name="banner_set_up_recovery_submit">"Siapkan Kunci pemulihan"</string>
|
||||||
<string name="banner_set_up_recovery_title">"Siapkan pemulihan"</string>
|
<string name="banner_set_up_recovery_title">"Cadangkan obrolan Anda"</string>
|
||||||
<string name="confirm_recovery_key_banner_message">"Konfirmasikan kunci pemulihan Anda untuk mempertahankan akses ke penyimpanan kunci dan riwayat pesan Anda."</string>
|
<string name="confirm_recovery_key_banner_message">"Konfirmasikan kunci pemulihan Anda untuk mempertahankan akses ke penyimpanan kunci dan riwayat pesan Anda."</string>
|
||||||
<string name="confirm_recovery_key_banner_primary_button_title">"Masukkan kunci pemulihan Anda"</string>
|
<string name="confirm_recovery_key_banner_primary_button_title">"Masukkan kunci pemulihan Anda"</string>
|
||||||
<string name="confirm_recovery_key_banner_secondary_button_title">"Lupa kunci pemulihan Anda?"</string>
|
<string name="confirm_recovery_key_banner_secondary_button_title">"Lupa kunci pemulihan Anda?"</string>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<string name="banner_new_sound_message">"O seu ping de notificação foi atualizado—mais suave, mais rápido, e menos disruptivo."</string>
|
<string name="banner_new_sound_message">"O seu ping de notificação foi atualizado—mais suave, mais rápido, e menos disruptivo."</string>
|
||||||
<string name="banner_new_sound_title">"Recarregamos seus sons"</string>
|
<string name="banner_new_sound_title">"Recarregamos seus sons"</string>
|
||||||
<string name="banner_set_up_recovery_content">"Recupere sua identidade criptográfica e o histórico de mensagens com uma chave de recuperação caso você perda todos os dispositivos existentes."</string>
|
<string name="banner_set_up_recovery_content">"Recupere sua identidade criptográfica e o histórico de mensagens com uma chave de recuperação caso você perda todos os dispositivos existentes."</string>
|
||||||
<string name="banner_set_up_recovery_submit">"Configurar a recuperação"</string>
|
<string name="banner_set_up_recovery_submit">"Receber chave de recuperação"</string>
|
||||||
<string name="banner_set_up_recovery_title">"Configure a recuperação para proteger sua conta"</string>
|
<string name="banner_set_up_recovery_title">"Configure a recuperação para proteger sua conta"</string>
|
||||||
<string name="confirm_recovery_key_banner_message">"Confirme sua chave de recuperação para manter o acesso ao seu armazenamento de chaves e histórico de mensagens."</string>
|
<string name="confirm_recovery_key_banner_message">"Confirme sua chave de recuperação para manter o acesso ao seu armazenamento de chaves e histórico de mensagens."</string>
|
||||||
<string name="confirm_recovery_key_banner_primary_button_title">"Digite sua chave de recuperação"</string>
|
<string name="confirm_recovery_key_banner_primary_button_title">"Digite sua chave de recuperação"</string>
|
||||||
|
|||||||
@@ -5,15 +5,15 @@
|
|||||||
<string name="banner_battery_optimization_title_android">"Не надходять сповіщення?"</string>
|
<string name="banner_battery_optimization_title_android">"Не надходять сповіщення?"</string>
|
||||||
<string name="banner_new_sound_message">"Ваш сигнал сповіщень оновлено — він став чіткішим, швидшим і не таким надокучливим."</string>
|
<string name="banner_new_sound_message">"Ваш сигнал сповіщень оновлено — він став чіткішим, швидшим і не таким надокучливим."</string>
|
||||||
<string name="banner_new_sound_title">"Ми оновили ваші звуки"</string>
|
<string name="banner_new_sound_title">"Ми оновили ваші звуки"</string>
|
||||||
<string name="banner_set_up_recovery_content">"Відновіть свою криптографічну ідентичність та історію повідомлень за допомогою ключа відновлення, якщо ви втратили всі наявні пристрої."</string>
|
<string name="banner_set_up_recovery_content">"Ваші бесіди автоматично резервуються з використанням наскрізного шифрування. Щоб відновити цю резервну копію та зберегти свою цифрову ідентичність у разі втрати доступу до всіх своїх пристроїв, вам знадобиться ключ відновлення."</string>
|
||||||
<string name="banner_set_up_recovery_submit">"Налаштувати відновлення"</string>
|
<string name="banner_set_up_recovery_submit">"Отримати ключ відновлення"</string>
|
||||||
<string name="banner_set_up_recovery_title">"Налаштуйте відновлення для захисту свого облікового запису"</string>
|
<string name="banner_set_up_recovery_title">"Створити резервну копію своїх бесід"</string>
|
||||||
<string name="confirm_recovery_key_banner_message">"Підтвердіть свій ключ відновлення, щоб мати доступ до сховища ключів та історії повідомлень."</string>
|
<string name="confirm_recovery_key_banner_message">"Підтвердіть свій ключ відновлення, щоб мати доступ до сховища ключів та історії повідомлень."</string>
|
||||||
<string name="confirm_recovery_key_banner_primary_button_title">"Введіть ключ відновлення"</string>
|
<string name="confirm_recovery_key_banner_primary_button_title">"Введіть ключ відновлення"</string>
|
||||||
<string name="confirm_recovery_key_banner_secondary_button_title">"Забули ключ відновлення?"</string>
|
<string name="confirm_recovery_key_banner_secondary_button_title">"Забули ключ відновлення?"</string>
|
||||||
<string name="confirm_recovery_key_banner_title">"Ваше сховище ключів не синхронізовано"</string>
|
<string name="confirm_recovery_key_banner_title">"Ваше сховище ключів не синхронізовано"</string>
|
||||||
<string name="full_screen_intent_banner_message">"Щоб ніколи не пропустити важливий виклик, змініть налаштування, щоб увімкнути повноекранні сповіщення, коли телефон заблоковано."</string>
|
<string name="full_screen_intent_banner_message">"Щоб ніколи не пропустити важливий виклик, змініть налаштування, щоб увімкнути повноекранні сповіщення, коли телефон заблоковано."</string>
|
||||||
<string name="full_screen_intent_banner_title">"Покращуйте досвід дзвінків"</string>
|
<string name="full_screen_intent_banner_title">"Покращуйте якість викликів"</string>
|
||||||
<string name="screen_home_tab_chats">"Бесіди"</string>
|
<string name="screen_home_tab_chats">"Бесіди"</string>
|
||||||
<string name="screen_home_tab_spaces">"Простори"</string>
|
<string name="screen_home_tab_spaces">"Простори"</string>
|
||||||
<string name="screen_invites_decline_chat_message">"Ви впевнені, що хочете відхилити запрошення приєднатися до %1$s?"</string>
|
<string name="screen_invites_decline_chat_message">"Ви впевнені, що хочете відхилити запрошення приєднатися до %1$s?"</string>
|
||||||
@@ -51,6 +51,6 @@
|
|||||||
<string name="screen_roomlist_mark_as_unread">"Позначити непрочитаним"</string>
|
<string name="screen_roomlist_mark_as_unread">"Позначити непрочитаним"</string>
|
||||||
<string name="screen_roomlist_tombstoned_room_description">"Цю кімнату оновлено"</string>
|
<string name="screen_roomlist_tombstoned_room_description">"Цю кімнату оновлено"</string>
|
||||||
<string name="screen_roomlist_your_spaces">"Ваші простори"</string>
|
<string name="screen_roomlist_your_spaces">"Ваші простори"</string>
|
||||||
<string name="session_verification_banner_message">"Схоже, ви використовуєте новий пристрій. Щоб отримати доступ до зашифрованих повідомлень, підтвердьте особу за допомогою іншого пристрою."</string>
|
<string name="session_verification_banner_message">"Здається, ви використовуєте новий пристрій. Звірте його за допомогою іншого пристрою, щоб отримати доступ до своїх зашифрованих повідомлень."</string>
|
||||||
<string name="session_verification_banner_title">"Підтвердьте, що це ви"</string>
|
<string name="session_verification_banner_title">"Підтвердьте, що це ви"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
+2
-4
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
package io.element.android.features.home.impl
|
package io.element.android.features.home.impl
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
||||||
import com.bumble.appyx.core.modality.BuildContext
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.home.api.HomeEntryPoint
|
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.services.analytics.test.FakeAnalyticsService
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
import io.element.android.tests.testutils.node.TestParentNode
|
import io.element.android.tests.testutils.node.TestParentNode
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class DefaultHomeEntryPointTest : RobolectricTest() {
|
||||||
class DefaultHomeEntryPointTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `test node builder`() = runTest {
|
fun `test node builder`() = runTest {
|
||||||
val entryPoint = DefaultHomeEntryPoint()
|
val entryPoint = DefaultHomeEntryPoint()
|
||||||
|
|||||||
+2
-4
@@ -13,18 +13,16 @@ package io.element.android.features.home.impl.filters
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.R
|
||||||
import io.element.android.features.home.impl.filters.selection.FilterSelectionState
|
import io.element.android.features.home.impl.filters.selection.FilterSelectionState
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.pressTag
|
import io.element.android.tests.testutils.pressTag
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class RoomListFiltersViewTest : RobolectricTest() {
|
||||||
class RoomListFiltersViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on filters generates expected Event`() = runAndroidComposeUiTest {
|
fun `clicking on filters generates expected Event`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<RoomListFiltersEvent>()
|
val eventsRecorder = EventsRecorder<RoomListFiltersEvent>()
|
||||||
|
|||||||
+22
@@ -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<Unit> = { Result.success(Unit) },
|
||||||
|
) : MarkRoomAsRead {
|
||||||
|
val invokedRoomIds = mutableListOf<RoomId>()
|
||||||
|
|
||||||
|
override suspend fun invoke(roomId: RoomId): Result<Unit> {
|
||||||
|
invokedRoomIds.add(roomId)
|
||||||
|
return invokeLambda(roomId)
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-5
@@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.R
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
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.EnsureNeverCalledWithParam
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
import io.element.android.tests.testutils.clickOn
|
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.tests.testutils.setSafeContent
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class RoomListContextMenuTest : RobolectricTest() {
|
||||||
class RoomListContextMenuTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on Mark as read generates expected Events`() = runAndroidComposeUiTest {
|
fun `clicking on Mark as read generates expected Events`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||||
@@ -36,7 +34,7 @@ class RoomListContextMenuTest {
|
|||||||
contextMenu = contextMenu,
|
contextMenu = contextMenu,
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
)
|
)
|
||||||
clickOn(R.string.screen_roomlist_mark_as_read)
|
clickOn(CommonStrings.action_mark_as_read)
|
||||||
eventsRecorder.assertList(
|
eventsRecorder.assertList(
|
||||||
listOf(
|
listOf(
|
||||||
RoomListEvent.HideContextMenu,
|
RoomListEvent.HideContextMenu,
|
||||||
|
|||||||
+2
-4
@@ -12,19 +12,17 @@ package io.element.android.features.home.impl.roomlist
|
|||||||
|
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.features.home.impl.model.aRoomListRoomSummary
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureCalledOnceWithParam
|
import io.element.android.tests.testutils.EnsureCalledOnceWithParam
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
import io.element.android.tests.testutils.clickOn
|
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.tests.testutils.setSafeContent
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class RoomListDeclineInviteMenuTest : RobolectricTest() {
|
||||||
class RoomListDeclineInviteMenuTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on decline emits the expected Events`() = runAndroidComposeUiTest {
|
fun `clicking on decline emits the expected Events`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
val eventsRecorder = EventsRecorder<RoomListEvent>()
|
||||||
|
|||||||
+31
-37
@@ -30,6 +30,7 @@ import io.element.android.features.invite.api.acceptdecline.anAcceptDeclineInvit
|
|||||||
import io.element.android.features.invite.test.InMemorySeenInvitesStore
|
import io.element.android.features.invite.test.InMemorySeenInvitesStore
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
import io.element.android.features.leaveroom.api.LeaveRoomEvent
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
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.features.rageshake.test.logs.FakeAnnouncementService
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.dateformatter.api.DateFormatter
|
import io.element.android.libraries.dateformatter.api.DateFormatter
|
||||||
@@ -63,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.roomlist.FakeRoomListService
|
||||||
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||||
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
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.api.store.SessionPreferencesStore
|
||||||
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
|
|
||||||
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
|
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
|
||||||
import io.element.android.libraries.push.api.battery.aBatteryOptimizationState
|
import io.element.android.libraries.push.api.battery.aBatteryOptimizationState
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
||||||
@@ -230,7 +229,6 @@ class RoomListPresenterTest {
|
|||||||
isDm = false,
|
isDm = false,
|
||||||
isFavorite = false,
|
isFavorite = false,
|
||||||
hasNewContent = false,
|
hasNewContent = false,
|
||||||
displayClearRoomCacheAction = false,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -247,35 +245,6 @@ class RoomListPresenterTest {
|
|||||||
isDm = false,
|
isDm = false,
|
||||||
isFavorite = true,
|
isFavorite = true,
|
||||||
hasNewContent = false,
|
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,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -303,7 +272,6 @@ class RoomListPresenterTest {
|
|||||||
isDm = false,
|
isDm = false,
|
||||||
isFavorite = false,
|
isFavorite = false,
|
||||||
hasNewContent = false,
|
hasNewContent = false,
|
||||||
displayClearRoomCacheAction = false,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -460,11 +428,17 @@ class RoomListPresenterTest {
|
|||||||
val notificationCleaner = FakeNotificationCleaner(
|
val notificationCleaner = FakeNotificationCleaner(
|
||||||
clearMessagesForRoomLambda = clearMessagesForRoomLambda,
|
clearMessagesForRoomLambda = clearMessagesForRoomLambda,
|
||||||
)
|
)
|
||||||
|
val markRoomAsRead = createTestMarkRoomAsRead(
|
||||||
|
client = matrixClient,
|
||||||
|
notificationCleaner = notificationCleaner,
|
||||||
|
sessionPreferencesStore = sessionPreferencesStore,
|
||||||
|
)
|
||||||
val presenter = createRoomListPresenter(
|
val presenter = createRoomListPresenter(
|
||||||
client = matrixClient,
|
client = matrixClient,
|
||||||
sessionPreferencesStore = sessionPreferencesStore,
|
sessionPreferencesStore = sessionPreferencesStore,
|
||||||
analyticsService = analyticsService,
|
analyticsService = analyticsService,
|
||||||
notificationCleaner = notificationCleaner,
|
notificationCleaner = notificationCleaner,
|
||||||
|
markRoomAsRead = markRoomAsRead,
|
||||||
)
|
)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
@@ -656,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(
|
private fun TestScope.createRoomListPresenter(
|
||||||
client: MatrixClient = FakeMatrixClient(),
|
client: MatrixClient = FakeMatrixClient(),
|
||||||
leaveRoomState: LeaveRoomState = aLeaveRoomState(),
|
leaveRoomState: LeaveRoomState = aLeaveRoomState(),
|
||||||
@@ -668,10 +660,10 @@ class RoomListPresenterTest {
|
|||||||
spaceFiltersPresenter: Presenter<SpaceFiltersState> = Presenter { aDisabledSpaceFiltersState() },
|
spaceFiltersPresenter: Presenter<SpaceFiltersState> = Presenter { aDisabledSpaceFiltersState() },
|
||||||
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState> = Presenter { anAcceptDeclineInviteState() },
|
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState> = Presenter { anAcceptDeclineInviteState() },
|
||||||
notificationCleaner: NotificationCleaner = FakeNotificationCleaner(),
|
notificationCleaner: NotificationCleaner = FakeNotificationCleaner(),
|
||||||
appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore(),
|
|
||||||
seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore(),
|
seenInvitesStore: SeenInvitesStore = InMemorySeenInvitesStore(),
|
||||||
announcementService: AnnouncementService = FakeAnnouncementService(),
|
announcementService: AnnouncementService = FakeAnnouncementService(),
|
||||||
featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
|
featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
|
||||||
|
markRoomAsRead: MarkRoomAsRead? = null,
|
||||||
) = RoomListPresenter(
|
) = RoomListPresenter(
|
||||||
client = client,
|
client = client,
|
||||||
leaveRoomPresenter = { leaveRoomState },
|
leaveRoomPresenter = { leaveRoomState },
|
||||||
@@ -688,15 +680,17 @@ class RoomListPresenterTest {
|
|||||||
analyticsService = FakeAnalyticsService(),
|
analyticsService = FakeAnalyticsService(),
|
||||||
),
|
),
|
||||||
searchPresenter = searchPresenter,
|
searchPresenter = searchPresenter,
|
||||||
sessionPreferencesStore = sessionPreferencesStore,
|
|
||||||
filtersPresenter = filtersPresenter,
|
filtersPresenter = filtersPresenter,
|
||||||
spaceFiltersPresenter = spaceFiltersPresenter,
|
spaceFiltersPresenter = spaceFiltersPresenter,
|
||||||
analyticsService = analyticsService,
|
analyticsService = analyticsService,
|
||||||
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
|
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
|
||||||
fullScreenIntentPermissionsPresenter = { aFullScreenIntentPermissionsState() },
|
fullScreenIntentPermissionsPresenter = { aFullScreenIntentPermissionsState() },
|
||||||
batteryOptimizationPresenter = { aBatteryOptimizationState() },
|
batteryOptimizationPresenter = { aBatteryOptimizationState() },
|
||||||
notificationCleaner = notificationCleaner,
|
markRoomAsRead = markRoomAsRead ?: createTestMarkRoomAsRead(
|
||||||
appPreferencesStore = appPreferencesStore,
|
client = client,
|
||||||
|
notificationCleaner = notificationCleaner,
|
||||||
|
sessionPreferencesStore = sessionPreferencesStore,
|
||||||
|
),
|
||||||
seenInvitesStore = seenInvitesStore,
|
seenInvitesStore = seenInvitesStore,
|
||||||
announcementService = announcementService,
|
announcementService = announcementService,
|
||||||
coldStartWatcher = FakeAnalyticsColdStartWatcher(),
|
coldStartWatcher = FakeAnalyticsColdStartWatcher(),
|
||||||
|
|||||||
+2
-4
@@ -19,7 +19,6 @@ import androidx.compose.ui.test.onNodeWithText
|
|||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.performTouchInput
|
import androidx.compose.ui.test.performTouchInput
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.HomeView
|
||||||
import io.element.android.features.home.impl.R
|
import io.element.android.features.home.impl.R
|
||||||
import io.element.android.features.home.impl.aHomeState
|
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.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import io.element.android.tests.testutils.setSafeContent
|
import io.element.android.tests.testutils.setSafeContent
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class RoomListViewTest : RobolectricTest() {
|
||||||
class RoomListViewTest {
|
|
||||||
@Config(qualifiers = "h1024dp")
|
@Config(qualifiers = "h1024dp")
|
||||||
@Test
|
@Test
|
||||||
fun `displaying the view automatically sends a couple of UpdateVisibleRangeEvents`() = runAndroidComposeUiTest {
|
fun `displaying the view automatically sends a couple of UpdateVisibleRangeEvents`() = runAndroidComposeUiTest {
|
||||||
|
|||||||
+2
-4
@@ -15,14 +15,12 @@ import androidx.compose.ui.test.ExperimentalTestApi
|
|||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.libraries.matrix.test.A_ROOM_ALIAS
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class SpaceFiltersViewTest : RobolectricTest() {
|
||||||
class SpaceFiltersViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on a filter with alias shows display name and alias`() = runAndroidComposeUiTest {
|
fun `clicking on a filter with alias shows display name and alias`() = runAndroidComposeUiTest {
|
||||||
val filter = aSpaceServiceFilter(
|
val filter = aSpaceServiceFilter(
|
||||||
|
|||||||
+2
-4
@@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi
|
|||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.performTextInput
|
import androidx.compose.ui.test.performTextInput
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.features.invite.impl.R
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
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.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class DeclineAndBlockViewTest : RobolectricTest() {
|
||||||
class DeclineAndBlockViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest {
|
fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<DeclineAndBlockEvents>(expectEvents = false)
|
val eventsRecorder = EventsRecorder<DeclineAndBlockEvents>(expectEvents = false)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_invite_users_already_a_member">"Уже учасник"</string>
|
<string name="screen_invite_users_already_a_member">"Уже учасник"</string>
|
||||||
<string name="screen_invite_users_already_invited">"Уже запрошені"</string>
|
<string name="screen_invite_users_already_invited">"Уже запрошені"</string>
|
||||||
<string name="screen_invite_users_confirm_dialog_subtitle_multiple_users">"Наразі у вас немає чатів із цими контактами. Підтвердьте запрошення їх до цієї кімнати, перш ніж продовжувати."</string>
|
<string name="screen_invite_users_confirm_dialog_subtitle_multiple_users">"Наразі у вас немає бесід з цими контактами. Підтвердьте запрошення їх до цієї кімнати, перш ніж продовжувати."</string>
|
||||||
<string name="screen_invite_users_confirm_dialog_subtitle_one_user">"Наразі у вас немає чатів із цим контактом. Підтвердьте запрошення до цієї кімнати, перш ніж продовжувати."</string>
|
<string name="screen_invite_users_confirm_dialog_subtitle_one_user">"Наразі у вас немає бесід із цим контактом. Підтвердьте запрошення до цієї кімнати, перш ніж продовжувати."</string>
|
||||||
<string name="screen_invite_users_confirm_dialog_title_mutiple_users">"Запросити нових контактів до цієї кімнати?"</string>
|
<string name="screen_invite_users_confirm_dialog_title_mutiple_users">"Запросити нових контактів до цієї кімнати?"</string>
|
||||||
<string name="screen_invite_users_confirm_dialog_title_one_user">"Запросити нового контакта до цієї кімнати?"</string>
|
<string name="screen_invite_users_confirm_dialog_title_one_user">"Запросити нового контакта до цієї кімнати?"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
<string name="screen_join_room_fail_reason">"Ruangan ini hanya untuk undangan atau mungkin ada pembatasan akses pada tingkat space."</string>
|
<string name="screen_join_room_fail_reason">"Ruangan ini hanya untuk undangan atau mungkin ada pembatasan akses pada tingkat space."</string>
|
||||||
<string name="screen_join_room_forget_action">"Lupa"</string>
|
<string name="screen_join_room_forget_action">"Lupa"</string>
|
||||||
<string name="screen_join_room_invite_required_message">"Anda memerlukan undangan untuk bergabung dalam ruangan ini"</string>
|
<string name="screen_join_room_invite_required_message">"Anda memerlukan undangan untuk bergabung dalam ruangan ini"</string>
|
||||||
|
<string name="screen_join_room_invited_by">
|
||||||
|
"Diundang oleh "
|
||||||
|
<userName/>
|
||||||
|
</string>
|
||||||
<string name="screen_join_room_join_action">"Gabung"</string>
|
<string name="screen_join_room_join_action">"Gabung"</string>
|
||||||
<string name="screen_join_room_join_restricted_message">"Anda mungkin perlu diundang atau menjadi anggota space untuk bergabung."</string>
|
<string name="screen_join_room_join_restricted_message">"Anda mungkin perlu diundang atau menjadi anggota space untuk bergabung."</string>
|
||||||
<string name="screen_join_room_knock_action">"Ketuk untuk bergabung"</string>
|
<string name="screen_join_room_knock_action">"Ketuk untuk bergabung"</string>
|
||||||
|
|||||||
+2
-4
@@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.api.InviteData
|
||||||
import io.element.android.features.invite.test.anInviteData
|
import io.element.android.features.invite.test.anInviteData
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
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.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class JoinRoomViewTest : RobolectricTest() {
|
||||||
class JoinRoomViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest {
|
fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<JoinRoomEvents>(expectEvents = false)
|
val eventsRecorder = EventsRecorder<JoinRoomEvents>(expectEvents = false)
|
||||||
|
|||||||
+2
-4
@@ -16,7 +16,6 @@ import androidx.compose.ui.test.ExperimentalTestApi
|
|||||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.R
|
||||||
import io.element.android.features.knockrequests.impl.data.aKnockRequestPresentable
|
import io.element.android.features.knockrequests.impl.data.aKnockRequestPresentable
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
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.EventsRecorder
|
||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class KnockRequestsBannerViewTest : RobolectricTest() {
|
||||||
class KnockRequestsBannerViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on view on single request invoke the expected callback`() = runAndroidComposeUiTest {
|
fun `clicking on view on single request invoke the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<KnockRequestsBannerEvents>(expectEvents = false)
|
val eventsRecorder = EventsRecorder<KnockRequestsBannerEvents>(expectEvents = false)
|
||||||
|
|||||||
+2
-4
@@ -14,7 +14,6 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.R
|
||||||
import io.element.android.features.knockrequests.impl.data.aKnockRequestPresentable
|
import io.element.android.features.knockrequests.impl.data.aKnockRequestPresentable
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
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.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class KnockRequestsListViewTest : RobolectricTest() {
|
||||||
class KnockRequestsListViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest {
|
fun `clicking on back invoke the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<KnockRequestsListEvents>(expectEvents = false)
|
val eventsRecorder = EventsRecorder<KnockRequestsListEvents>(expectEvents = false)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="leave_conversation_alert_subtitle">"Czy na pewno chcesz opuścić tę konwersację? Konwersacja nie jest publiczna i nie będziesz mógł dołączyć ponownie bez zaproszenia."</string>
|
<string name="leave_conversation_alert_subtitle">"Czy na pewno chcesz opuścić tę konwersację? Konwersacja nie jest publiczna i nie będziesz mógł dołączyć ponownie bez zaproszenia."</string>
|
||||||
<string name="leave_room_alert_empty_subtitle">"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."</string>
|
<string name="leave_room_alert_empty_subtitle">"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."</string>
|
||||||
<string name="leave_room_alert_private_subtitle">"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."</string>
|
<string name="leave_room_alert_private_subtitle">"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."</string>
|
||||||
<string name="leave_room_alert_select_new_owner_action">"Wybierz właścicieli"</string>
|
<string name="leave_room_alert_select_new_owner_action">"Wybierz właścicieli"</string>
|
||||||
<string name="leave_room_alert_select_new_owner_subtitle">"Jesteś jedynym właścicielem tego pokoju. Musisz przenieść własność na kogoś innego, zanim go opuścisz."</string>
|
<string name="leave_room_alert_select_new_owner_subtitle">"Jesteś jedynym właścicielem tego pokoju. Musisz przenieść własność na kogoś innego, zanim go opuścisz."</string>
|
||||||
<string name="leave_room_alert_select_new_owner_title">"Przenieś własność"</string>
|
<string name="leave_room_alert_select_new_owner_title">"Przenieś własność"</string>
|
||||||
<string name="leave_room_alert_subtitle">"Jesteś pewien, że chcesz wyjść z tego pokoju?"</string>
|
<string name="leave_room_alert_subtitle">"Czy na pewno chcesz wyjść z tego pokoju?"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ dependencies {
|
|||||||
// TODO Cleanup
|
// TODO Cleanup
|
||||||
implementation(projects.appconfig)
|
implementation(projects.appconfig)
|
||||||
implementation(projects.features.enterprise.api)
|
implementation(projects.features.enterprise.api)
|
||||||
|
implementation(projects.features.lockscreen.api)
|
||||||
implementation(projects.features.rageshake.api)
|
implementation(projects.features.rageshake.api)
|
||||||
implementation(projects.libraries.core)
|
implementation(projects.libraries.core)
|
||||||
implementation(projects.libraries.androidutils)
|
implementation(projects.libraries.androidutils)
|
||||||
@@ -53,6 +54,7 @@ dependencies {
|
|||||||
|
|
||||||
testCommonDependencies(libs, true)
|
testCommonDependencies(libs, true)
|
||||||
testImplementation(projects.features.linknewdevice.test)
|
testImplementation(projects.features.linknewdevice.test)
|
||||||
|
testImplementation(projects.features.lockscreen.test)
|
||||||
testImplementation(projects.features.enterprise.test)
|
testImplementation(projects.features.enterprise.test)
|
||||||
testImplementation(projects.libraries.featureflag.test)
|
testImplementation(projects.libraries.featureflag.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
|||||||
+34
-3
@@ -13,8 +13,10 @@ import androidx.activity.compose.LocalActivity
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import com.bumble.appyx.core.composable.PermanentChild
|
||||||
import com.bumble.appyx.core.lifecycle.subscribe
|
import com.bumble.appyx.core.lifecycle.subscribe
|
||||||
import com.bumble.appyx.core.modality.BuildContext
|
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.node.Node
|
||||||
import com.bumble.appyx.core.plugin.Plugin
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
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.error.ErrorScreenType
|
||||||
import io.element.android.features.linknewdevice.impl.screens.number.EnterNumberNode
|
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.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.root.LinkNewDeviceRootNode
|
||||||
import io.element.android.features.linknewdevice.impl.screens.scan.ScanQrCodeNode
|
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.androidutils.browser.openUrlInChromeCustomTab
|
||||||
import io.element.android.libraries.architecture.BackstackView
|
import io.element.android.libraries.architecture.BackstackView
|
||||||
import io.element.android.libraries.architecture.BaseFlowNode
|
import io.element.android.libraries.architecture.BaseFlowNode
|
||||||
@@ -67,11 +71,16 @@ class LinkNewDeviceFlowNode(
|
|||||||
private val linkNewMobileHandler: LinkNewMobileHandler,
|
private val linkNewMobileHandler: LinkNewMobileHandler,
|
||||||
private val linkNewDesktopHandler: LinkNewDesktopHandler,
|
private val linkNewDesktopHandler: LinkNewDesktopHandler,
|
||||||
private val sessionEnterpriseService: SessionEnterpriseService,
|
private val sessionEnterpriseService: SessionEnterpriseService,
|
||||||
|
private val deviceUnlockEntryPoint: DeviceUnlockEntryPoint,
|
||||||
) : BaseFlowNode<LinkNewDeviceFlowNode.NavTarget>(
|
) : BaseFlowNode<LinkNewDeviceFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
initialElement = NavTarget.Root,
|
initialElement = NavTarget.Root,
|
||||||
savedStateMap = buildContext.savedStateMap,
|
savedStateMap = buildContext.savedStateMap,
|
||||||
),
|
),
|
||||||
|
permanentNavModel = PermanentNavModel(
|
||||||
|
navTargets = setOf(NavTarget.LockScreen),
|
||||||
|
savedStateMap = buildContext.savedStateMap,
|
||||||
|
),
|
||||||
buildContext = buildContext,
|
buildContext = buildContext,
|
||||||
plugins = plugins,
|
plugins = plugins,
|
||||||
) {
|
) {
|
||||||
@@ -124,6 +133,9 @@ class LinkNewDeviceFlowNode(
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
data object DesktopScanQrCode : NavTarget
|
data object DesktopScanQrCode : NavTarget
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data object LockScreen : NavTarget
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Error(
|
data class Error(
|
||||||
val errorScreenType: ErrorScreenType,
|
val errorScreenType: ErrorScreenType,
|
||||||
@@ -137,6 +149,9 @@ class LinkNewDeviceFlowNode(
|
|||||||
Timber.tag(tag.value).d("step: ${linkMobileStep::class.java.simpleName}")
|
Timber.tag(tag.value).d("step: ${linkMobileStep::class.java.simpleName}")
|
||||||
when (linkMobileStep) {
|
when (linkMobileStep) {
|
||||||
LinkMobileStep.Uninitialized -> Unit
|
LinkMobileStep.Uninitialized -> Unit
|
||||||
|
LinkMobileStep.CreatingQrCode -> {
|
||||||
|
// This step is handled in LinkNewDeviceRootPresenter
|
||||||
|
}
|
||||||
LinkMobileStep.Done -> {
|
LinkMobileStep.Done -> {
|
||||||
callback.onDone()
|
callback.onDone()
|
||||||
}
|
}
|
||||||
@@ -224,13 +239,28 @@ class LinkNewDeviceFlowNode(
|
|||||||
callback.onDone()
|
callback.onDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun linkDesktopDevice() {
|
override fun onUnlockDevice(type: LinkDeviceType) {
|
||||||
linkNewDesktopHandler.reset()
|
val callback = object : DeviceUnlockEntryPoint.Callback {
|
||||||
backstack.push(NavTarget.DesktopNotice)
|
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<LinkNewDeviceRootNode>(buildContext, listOf(callback))
|
createNode<LinkNewDeviceRootNode>(buildContext, listOf(callback))
|
||||||
}
|
}
|
||||||
|
is NavTarget.LockScreen -> {
|
||||||
|
deviceUnlockEntryPoint.createNode(this, buildContext)
|
||||||
|
}
|
||||||
NavTarget.DesktopNotice -> {
|
NavTarget.DesktopNotice -> {
|
||||||
val callback = object : DesktopNoticeNode.Callback {
|
val callback = object : DesktopNoticeNode.Callback {
|
||||||
override fun navigateBack() {
|
override fun navigateBack() {
|
||||||
@@ -324,5 +354,6 @@ class LinkNewDeviceFlowNode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BackstackView()
|
BackstackView()
|
||||||
|
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LockScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -43,12 +43,15 @@ class LinkNewMobileHandler(
|
|||||||
val stepFlow: StateFlow<LinkMobileStep>
|
val stepFlow: StateFlow<LinkMobileStep>
|
||||||
get() = linkMobileStepFlow.asStateFlow()
|
get() = linkMobileStepFlow.asStateFlow()
|
||||||
|
|
||||||
fun createAndStartNewHandler() {
|
fun createAndStartNewHandler(forRotating: Boolean = false) {
|
||||||
Timber.tag(loggerTag.value).d("createAndStartNewHandler()")
|
Timber.tag(loggerTag.value).d("createAndStartNewHandler()")
|
||||||
currentJob?.cancel()
|
currentJob?.cancel()
|
||||||
handler = matrixClient.createLinkMobileHandler().getOrNull()
|
handler = matrixClient.createLinkMobileHandler().getOrNull()
|
||||||
handler?.let { h ->
|
handler?.let { h ->
|
||||||
currentJob = sessionScope.launch {
|
currentJob = sessionScope.launch {
|
||||||
|
if (!forRotating) {
|
||||||
|
linkMobileStepFlow.emit(LinkMobileStep.CreatingQrCode)
|
||||||
|
}
|
||||||
h.linkMobileStep
|
h.linkMobileStep
|
||||||
.onEach {
|
.onEach {
|
||||||
linkMobileStepFlow.emit(it)
|
linkMobileStepFlow.emit(it)
|
||||||
@@ -68,7 +71,7 @@ class LinkNewMobileHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun rotateQrCode() {
|
fun rotateQrCode() {
|
||||||
createAndStartNewHandler()
|
createAndStartNewHandler(forRotating = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onTooManyRotation() {
|
fun onTooManyRotation() {
|
||||||
|
|||||||
+4
-3
@@ -5,8 +5,9 @@
|
|||||||
* Please see LICENSE files in the repository root for full details.
|
* 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 {
|
enum class LinkDeviceType {
|
||||||
fun provides(): List<ByteArray>
|
Mobile,
|
||||||
|
Desktop,
|
||||||
}
|
}
|
||||||
-1
@@ -8,6 +8,5 @@
|
|||||||
package io.element.android.features.linknewdevice.impl.screens.root
|
package io.element.android.features.linknewdevice.impl.screens.root
|
||||||
|
|
||||||
sealed interface LinkNewDeviceRootEvent {
|
sealed interface LinkNewDeviceRootEvent {
|
||||||
data object LinkMobileDevice : LinkNewDeviceRootEvent
|
|
||||||
data object CloseDialog : LinkNewDeviceRootEvent
|
data object CloseDialog : LinkNewDeviceRootEvent
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -27,7 +27,7 @@ class LinkNewDeviceRootNode(
|
|||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun onDone()
|
fun onDone()
|
||||||
fun linkDesktopDevice()
|
fun onUnlockDevice(type: LinkDeviceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val callback: Callback = callback()
|
private val callback: Callback = callback()
|
||||||
@@ -39,7 +39,7 @@ class LinkNewDeviceRootNode(
|
|||||||
state = state,
|
state = state,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onBackClick = callback::onDone,
|
onBackClick = callback::onDone,
|
||||||
onLinkDesktopDeviceClick = callback::linkDesktopDevice,
|
onUnlockDevice = callback::onUnlockDevice,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -50,7 +50,13 @@ class LinkNewDeviceRootPresenter(
|
|||||||
LaunchedEffect(step) {
|
LaunchedEffect(step) {
|
||||||
when (val finalStep = step) {
|
when (val finalStep = step) {
|
||||||
is LinkMobileStep.Uninitialized -> {
|
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 -> {
|
is LinkMobileStep.QrReady -> {
|
||||||
qrCodeData = AsyncData.Success(Unit)
|
qrCodeData = AsyncData.Success(Unit)
|
||||||
@@ -64,12 +70,6 @@ class LinkNewDeviceRootPresenter(
|
|||||||
|
|
||||||
fun handleEvent(event: LinkNewDeviceRootEvent) {
|
fun handleEvent(event: LinkNewDeviceRootEvent) {
|
||||||
when (event) {
|
when (event) {
|
||||||
LinkNewDeviceRootEvent.LinkMobileDevice -> coroutineScope.launch {
|
|
||||||
qrCodeData = AsyncData.Loading()
|
|
||||||
// Wait for the QrCode to be ready
|
|
||||||
linkNewMobileHandler.reset()
|
|
||||||
linkNewMobileHandler.createAndStartNewHandler()
|
|
||||||
}
|
|
||||||
LinkNewDeviceRootEvent.CloseDialog -> coroutineScope.launch {
|
LinkNewDeviceRootEvent.CloseDialog -> coroutineScope.launch {
|
||||||
linkNewMobileHandler.reset()
|
linkNewMobileHandler.reset()
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-36
@@ -41,7 +41,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
|||||||
fun LinkNewDeviceRootView(
|
fun LinkNewDeviceRootView(
|
||||||
state: LinkNewDeviceRootState,
|
state: LinkNewDeviceRootState,
|
||||||
onBackClick: () -> Unit,
|
onBackClick: () -> Unit,
|
||||||
onLinkDesktopDeviceClick: () -> Unit,
|
onUnlockDevice: (type: LinkDeviceType) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val (title, subtitle, iconStyle) = if (state.isSupported.dataOrNull() == false) {
|
val (title, subtitle, iconStyle) = if (state.isSupported.dataOrNull() == false) {
|
||||||
@@ -57,6 +57,7 @@ fun LinkNewDeviceRootView(
|
|||||||
BigIcon.Style.Default(CompoundIcons.Devices())
|
BigIcon.Style.Default(CompoundIcons.Devices())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlowStepPage(
|
FlowStepPage(
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
title = title,
|
title = title,
|
||||||
@@ -83,40 +84,37 @@ fun LinkNewDeviceRootView(
|
|||||||
}
|
}
|
||||||
is AsyncData.Success -> {
|
is AsyncData.Success -> {
|
||||||
if (state.isSupported.data) {
|
if (state.isSupported.data) {
|
||||||
when (state.qrCodeData) {
|
val canClick = state.qrCodeData is AsyncData.Uninitialized
|
||||||
AsyncData.Uninitialized,
|
val isLoading = state.qrCodeData is AsyncData.Loading || state.qrCodeData is AsyncData.Success
|
||||||
is AsyncData.Failure -> {
|
Button(
|
||||||
Button(
|
onClick = {
|
||||||
onClick = { state.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) },
|
if (canClick) {
|
||||||
text = stringResource(id = R.string.screen_link_new_device_root_mobile_device),
|
onUnlockDevice(LinkDeviceType.Mobile)
|
||||||
modifier = Modifier.fillMaxWidth(),
|
}
|
||||||
leadingIcon = IconSource.Vector(CompoundIcons.Mobile()),
|
},
|
||||||
)
|
text = stringResource(
|
||||||
Button(
|
id = if (isLoading) {
|
||||||
onClick = onLinkDesktopDeviceClick,
|
R.string.screen_link_new_device_root_loading_qr_code
|
||||||
text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer),
|
} else {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
R.string.screen_link_new_device_root_mobile_device
|
||||||
leadingIcon = IconSource.Vector(CompoundIcons.Computer()),
|
}
|
||||||
)
|
),
|
||||||
}
|
showProgress = isLoading,
|
||||||
is AsyncData.Loading,
|
enabled = !isLoading,
|
||||||
is AsyncData.Success -> {
|
modifier = Modifier.fillMaxWidth(),
|
||||||
Button(
|
leadingIcon = IconSource.Vector(CompoundIcons.Mobile()),
|
||||||
onClick = { state.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice) },
|
)
|
||||||
text = stringResource(id = R.string.screen_link_new_device_root_loading_qr_code),
|
Button(
|
||||||
showProgress = true,
|
onClick = {
|
||||||
enabled = false,
|
if (canClick) {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
onUnlockDevice(LinkDeviceType.Desktop)
|
||||||
)
|
}
|
||||||
Button(
|
},
|
||||||
onClick = onLinkDesktopDeviceClick,
|
text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer),
|
||||||
text = stringResource(id = R.string.screen_link_new_device_root_desktop_computer),
|
enabled = !isLoading,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
enabled = false,
|
leadingIcon = IconSource.Vector(CompoundIcons.Computer()),
|
||||||
leadingIcon = IconSource.Vector(CompoundIcons.Computer()),
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Button(
|
Button(
|
||||||
onClick = onBackClick,
|
onClick = onBackClick,
|
||||||
@@ -147,6 +145,6 @@ internal fun LinkNewDeviceRootViewPreview(
|
|||||||
LinkNewDeviceRootView(
|
LinkNewDeviceRootView(
|
||||||
state = state,
|
state = state,
|
||||||
onBackClick = { },
|
onBackClick = { },
|
||||||
onLinkDesktopDeviceClick = { },
|
onUnlockDevice = { },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -13,6 +13,7 @@ import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
|
|||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.enterprise.test.FakeSessionEnterpriseService
|
import io.element.android.features.enterprise.test.FakeSessionEnterpriseService
|
||||||
import io.element.android.features.linknewdevice.api.LinkNewDeviceEntryPoint
|
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.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
import io.element.android.tests.testutils.node.TestParentNode
|
import io.element.android.tests.testutils.node.TestParentNode
|
||||||
@@ -39,6 +40,7 @@ class DefaultLinkNewDeviceEntryPointTest {
|
|||||||
linkNewMobileHandler = LinkNewMobileHandler(client),
|
linkNewMobileHandler = LinkNewMobileHandler(client),
|
||||||
linkNewDesktopHandler = LinkNewDesktopHandler(client),
|
linkNewDesktopHandler = LinkNewDesktopHandler(client),
|
||||||
sessionEnterpriseService = FakeSessionEnterpriseService(),
|
sessionEnterpriseService = FakeSessionEnterpriseService(),
|
||||||
|
deviceUnlockEntryPoint = FakeDeviceUnlockEntryPoint(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val callback: LinkNewDeviceEntryPoint.Callback = object : LinkNewDeviceEntryPoint.Callback {
|
val callback: LinkNewDeviceEntryPoint.Callback = object : LinkNewDeviceEntryPoint.Callback {
|
||||||
|
|||||||
+2
-4
@@ -13,7 +13,6 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.features.linknewdevice.impl.R
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
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.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class DesktopNoticeViewTest : RobolectricTest() {
|
||||||
class DesktopNoticeViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
||||||
ensureCalledOnce { callback ->
|
ensureCalledOnce { callback ->
|
||||||
|
|||||||
+2
-4
@@ -13,17 +13,15 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class ErrorViewTest : RobolectricTest() {
|
||||||
class ErrorViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `on back pressed - calls the onCancel callback`() = runAndroidComposeUiTest {
|
fun `on back pressed - calls the onCancel callback`() = runAndroidComposeUiTest {
|
||||||
ensureCalledOnce { callback ->
|
ensureCalledOnce { callback ->
|
||||||
|
|||||||
+5
-2
@@ -88,6 +88,7 @@ class EnterNumberPresenterTest {
|
|||||||
navigator = navigator,
|
navigator = navigator,
|
||||||
linkNewMobileHandler = linkNewMobileHandler,
|
linkNewMobileHandler = linkNewMobileHandler,
|
||||||
).test {
|
).test {
|
||||||
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
linkMobileHandler.emitStep(
|
linkMobileHandler.emitStep(
|
||||||
LinkMobileStep.QrScanned(checkCodeSender)
|
LinkMobileStep.QrScanned(checkCodeSender)
|
||||||
@@ -96,7 +97,7 @@ class EnterNumberPresenterTest {
|
|||||||
initialState.eventSink(EnterNumberEvent.UpdateNumber("88"))
|
initialState.eventSink(EnterNumberEvent.UpdateNumber("88"))
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
initialState.eventSink(EnterNumberEvent.Continue)
|
initialState.eventSink(EnterNumberEvent.Continue)
|
||||||
skipItems(1)
|
skipItems(2)
|
||||||
val finalState = awaitItem()
|
val finalState = awaitItem()
|
||||||
assertThat(finalState.sendingCode.isLoading()).isTrue()
|
assertThat(finalState.sendingCode.isLoading()).isTrue()
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
@@ -130,6 +131,7 @@ class EnterNumberPresenterTest {
|
|||||||
LinkMobileStep.QrScanned(checkCodeSender)
|
LinkMobileStep.QrScanned(checkCodeSender)
|
||||||
)
|
)
|
||||||
runCurrent()
|
runCurrent()
|
||||||
|
skipItems(1)
|
||||||
initialState.eventSink(EnterNumberEvent.UpdateNumber("88"))
|
initialState.eventSink(EnterNumberEvent.UpdateNumber("88"))
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
initialState.eventSink(EnterNumberEvent.Continue)
|
initialState.eventSink(EnterNumberEvent.Continue)
|
||||||
@@ -163,6 +165,7 @@ class EnterNumberPresenterTest {
|
|||||||
createPresenter(
|
createPresenter(
|
||||||
linkNewMobileHandler = linkNewMobileHandler,
|
linkNewMobileHandler = linkNewMobileHandler,
|
||||||
).test {
|
).test {
|
||||||
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
linkMobileHandler.emitStep(
|
linkMobileHandler.emitStep(
|
||||||
LinkMobileStep.QrScanned(checkCodeSender)
|
LinkMobileStep.QrScanned(checkCodeSender)
|
||||||
@@ -171,7 +174,7 @@ class EnterNumberPresenterTest {
|
|||||||
initialState.eventSink(EnterNumberEvent.UpdateNumber("88"))
|
initialState.eventSink(EnterNumberEvent.UpdateNumber("88"))
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
initialState.eventSink(EnterNumberEvent.Continue)
|
initialState.eventSink(EnterNumberEvent.Continue)
|
||||||
skipItems(1)
|
skipItems(2)
|
||||||
val loadingState = awaitItem()
|
val loadingState = awaitItem()
|
||||||
assertThat(loadingState.sendingCode.isLoading()).isTrue()
|
assertThat(loadingState.sendingCode.isLoading()).isTrue()
|
||||||
expectNoEvents()
|
expectNoEvents()
|
||||||
|
|||||||
+2
-4
@@ -15,7 +15,6 @@ import androidx.compose.ui.test.ExperimentalTestApi
|
|||||||
import androidx.compose.ui.test.assertIsNotEnabled
|
import androidx.compose.ui.test.assertIsNotEnabled
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
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.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class EnterNumberViewTest : RobolectricTest() {
|
||||||
class EnterNumberViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
||||||
ensureCalledOnce { callback ->
|
ensureCalledOnce { callback ->
|
||||||
|
|||||||
+2
-4
@@ -13,15 +13,13 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.EnsureNeverCalled
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class ShowQrCodeViewTest : RobolectricTest() {
|
||||||
class ShowQrCodeViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
||||||
ensureCalledOnce { callback ->
|
ensureCalledOnce { callback ->
|
||||||
|
|||||||
+34
-1
@@ -75,15 +75,48 @@ class LinkNewDeviceRootPresenterTest {
|
|||||||
sessionCoroutineScope = backgroundScope,
|
sessionCoroutineScope = backgroundScope,
|
||||||
createLinkMobileHandlerResult = { Result.success(linkMobileHandler) }
|
createLinkMobileHandlerResult = { Result.success(linkMobileHandler) }
|
||||||
)
|
)
|
||||||
|
val linkNewMobileHandler = LinkNewMobileHandler(matrixClient)
|
||||||
createPresenter(
|
createPresenter(
|
||||||
matrixClient = matrixClient,
|
matrixClient = matrixClient,
|
||||||
|
linkNewMobileHandler = linkNewMobileHandler,
|
||||||
).test {
|
).test {
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.isSupported.dataOrNull()).isTrue()
|
assertThat(initialState.isSupported.dataOrNull()).isTrue()
|
||||||
initialState.eventSink(LinkNewDeviceRootEvent.LinkMobileDevice)
|
linkNewMobileHandler.createAndStartNewHandler()
|
||||||
|
skipItems(1)
|
||||||
val loadingState = awaitItem()
|
val loadingState = awaitItem()
|
||||||
assertThat(loadingState.qrCodeData.isLoading()).isTrue()
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-17
@@ -13,20 +13,20 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.features.linknewdevice.impl.R
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
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.EventsRecorder
|
||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
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.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class LinkNewDeviceRootViewTest : RobolectricTest() {
|
||||||
class LinkNewDeviceRootViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `on back pressed - calls the onRetry callback`() = runAndroidComposeUiTest {
|
fun `on back pressed - calls the onRetry callback`() = runAndroidComposeUiTest {
|
||||||
val eventRecorder = EventsRecorder<LinkNewDeviceRootEvent>(expectEvents = false)
|
val eventRecorder = EventsRecorder<LinkNewDeviceRootEvent>(expectEvents = false)
|
||||||
@@ -44,29 +44,31 @@ class LinkNewDeviceRootViewTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `link desktop button clicked - calls the expected callback`() = runAndroidComposeUiTest {
|
fun `link desktop button clicked - calls the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventRecorder = EventsRecorder<LinkNewDeviceRootEvent>(expectEvents = false)
|
val eventRecorder = EventsRecorder<LinkNewDeviceRootEvent>(expectEvents = false)
|
||||||
ensureCalledOnce { callback ->
|
ensureCalledOnceWithParam(LinkDeviceType.Desktop) { callback ->
|
||||||
setLinkNewDeviceRootView(
|
setLinkNewDeviceRootView(
|
||||||
state = aLinkNewDeviceRootState(
|
state = aLinkNewDeviceRootState(
|
||||||
isSupported = AsyncData.Success(true),
|
isSupported = AsyncData.Success(true),
|
||||||
eventSink = eventRecorder,
|
eventSink = eventRecorder,
|
||||||
),
|
),
|
||||||
onLinkDesktopDeviceClick = callback,
|
onUnlockDevice = callback,
|
||||||
)
|
)
|
||||||
clickOn(R.string.screen_link_new_device_root_desktop_computer)
|
clickOn(R.string.screen_link_new_device_root_desktop_computer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `link mobile button clicked - emits the expected event`() = runAndroidComposeUiTest {
|
fun `link mobile button clicked - calls the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventRecorder = EventsRecorder<LinkNewDeviceRootEvent>()
|
val eventRecorder = EventsRecorder<LinkNewDeviceRootEvent>(expectEvents = false)
|
||||||
setLinkNewDeviceRootView(
|
ensureCalledOnceWithParam(LinkDeviceType.Mobile) { callback ->
|
||||||
state = aLinkNewDeviceRootState(
|
setLinkNewDeviceRootView(
|
||||||
isSupported = AsyncData.Success(true),
|
state = aLinkNewDeviceRootState(
|
||||||
eventSink = eventRecorder,
|
isSupported = AsyncData.Success(true),
|
||||||
|
eventSink = eventRecorder,
|
||||||
|
),
|
||||||
|
onUnlockDevice = callback,
|
||||||
)
|
)
|
||||||
)
|
clickOn(R.string.screen_link_new_device_root_mobile_device)
|
||||||
clickOn(R.string.screen_link_new_device_root_mobile_device)
|
}
|
||||||
eventRecorder.assertSingle(LinkNewDeviceRootEvent.LinkMobileDevice)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,13 +89,13 @@ class LinkNewDeviceRootViewTest {
|
|||||||
private fun AndroidComposeUiTest<ComponentActivity>.setLinkNewDeviceRootView(
|
private fun AndroidComposeUiTest<ComponentActivity>.setLinkNewDeviceRootView(
|
||||||
state: LinkNewDeviceRootState = aLinkNewDeviceRootState(),
|
state: LinkNewDeviceRootState = aLinkNewDeviceRootState(),
|
||||||
onBackClick: () -> Unit = EnsureNeverCalled(),
|
onBackClick: () -> Unit = EnsureNeverCalled(),
|
||||||
onLinkDesktopDeviceClick: () -> Unit = EnsureNeverCalled(),
|
onUnlockDevice: (type: LinkDeviceType) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
) {
|
) {
|
||||||
setContent {
|
setContent {
|
||||||
LinkNewDeviceRootView(
|
LinkNewDeviceRootView(
|
||||||
state = state,
|
state = state,
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
onLinkDesktopDeviceClick = onLinkDesktopDeviceClick,
|
onUnlockDevice = onUnlockDevice,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -9,13 +9,13 @@
|
|||||||
|
|
||||||
package io.element.android.features.linknewdevice.impl.screens.scan
|
package io.element.android.features.linknewdevice.impl.screens.scan
|
||||||
|
|
||||||
|
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.platform.LocalInspectionMode
|
import androidx.compose.ui.platform.LocalInspectionMode
|
||||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.ExperimentalTestApi
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
@@ -24,12 +24,13 @@ import io.element.android.tests.testutils.EventsRecorder
|
|||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class ScanQrCodeViewTest : RobolectricTest() {
|
||||||
class ScanQrCodeViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
|
@Config(sdk = [UPSIDE_DOWN_CAKE])
|
||||||
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
fun `on back pressed - calls the expected callback`() = runAndroidComposeUiTest {
|
||||||
val eventRecorder = EventsRecorder<ScanQrCodeEvent>(expectEvents = false)
|
val eventRecorder = EventsRecorder<ScanQrCodeEvent>(expectEvents = false)
|
||||||
ensureCalledOnce { callback ->
|
ensureCalledOnce { callback ->
|
||||||
@@ -44,6 +45,7 @@ class ScanQrCodeViewTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Config(sdk = [UPSIDE_DOWN_CAKE])
|
||||||
fun `try again button clicked - emits the expected event`() = runAndroidComposeUiTest {
|
fun `try again button clicked - emits the expected event`() = runAndroidComposeUiTest {
|
||||||
val eventRecorder = EventsRecorder<ScanQrCodeEvent>()
|
val eventRecorder = EventsRecorder<ScanQrCodeEvent>()
|
||||||
setView(
|
setView(
|
||||||
|
|||||||
+4
-2
@@ -30,7 +30,7 @@ import androidx.compose.material3.SheetValue
|
|||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
||||||
import androidx.compose.material3.rememberStandardBottomSheetState
|
import androidx.compose.material3.rememberBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
@@ -86,7 +86,9 @@ fun MapBottomSheetScaffold(
|
|||||||
customMapStyleUrl: AsyncData<String?>,
|
customMapStyleUrl: AsyncData<String?>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
scaffoldState: BottomSheetScaffoldState = rememberBottomSheetScaffoldState(
|
scaffoldState: BottomSheetScaffoldState = rememberBottomSheetScaffoldState(
|
||||||
bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.PartiallyExpanded)
|
bottomSheetState = rememberBottomSheetState(
|
||||||
|
initialValue = SheetValue.PartiallyExpanded,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
cameraState: CameraState = rememberCameraState(),
|
cameraState: CameraState = rememberCameraState(),
|
||||||
mapOptions: MapOptions = MapDefaults.options,
|
mapOptions: MapOptions = MapDefaults.options,
|
||||||
|
|||||||
+4
-2
@@ -20,7 +20,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
|||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.SheetValue
|
import androidx.compose.material3.SheetValue
|
||||||
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
||||||
import androidx.compose.material3.rememberStandardBottomSheetState
|
import androidx.compose.material3.rememberBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -105,7 +105,9 @@ fun ShareLocationView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val scaffoldState = rememberBottomSheetScaffoldState(
|
val scaffoldState = rememberBottomSheetScaffoldState(
|
||||||
bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.Expanded)
|
bottomSheetState = rememberBottomSheetState(
|
||||||
|
initialValue = SheetValue.Expanded,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
val cameraState = rememberCameraState(firstPosition = MapDefaults.defaultCameraPosition)
|
val cameraState = rememberCameraState(firstPosition = MapDefaults.defaultCameraPosition)
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -21,7 +21,7 @@ import androidx.compose.material3.BottomSheetDefaults
|
|||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.SheetValue
|
import androidx.compose.material3.SheetValue
|
||||||
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
||||||
import androidx.compose.material3.rememberStandardBottomSheetState
|
import androidx.compose.material3.rememberBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -92,7 +92,9 @@ fun ShowLocationView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val scaffoldState = rememberBottomSheetScaffoldState(
|
val scaffoldState = rememberBottomSheetScaffoldState(
|
||||||
bottomSheetState = rememberStandardBottomSheetState(SheetValue.Expanded)
|
bottomSheetState = rememberBottomSheetState(
|
||||||
|
initialValue = SheetValue.Expanded,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
LaunchedEffect(state.isSheetDraggable) {
|
LaunchedEffect(state.isSheetDraggable) {
|
||||||
if (!state.isSheetDraggable) {
|
if (!state.isSheetDraggable) {
|
||||||
|
|||||||
@@ -2,4 +2,5 @@
|
|||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_share_location_live_location_disclaimer_title">"Votre historique de localisation en direct sera enregistré dans le salon et visible par les membres après la fin de la session."</string>
|
<string name="screen_share_location_live_location_disclaimer_title">"Votre historique de localisation en direct sera enregistré dans le salon et visible par les membres après la fin de la session."</string>
|
||||||
<string name="screen_share_location_live_location_duration_picker_title">"Choisissez la durée pendant laquelle vous partagerez votre position en direct."</string>
|
<string name="screen_share_location_live_location_duration_picker_title">"Choisissez la durée pendant laquelle vous partagerez votre position en direct."</string>
|
||||||
|
<string name="screen_share_location_live_location_missing_permissions">"Vous n’êtes pas autorisé à partager votre position en direct dans ce salon."</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
+2
-4
@@ -17,7 +17,6 @@ import androidx.compose.ui.test.ExperimentalTestApi
|
|||||||
import androidx.compose.ui.test.onNodeWithTag
|
import androidx.compose.ui.test.onNodeWithTag
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
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.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class ShareLocationViewTest : RobolectricTest() {
|
||||||
class ShareLocationViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `test back action`() = runAndroidComposeUiTest {
|
fun `test back action`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<ShareLocationEvent>(expectEvents = false)
|
val eventsRecorder = EventsRecorder<ShareLocationEvent>(expectEvents = false)
|
||||||
|
|||||||
+2
-4
@@ -19,7 +19,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
|||||||
import androidx.compose.ui.test.onNodeWithTag
|
import androidx.compose.ui.test.onNodeWithTag
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
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.api.Location
|
||||||
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
|
||||||
import io.element.android.libraries.testtags.TestTags
|
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.clickOn
|
||||||
import io.element.android.tests.testutils.ensureCalledOnce
|
import io.element.android.tests.testutils.ensureCalledOnce
|
||||||
import io.element.android.tests.testutils.pressBack
|
import io.element.android.tests.testutils.pressBack
|
||||||
|
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
class ShowLocationViewTest : RobolectricTest() {
|
||||||
class ShowLocationViewTest {
|
|
||||||
@Test
|
@Test
|
||||||
fun `test back action`() = runAndroidComposeUiTest {
|
fun `test back action`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<ShowLocationEvent>(expectEvents = false)
|
val eventsRecorder = EventsRecorder<ShowLocationEvent>(expectEvents = false)
|
||||||
|
|||||||
+35
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.biometric)
|
implementation(libs.androidx.biometric)
|
||||||
|
|
||||||
testCommonDependencies(libs, true)
|
testCommonDependencies(libs, true)
|
||||||
|
testImplementation(projects.features.lockscreen.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.libraries.cryptography.test)
|
testImplementation(projects.libraries.cryptography.test)
|
||||||
testImplementation(projects.libraries.cryptography.impl)
|
testImplementation(projects.libraries.cryptography.impl)
|
||||||
|
|||||||
+35
@@ -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<DeviceUnlockNode>(
|
||||||
|
buildContext = buildContext,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) {
|
||||||
|
deviceUnlockCallbackHolder.requestUnlock(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -59,6 +59,7 @@ class DefaultBiometricAuthentication(
|
|||||||
private var cryptoObject: CryptoObject? = null
|
private var cryptoObject: CryptoObject? = null
|
||||||
|
|
||||||
override suspend fun setup() {
|
override suspend fun setup() {
|
||||||
|
if (cryptoObject != null) return
|
||||||
try {
|
try {
|
||||||
val secretKey = ensureKey()
|
val secretKey = ensureKey()
|
||||||
val cipher = encryptionDecryptionService.createEncryptionCipher(secretKey)
|
val cipher = encryptionDecryptionService.createEncryptionCipher(secretKey)
|
||||||
@@ -109,7 +110,9 @@ private class AuthenticationCallback(
|
|||||||
|
|
||||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||||
super.onAuthenticationSucceeded(result)
|
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() }
|
callbacks.forEach { it.onBiometricAuthenticationSuccess() }
|
||||||
deferredAuthenticationResult.complete(BiometricAuthenticator.AuthenticationResult.Success)
|
deferredAuthenticationResult.complete(BiometricAuthenticator.AuthenticationResult.Success)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+11
@@ -21,6 +21,11 @@ interface BiometricAuthenticatorManager {
|
|||||||
*/
|
*/
|
||||||
val hasAvailableAuthenticator: Boolean
|
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 addCallback(callback: BiometricAuthenticator.Callback)
|
||||||
fun removeCallback(callback: BiometricAuthenticator.Callback)
|
fun removeCallback(callback: BiometricAuthenticator.Callback)
|
||||||
|
|
||||||
@@ -35,6 +40,12 @@ interface BiometricAuthenticatorManager {
|
|||||||
@Composable
|
@Composable
|
||||||
fun rememberUnlockBiometricAuthenticator(): BiometricAuthenticator
|
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.
|
* Remember a biometric authenticator ready for confirmation.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+50
-6
@@ -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.di.annotations.ApplicationContext
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
|
||||||
@@ -69,6 +70,12 @@ class DefaultBiometricAuthenticatorManager(
|
|||||||
get() = lockScreenConfig.isStrongBiometricsEnabled &&
|
get() = lockScreenConfig.isStrongBiometricsEnabled &&
|
||||||
biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
|
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.
|
* Returns true if any biometric method (weak or strong) can be used.
|
||||||
*/
|
*/
|
||||||
@@ -78,6 +85,9 @@ class DefaultBiometricAuthenticatorManager(
|
|||||||
override val isDeviceSecured: Boolean
|
override val isDeviceSecured: Boolean
|
||||||
get() = keyguardManager.isDeviceSecure
|
get() = keyguardManager.isDeviceSecure
|
||||||
|
|
||||||
|
override val canUseDeviceUnlock: Boolean
|
||||||
|
get() = isDeviceSecured && (canUseWeakBiometricAuth || canUseStrongBiometricAuth || canUseDeviceCredentialAuth)
|
||||||
|
|
||||||
private val internalCallback = object : DefaultBiometricUnlockCallback() {
|
private val internalCallback = object : DefaultBiometricUnlockCallback() {
|
||||||
override fun onBiometricSetupError() {
|
override fun onBiometricSetupError() {
|
||||||
coroutineScope.launch { disable() }
|
coroutineScope.launch { disable() }
|
||||||
@@ -99,6 +109,28 @@ class DefaultBiometricAuthenticatorManager(
|
|||||||
isAvailable = isAvailable,
|
isAvailable = isAvailable,
|
||||||
promptTitle = promptTitle,
|
promptTitle = promptTitle,
|
||||||
promptNegative = promptNegative,
|
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,
|
isAvailable = isAvailable,
|
||||||
promptTitle = promptTitle,
|
promptTitle = promptTitle,
|
||||||
promptNegative = promptNegative,
|
promptNegative = promptNegative,
|
||||||
|
forDeviceUnlock = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +159,8 @@ class DefaultBiometricAuthenticatorManager(
|
|||||||
private fun rememberBiometricAuthenticator(
|
private fun rememberBiometricAuthenticator(
|
||||||
isAvailable: Boolean,
|
isAvailable: Boolean,
|
||||||
promptTitle: String,
|
promptTitle: String,
|
||||||
promptNegative: String,
|
promptNegative: String?,
|
||||||
|
forDeviceUnlock: Boolean,
|
||||||
): BiometricAuthenticator {
|
): BiometricAuthenticator {
|
||||||
val activity = LocalContext.current.findFragmentActivity()
|
val activity = LocalContext.current.findFragmentActivity()
|
||||||
return remember(isAvailable) {
|
return remember(isAvailable) {
|
||||||
@@ -136,11 +170,21 @@ class DefaultBiometricAuthenticatorManager(
|
|||||||
canUseWeakBiometricAuth -> BiometricManager.Authenticators.BIOMETRIC_WEAK
|
canUseWeakBiometricAuth -> BiometricManager.Authenticators.BIOMETRIC_WEAK
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
val promptInfo = BiometricPrompt.PromptInfo.Builder().apply {
|
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||||
setTitle(promptTitle)
|
.setTitle(promptTitle)
|
||||||
setNegativeButtonText(promptNegative)
|
.apply {
|
||||||
setAllowedAuthenticators(authenticators)
|
if (promptNegative != null) {
|
||||||
}.build()
|
setNegativeButtonText(promptNegative)
|
||||||
|
}
|
||||||
|
if (forDeviceUnlock) {
|
||||||
|
setAllowedAuthenticators(
|
||||||
|
authenticators or if (canUseDeviceCredentialAuth) BiometricManager.Authenticators.DEVICE_CREDENTIAL else 0
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setAllowedAuthenticators(authenticators)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
DefaultBiometricAuthentication(
|
DefaultBiometricAuthentication(
|
||||||
activity = activity,
|
activity = activity,
|
||||||
promptInfo = promptInfo,
|
promptInfo = promptInfo,
|
||||||
|
|||||||
+30
@@ -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<DeviceUnlockEntryPoint.Callback?>(null)
|
||||||
|
val deviceUnlockCallback: StateFlow<DeviceUnlockEntryPoint.Callback?> = _deviceUnlockCallback
|
||||||
|
|
||||||
|
fun requestUnlock(callback: DeviceUnlockEntryPoint.Callback) {
|
||||||
|
_deviceUnlockCallback.value = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDone() {
|
||||||
|
_deviceUnlockCallback.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user